Add support for wrapping modes.

Not terribly useful atm due to POT, but at least it's there.
Has some use mostly with LUTs ... NPOT + REPEAT requires extension on
GLES2 at least.
This commit is contained in:
Themaister 2013-08-16 00:30:54 +02:00
parent 26df85f020
commit 551fd27204
7 changed files with 130 additions and 29 deletions

View File

@ -347,6 +347,7 @@ void gl_shader_set_coords(void *data, const struct gl_coords *coords, const math
#define gl_shader_num(gl) ((gl->shader) ? gl->shader->num_shaders() : 0)
#define gl_shader_filter_type(gl, index, smooth) ((gl->shader) ? gl->shader->filter_type(index, smooth) : false)
#define gl_shader_wrap_type(gl, index) ((gl->shader) ? gl->shader->wrap_type(index) : RARCH_WRAP_BORDER)
#ifdef IOS
// There is no default frame buffer on IOS.
@ -465,16 +466,18 @@ static void gl_create_fbo_textures(void *data)
{
glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->border_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->border_type);
GLuint filter_type = base_filt;
bool smooth = false;
if (gl_shader_filter_type(gl, i + 2, &smooth))
filter_type = smooth ? GL_LINEAR : GL_NEAREST;
enum gfx_wrap_type wrap = gl_shader_wrap_type(gl, i + 2);
GLenum wrap_enum = gl_wrap_type_to_enum(wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_enum);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_enum);
bool fp_fbo = gl->fbo_scale[i].valid && gl->fbo_scale[i].fp_fbo;
@ -1156,8 +1159,8 @@ static void gl_init_textures(void *data, const video_info_t *video)
{
glBindTexture(GL_TEXTURE_2D, gl->texture[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->border_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->border_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->wrap_mode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->wrap_mode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl->tex_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl->tex_filter);
@ -1643,13 +1646,6 @@ static bool resolve_extensions(gl_t *gl)
RARCH_LOG("[GL]: Using ARB_sync to reduce latency.\n");
#endif
#ifdef NO_GL_CLAMP_TO_BORDER
// NOTE: This will be a serious problem for some shaders.
gl->border_type = GL_CLAMP_TO_EDGE;
#else
gl->border_type = GL_CLAMP_TO_BORDER;
#endif
driver.gfx_use_rgba = false;
#ifdef HAVE_OPENGLES2
if (gl_query_extension(gl, "BGRA8888"))
@ -2055,6 +2051,7 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
gl->tex_filter = force_smooth ? GL_LINEAR : GL_NEAREST;
else
gl->tex_filter = video->smooth ? GL_LINEAR : GL_NEAREST;
gl->wrap_mode = gl_wrap_type_to_enum(gl_shader_wrap_type(gl, 1));
gl_set_texture_fmts(gl, video->rgb32);
@ -2155,18 +2152,22 @@ static void gl_update_tex_filter_frame(gl_t *gl)
bool smooth = false;
if (!gl_shader_filter_type(gl, 1, &smooth))
smooth = g_settings.video.smooth;
GLenum wrap_mode = gl_wrap_type_to_enum(gl_shader_wrap_type(gl, 1));
gl->video_info.smooth = smooth;
GLuint new_filt = smooth ? GL_LINEAR : GL_NEAREST;
if (new_filt == gl->tex_filter)
if (new_filt == gl->tex_filter && wrap_mode == gl->wrap_mode)
return;
gl->tex_filter = new_filt;
gl->wrap_mode = wrap_mode;
for (unsigned i = 0; i < gl->textures; i++)
{
if (gl->texture[i])
{
glBindTexture(GL_TEXTURE_2D, gl->texture[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->wrap_mode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->wrap_mode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl->tex_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl->tex_filter);
}
@ -2394,8 +2395,8 @@ static bool gl_overlay_load(void *data, const uint32_t *image, unsigned width, u
glGenTextures(1, &gl->tex_overlay);
glBindTexture(GL_TEXTURE_2D, gl->tex_overlay);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->border_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->border_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -2567,8 +2568,8 @@ static void gl_set_texture_frame(void *data,
{
glGenTextures(1, &gl->rgui_texture);
glBindTexture(GL_TEXTURE_2D, gl->rgui_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl->border_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl->border_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}

View File

@ -199,7 +199,7 @@ typedef struct gl
GLenum internal_fmt;
GLenum texture_type; // RGB565 or ARGB
GLenum texture_fmt;
GLenum border_type;
GLenum wrap_mode;
unsigned base_size; // 2 or 4
// Fonts
@ -314,5 +314,26 @@ void gl_shader_set_coords(void *data, const struct gl_coords *coords, const math
void gl_init_fbo(void *data, unsigned width, unsigned height);
void gl_deinit_fbo(void *data);
static inline GLenum gl_wrap_type_to_enum(enum gfx_wrap_type type)
{
switch (type)
{
#ifndef HAVE_OPENGLES
case RARCH_WRAP_BORDER:
return GL_CLAMP_TO_BORDER;
#else
case RARCH_WRAP_BORDER:
#endif
case RARCH_WRAP_EDGE:
return GL_CLAMP_TO_EDGE;
case RARCH_WRAP_REPEAT:
return GL_REPEAT;
case RARCH_WRAP_MIRRORED_REPEAT:
return GL_MIRRORED_REPEAT;
default:
return 0;
}
}
#endif

View File

@ -493,18 +493,12 @@ static bool load_plain(const char *path)
#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
#ifdef HAVE_OPENGLES2
#define BORDER_FUNC GL_CLAMP_TO_EDGE
#else
#define BORDER_FUNC GL_CLAMP_TO_BORDER
#endif
static void load_texture_data(GLuint obj, const struct texture_image *img, bool smooth)
static void load_texture_data(GLuint obj, const struct texture_image *img, bool smooth, GLenum wrap)
{
glBindTexture(GL_TEXTURE_2D, obj);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, BORDER_FUNC);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, BORDER_FUNC);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
@ -538,7 +532,8 @@ static bool load_textures(void)
}
load_texture_data(lut_textures[i], &img,
cg_shader->lut[i].filter != RARCH_FILTER_NEAREST);
cg_shader->lut[i].filter != RARCH_FILTER_NEAREST,
gl_wrap_type_to_enum(cg_shader->lut[i].wrap));
}
glBindTexture(GL_TEXTURE_2D, 0);
@ -903,6 +898,14 @@ static bool gl_cg_filter_type(unsigned index, bool *smooth)
return false;
}
static enum gfx_wrap_type gl_cg_wrap_type(unsigned index)
{
if (cg_active && index)
return cg_shader->pass[index - 1].wrap;
else
return RARCH_WRAP_BORDER;
}
static void gl_cg_shader_scale(unsigned index, struct gfx_fbo_scale *scale)
{
if (cg_active && index)
@ -942,6 +945,7 @@ const gl_shader_backend_t gl_cg_backend = {
gl_cg_use,
gl_cg_num,
gl_cg_filter_type,
gl_cg_wrap_type,
gl_cg_shader_scale,
gl_cg_set_coords,
gl_cg_set_mvp,

View File

@ -47,6 +47,7 @@ struct gl_shader_backend
void (*use)(unsigned index);
unsigned (*num_shaders)(void);
bool (*filter_type)(unsigned index, bool *smooth);
enum gfx_wrap_type (*wrap_type)(unsigned index);
void (*shader_scale)(unsigned index, struct gfx_fbo_scale *scale);
bool (*set_coords)(const struct gl_coords *coords);
bool (*set_mvp)(const math_matrix *mat);

View File

@ -1180,6 +1180,14 @@ static bool gl_glsl_filter_type(unsigned index, bool *smooth)
return false;
}
static enum gfx_wrap_type gl_glsl_wrap_type(unsigned index)
{
if (glsl_enable && index)
return glsl_shader->pass[index - 1].wrap;
else
return RARCH_WRAP_BORDER;
}
static void gl_glsl_shader_scale(unsigned index, struct gfx_fbo_scale *scale)
{
if (glsl_enable && index)
@ -1221,6 +1229,7 @@ const gl_shader_backend_t gl_glsl_backend = {
gl_glsl_use,
gl_glsl_num,
gl_glsl_filter_type,
gl_glsl_wrap_type,
gl_glsl_shader_scale,
gl_glsl_set_coords,
gl_glsl_set_mvp,

View File

@ -30,6 +30,41 @@
#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
static const char *wrap_mode_to_str(enum gfx_wrap_type type)
{
switch (type)
{
case RARCH_WRAP_BORDER:
return "clamp_to_border";
case RARCH_WRAP_EDGE:
return "clamp_to_edge";
case RARCH_WRAP_REPEAT:
return "repeat";
case RARCH_WRAP_MIRRORED_REPEAT:
return "mirrored_repeat";
default:
return "???";
}
}
static enum gfx_wrap_type wrap_str_to_mode(const char *wrap_mode)
{
if (strcmp(wrap_mode, "clamp_to_border") == 0)
return RARCH_WRAP_BORDER;
else if (strcmp(wrap_mode, "clamp_to_edge") == 0)
return RARCH_WRAP_EDGE;
else if (strcmp(wrap_mode, "repeat") == 0)
return RARCH_WRAP_REPEAT;
else if (strcmp(wrap_mode, "mirrored_repeat") == 0)
return RARCH_WRAP_MIRRORED_REPEAT;
else
{
RARCH_WARN("Invalid wrapping type %s. Valid ones are: clamp_to_border (default), clamp_to_edge, repeat and mirrored_repeat. Falling back to default.\n",
wrap_mode);
return RARCH_WRAP_DEFAULT;
}
}
// CGP
static bool shader_parse_pass(config_file_t *conf, struct gfx_shader_pass *pass, unsigned i)
{
@ -52,6 +87,13 @@ static bool shader_parse_pass(config_file_t *conf, struct gfx_shader_pass *pass,
else
pass->filter = RARCH_FILTER_UNSPEC;
// Wrapping mode
char wrap_name_buf[64];
print_buf(wrap_name_buf, "wrap_mode%u", i);
char wrap_mode[64];
if (config_get_array(conf, wrap_name_buf, wrap_mode, sizeof(wrap_mode)))
pass->wrap = wrap_str_to_mode(wrap_mode);
// Frame count mod
char frame_count_mod[64] = {0};
char frame_count_mod_buf[64];
@ -207,6 +249,12 @@ static bool shader_parse_textures(config_file_t *conf, struct gfx_shader *shader
shader->lut[shader->luts].filter = smooth ? RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST;
else
shader->lut[shader->luts].filter = RARCH_FILTER_UNSPEC;
char id_wrap[64];
print_buf(id_wrap, "%s_wrap_mode", id);
char wrap_mode[64];
if (config_get_array(conf, id_wrap, wrap_mode, sizeof(wrap_mode)))
shader->lut[shader->luts].wrap = wrap_str_to_mode(wrap_mode);
}
return true;
@ -998,6 +1046,9 @@ void gfx_shader_write_conf_cgp(config_file_t *conf, const struct gfx_shader *sha
config_set_bool(conf, key, pass->filter == RARCH_FILTER_LINEAR);
}
print_buf(key, "wrap_mode%u", i);
config_set_string(conf, key, wrap_mode_to_str(pass->wrap));
if (pass->frame_count_mod)
{
print_buf(key, "frame_count_mod%u", i);
@ -1031,6 +1082,9 @@ void gfx_shader_write_conf_cgp(config_file_t *conf, const struct gfx_shader *sha
print_buf(key, "%s_linear", shader->lut[i].id);
config_set_bool(conf, key, shader->lut[i].filter != RARCH_FILTER_LINEAR);
}
print_buf(key, "%s_wrap_mode", shader->lut[i].id);
config_set_string(conf, key, wrap_mode_to_str(shader->lut[i].wrap));
}
}

View File

@ -40,7 +40,16 @@ enum gfx_filter_type
{
RARCH_FILTER_UNSPEC = 0,
RARCH_FILTER_LINEAR,
RARCH_FILTER_NEAREST,
RARCH_FILTER_NEAREST
};
enum gfx_wrap_type
{
RARCH_WRAP_BORDER = 0, // Kinda deprecated, but keep as default. Will be translated to EDGE in GLES.
RARCH_WRAP_DEFAULT = RARCH_WRAP_BORDER,
RARCH_WRAP_EDGE,
RARCH_WRAP_REPEAT,
RARCH_WRAP_MIRRORED_REPEAT
};
struct gfx_fbo_scale
@ -69,6 +78,7 @@ struct gfx_shader_pass
struct gfx_fbo_scale fbo;
enum gfx_filter_type filter;
enum gfx_wrap_type wrap;
unsigned frame_count_mod;
};
@ -77,6 +87,7 @@ struct gfx_shader_lut
char id[64];
char path[PATH_MAX];
enum gfx_filter_type filter;
enum gfx_wrap_type wrap;
};
// This is pretty big, shouldn't be put on the stack.