From 5342945bb87116c3d0ddc26087c4834716366c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Molinari?= Date: Fri, 8 Nov 2024 15:18:10 +0100 Subject: [PATCH] gl-renderer: Add texture parameters utilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cache and update texture parameters only when changed by storing minification/magnification filters, wrap modes and their target into a dedicated gl_texture_parameters structure and by calling new utility functions to create and flush parameters. This structure is itself stored into the buffer state for each texture of a surface and into the output state for border and shadow textures. The shader config filled before emitting a draw call now just takes a pointer to the array of texture ids, a pointer to the array of parameters and the number of textures. This allows to simplify the logic in gl-renderer.c, to minimise GL state changes and to let the utility wrapper validate the parameters. Signed-off-by: Loïc Molinari --- libweston/renderer-gl/gl-renderer-internal.h | 39 +++++- libweston/renderer-gl/gl-renderer.c | 103 +++++++------- .../gl-shader-config-color-transformation.c | 18 ++- libweston/renderer-gl/gl-shaders.c | 22 ++- libweston/renderer-gl/gl-utils.c | 132 ++++++++++++++++++ 5 files changed, 237 insertions(+), 77 deletions(-) diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h index 7a4068d82..b1659cdf1 100644 --- a/libweston/renderer-gl/gl-renderer-internal.h +++ b/libweston/renderer-gl/gl-renderer-internal.h @@ -299,6 +299,26 @@ static_assert(sizeof(struct gl_shader_requirements) == 4 /* total bitfield size in bytes */, "struct gl_shader_requirements must not contain implicit padding"); +enum gl_texture_flag { + TEXTURE_FILTERS_DIRTY = 1 << 0, + TEXTURE_WRAP_MODES_DIRTY = 1 << 1, + TEXTURE_ALL_DIRTY = (TEXTURE_FILTERS_DIRTY | + TEXTURE_WRAP_MODES_DIRTY), +}; + +struct gl_texture_parameters { + GLenum target; + union { + struct { GLint min, mag; }; + GLint array[2]; + } filters; + union { + struct { GLint s, t, r; }; + GLint array[3]; + } wrap_modes; + uint32_t flags; +}; + struct gl_shader; struct weston_color_transform; struct dmabuf_allocator; @@ -311,8 +331,11 @@ struct gl_shader_config { float view_alpha; GLfloat unicolor[4]; GLfloat tint[4]; - GLint input_tex_filter; /* GL_NEAREST or GL_LINEAR */ - GLuint input_tex[SHADER_INPUT_TEX_MAX]; + + struct gl_texture_parameters *input_param; + GLuint *input_tex; + int input_num; + GLuint wireframe_tex; union { @@ -589,6 +612,18 @@ gl_texture_3d_store(struct gl_renderer *gr, void gl_texture_fini(GLuint *tex); +void +gl_texture_parameters_init(struct gl_renderer *gr, + struct gl_texture_parameters *parameters, + GLenum target, + const GLint *filters, + const GLint *wrap_modes, + bool flush); + +void +gl_texture_parameters_flush(struct gl_renderer *gr, + struct gl_texture_parameters *parameters); + bool gl_fbo_is_format_supported(struct gl_renderer *gr, GLenum format); diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index fece4dc4b..5d8584db4 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -145,6 +145,7 @@ struct gl_output_state { struct gl_border_image borders_pending[4]; struct gl_border_image borders_current[4]; enum gl_border_status border_status; + struct gl_texture_parameters borders_param[4]; GLuint borders_tex[4]; struct weston_matrix output_matrix; @@ -156,6 +157,7 @@ struct gl_output_state { struct wl_list timeline_render_point_list; const struct pixel_format_info *shadow_format; + struct gl_texture_parameters shadow_param; GLuint shadow_tex; GLuint shadow_fb; @@ -243,6 +245,7 @@ struct gl_buffer_state { enum gl_shader_texture_variant shader_variant; struct gl_format_info texture_format[3]; + struct gl_texture_parameters parameters[3]; GLuint textures[3]; int num_textures; @@ -1338,13 +1341,11 @@ prepare_placeholder(struct gl_shader_config *sconf, *sconf = alt; } + static void gl_shader_config_set_input_textures(struct gl_shader_config *sconf, - struct gl_surface_state *gs) + struct gl_buffer_state *gb) { - struct gl_buffer_state *gb = gs->buffer; - int i; - sconf->req.variant = gb->shader_variant; sconf->req.color_channel_order = gb->gl_channel_order; sconf->req.input_is_premult = @@ -1352,22 +1353,22 @@ gl_shader_config_set_input_textures(struct gl_shader_config *sconf, copy_uniform4f(sconf->unicolor, gb->color); - assert(gb->num_textures <= SHADER_INPUT_TEX_MAX); - for (i = 0; i < gb->num_textures; i++) - sconf->input_tex[i] = gb->textures[i]; - for (; i < SHADER_INPUT_TEX_MAX; i++) - sconf->input_tex[i] = 0; + sconf->input_param = gb->parameters; + sconf->input_tex = gb->textures; + sconf->input_num = gb->num_textures; } static bool gl_shader_config_init_for_paint_node(struct gl_shader_config *sconf, - struct weston_paint_node *pnode, - GLint filter) + struct weston_paint_node *pnode) { struct gl_renderer *gr = get_renderer(pnode->surface->compositor); struct gl_surface_state *gs = get_surface_state(pnode->surface); + struct gl_buffer_state *gb = gs->buffer; struct gl_output_state *go = get_output_state(pnode->output); struct weston_buffer *buffer = gs->buffer_ref.buffer; + GLint filter; + int i; if (!pnode->surf_xform_valid) return false; @@ -1378,7 +1379,6 @@ gl_shader_config_init_for_paint_node(struct gl_shader_config *sconf, .surface_to_buffer = pnode->view->surface->surface_to_buffer_matrix, .view_alpha = pnode->view->alpha, - .input_tex_filter = filter, }; weston_matrix_multiply(&sconf->projection, &go->output_matrix); @@ -1394,7 +1394,16 @@ gl_shader_config_init_for_paint_node(struct gl_shader_config *sconf, weston_matrix_translate(&sconf->surface_to_buffer, 0, 1, 0); } - gl_shader_config_set_input_textures(sconf, gs); + gl_shader_config_set_input_textures(sconf, gb); + + filter = pnode->needs_filtering ? GL_LINEAR : GL_NEAREST; + for (i = 0; i < gb->num_textures; i++) { + if (filter != gb->parameters[i].filters.min) { + gb->parameters[i].filters.min = filter; + gb->parameters[i].filters.mag = filter; + gb->parameters[i].flags |= TEXTURE_FILTERS_DIRTY; + } + } if (!gl_shader_config_set_color_transform(gr, sconf, pnode->surf_xform.transform)) { weston_log("GL-renderer: failed to generate a color transformation.\n"); @@ -1754,7 +1763,6 @@ draw_paint_node(struct weston_paint_node *pnode, pixman_region32_t surface_opaque; /* non-opaque region in surface coordinates: */ pixman_region32_t surface_blend; - GLint filter; struct gl_shader_config sconf; struct clipper_quad *quads = NULL; int nquads; @@ -1772,12 +1780,7 @@ draw_paint_node(struct weston_paint_node *pnode, if (!pnode->draw_solid && ensure_surface_buffer_is_ready(gr, gs) < 0) goto out; - if (pnode->needs_filtering) - filter = GL_LINEAR; - else - filter = GL_NEAREST; - - if (!gl_shader_config_init_for_paint_node(&sconf, pnode, filter)) + if (!gl_shader_config_init_for_paint_node(&sconf, pnode)) goto out; /* XXX: Should we be using ev->transform.opaque here? */ @@ -1947,6 +1950,8 @@ static void update_wireframe_tex(struct gl_renderer *gr, const struct weston_geometry *area) { + GLint filters[] = { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }; + struct gl_texture_parameters params; int new_size, i; uint8_t *buffer; @@ -1972,9 +1977,8 @@ update_wireframe_tex(struct gl_renderer *gr, glActiveTexture(GL_TEXTURE0 + TEX_UNIT_WIREFRAME); gl_texture_2d_init(gr, (int) log2(new_size) + 1, GL_R8, new_size, 1, &gr->wireframe_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR); + gl_texture_parameters_init(gr, ¶ms, GL_TEXTURE_2D, filters, NULL, + true); gr->wireframe_size = new_size; /* Store mip chain with a wireframe thickness of 1.0. */ @@ -2010,12 +2014,9 @@ update_borders_tex(struct gl_renderer *gr, gl_texture_2d_init( gr, 1, GL_BGRA8_EXT, pending->tex_width, pending->height, &go->borders_tex[i]); - glTexParameteri(GL_TEXTURE_2D, - GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, - GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); + gl_texture_parameters_init( + gr, &go->borders_param[i], + GL_TEXTURE_2D, NULL, NULL, false); } } @@ -2043,8 +2044,9 @@ draw_output_border_texture(struct gl_renderer *gr, /* An empty border image (as allowed by output_set_borders) would use * the default (incomplete) OpenGL ES texture which, per spec, returns * (0, 0, 0, 1) in the fragment shader. */ - sconf->input_tex_filter = GL_NEAREST; - sconf->input_tex[0] = go->borders_tex[side]; + sconf->input_tex = &go->borders_tex[side]; + sconf->input_param = &go->borders_param[side]; + sconf->input_num = 1; gl_renderer_use_program(gr, sconf); GLfloat texcoord[] = { @@ -2278,8 +2280,9 @@ blit_shadow_to_output(struct weston_output *output, WESTON_MATRIX_TRANSFORM_TRANSLATE, }, .view_alpha = 1.0f, - .input_tex_filter = GL_NEAREST, - .input_tex[0] = go->shadow_tex, + .input_tex = &go->shadow_tex, + .input_param = &go->shadow_param, + .input_num = 1, }; struct gl_renderer *gr = get_renderer(output->compositor); double width = go->area.width; @@ -2736,14 +2739,12 @@ ensure_textures(struct gl_buffer_state *gb, GLenum target, int num_textures) assert(gb->num_textures == 0); - for (i = 0; i < num_textures; i++) { - glGenTextures(1, &gb->textures[i]); - glBindTexture(target, gb->textures[i]); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } + glGenTextures(num_textures, gb->textures); gb->num_textures = num_textures; - glBindTexture(target, 0); + + for (i = 0; i < num_textures; i++) + gl_texture_parameters_init(gb->gr, &gb->parameters[i], target, + NULL, NULL, false); } static void @@ -2874,10 +2875,8 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer) gl_texture_2d_init(gr, 1, texture_format[i].internal, buffer->width / hsub, buffer->height / vsub, &gb->textures[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); + gl_texture_parameters_init(gr, &gb->parameters[i], + GL_TEXTURE_2D, NULL, NULL, false); } } @@ -3524,7 +3523,6 @@ gl_renderer_attach_buffer(struct weston_surface *surface, struct gl_renderer *gr = get_renderer(surface->compositor); struct gl_surface_state *gs = get_surface_state(surface); struct gl_buffer_state *gb; - GLenum target; int i; assert(buffer->renderer_private); @@ -3535,14 +3533,14 @@ gl_renderer_attach_buffer(struct weston_surface *surface, if (gb->specified) return; - target = gl_shader_texture_variant_get_target(gb->shader_variant); for (i = 0; i < gb->num_images; ++i) { - glBindTexture(target, gb->textures[i]); + glBindTexture(gb->parameters[i].target, gb->textures[i]); if (gl_extensions_has(gr, EXTENSION_EXT_EGL_IMAGE_STORAGE)) - gr->image_target_tex_storage(target, gb->images[i], - NULL); + gr->image_target_tex_storage(gb->parameters[i].target, + gb->images[i], NULL); else - gr->image_target_texture_2d(target, gb->images[i]); + gr->image_target_texture_2d(gb->parameters[i].target, + gb->images[i]); } gb->specified = true; @@ -3763,7 +3761,6 @@ gl_renderer_surface_copy_content(struct weston_surface *surface, }; struct gl_shader_config sconf = { .view_alpha = 1.0f, - .input_tex_filter = GL_NEAREST, }; const pixman_format_code_t format = PIXMAN_a8b8g8r8; struct gl_renderer *gr = get_renderer(surface->compositor); @@ -3794,7 +3791,7 @@ gl_renderer_surface_copy_content(struct weston_surface *surface, break; } - gl_shader_config_set_input_textures(&sconf, gs); + gl_shader_config_set_input_textures(&sconf, gb); if (!gl_fbo_init(gr, GL_RGBA8, cw, ch, &fbo, &rb)) { weston_log("Failed to init FBO\n"); @@ -4037,6 +4034,8 @@ gl_renderer_resize_output(struct weston_output *output, ret = gl_fbo_texture_init(gr, shfmt->gl.internal, area->width, area->height, &go->shadow_fb, &go->shadow_tex); + gl_texture_parameters_init(gr, &go->shadow_param, GL_TEXTURE_2D, NULL, + NULL, false); return ret; } diff --git a/libweston/renderer-gl/gl-shader-config-color-transformation.c b/libweston/renderer-gl/gl-shader-config-color-transformation.c index beb1a9110..a578033bd 100644 --- a/libweston/renderer-gl/gl-shader-config-color-transformation.c +++ b/libweston/renderer-gl/gl-shader-config-color-transformation.c @@ -181,8 +181,10 @@ gl_color_curve_lut_3x1d(struct gl_renderer *gr, const struct weston_color_curve *curve, struct weston_color_transform *xform) { + GLint filters[] = { GL_LINEAR, GL_LINEAR }; const unsigned lut_len = curve->u.lut_3x1d.optimal_len; const unsigned nr_rows = 4; + struct gl_texture_parameters params; GLuint tex; float *lut; @@ -199,12 +201,10 @@ gl_color_curve_lut_3x1d(struct gl_renderer *gr, curve->u.lut_3x1d.fill_in(xform, lut, lut_len); gl_texture_2d_init(gr, 1, GL_R32F, lut_len, nr_rows, &tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); gl_texture_2d_store(gr, 0, 0, 0, lut_len, nr_rows, GL_RED, GL_FLOAT, lut); + gl_texture_parameters_init(gr, ¶ms, GL_TEXTURE_2D, filters, NULL, + true); free(lut); @@ -222,7 +222,8 @@ gl_3d_lut(struct gl_renderer *gr, struct gl_renderer_color_transform *gl_xform, struct weston_color_transform *xform) { - + GLint filters[] = { GL_LINEAR, GL_LINEAR }; + struct gl_texture_parameters params; GLuint tex3d; float *lut; const unsigned dim_size = xform->mapping.u.lut3d.optimal_len; @@ -235,13 +236,10 @@ gl_3d_lut(struct gl_renderer *gr, gl_texture_3d_init(gr, 1, GL_RGB32F, dim_size, dim_size, dim_size, &tex3d); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); gl_texture_3d_store(gr, 0, 0, 0, 0, dim_size, dim_size, dim_size, GL_RGB, GL_FLOAT, lut); + gl_texture_parameters_init(gr, ¶ms, GL_TEXTURE_3D, filters, NULL, + true); glBindTexture(GL_TEXTURE_3D, 0); gl_xform->mapping.type = SHADER_COLOR_MAPPING_3DLUT; diff --git a/libweston/renderer-gl/gl-shaders.c b/libweston/renderer-gl/gl-shaders.c index 9eccbd9ae..fb9ccb077 100644 --- a/libweston/renderer-gl/gl-shaders.c +++ b/libweston/renderer-gl/gl-shaders.c @@ -657,11 +657,10 @@ gl_shader_texture_variant_get_target(enum gl_shader_texture_variant v) } static void -gl_shader_load_config(struct gl_shader *shader, +gl_shader_load_config(struct gl_renderer *gr, + struct gl_shader *shader, const struct gl_shader_config *sconf) { - GLint in_filter = sconf->input_tex_filter; - GLenum in_tgt; GLsizei n_params; int i; @@ -679,18 +678,15 @@ gl_shader_load_config(struct gl_shader *shader, glUniform1f(shader->view_alpha_uniform, sconf->view_alpha); - in_tgt = gl_shader_texture_variant_get_target(sconf->req.variant); - for (i = 0; i < SHADER_INPUT_TEX_MAX; i++) { - if (sconf->input_tex[i] == 0) - continue; - + assert(sconf->input_num <= SHADER_INPUT_TEX_MAX); + for (i = 0; i < sconf->input_num; i++) { assert(shader->tex_uniforms[i] != -1); glUniform1i(shader->tex_uniforms[i], TEX_UNIT_IMAGES + i); glActiveTexture(GL_TEXTURE0 + TEX_UNIT_IMAGES + i); - - glBindTexture(in_tgt, sconf->input_tex[i]); - glTexParameteri(in_tgt, GL_TEXTURE_MIN_FILTER, in_filter); - glTexParameteri(in_tgt, GL_TEXTURE_MAG_FILTER, in_filter); + glBindTexture(sconf->input_param[i].target, + sconf->input_tex[i]); + if (sconf->input_tex[i]) + gl_texture_parameters_flush(gr, &sconf->input_param[i]); } /* Fixed texture unit for color_pre_curve LUT if it is available */ @@ -809,7 +805,7 @@ gl_renderer_use_program(struct gl_renderer *gr, gr->current_shader = shader; } - gl_shader_load_config(shader, sconf); + gl_shader_load_config(gr, shader, sconf); return true; } diff --git a/libweston/renderer-gl/gl-utils.c b/libweston/renderer-gl/gl-utils.c index d87fc6619..8c08f4584 100644 --- a/libweston/renderer-gl/gl-utils.c +++ b/libweston/renderer-gl/gl-utils.c @@ -579,6 +579,63 @@ is_valid_combination_es2(struct gl_renderer *gr, } } +/* Validate texture parameters. + */ +static bool +are_valid_texture_parameters(struct gl_renderer *gr, + struct gl_texture_parameters *parameters) +{ + GLint tex = 0; + int i; + + if (parameters->target == GL_TEXTURE_2D) + glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex); + else if (parameters->target == GL_TEXTURE_3D) + glGetIntegerv(GL_TEXTURE_BINDING_3D, &tex); + else if (parameters->target == GL_TEXTURE_EXTERNAL_OES) + glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &tex); + if (tex == 0) + return false; + + /* Filters. */ + for (i = 0; i < 2; i++) { + switch (parameters->filters.array[i]) { + case GL_NEAREST: + case GL_LINEAR: + break; + + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + /* Minification filter only. */ + if (parameters->target == GL_TEXTURE_EXTERNAL_OES || + ¶meters->filters.array[i] == ¶meters->filters.mag) + return false; + break; + + default: + return false; + }; + } + + /* Wrap modes. OpenGL ES 3.2 (and extensions) has GL_CLAMP_TO_BORDER but + * Weston doesn't need it. */ + for (i = 0; i < 3; i++) { + switch (parameters->wrap_modes.array[i]) { + case GL_CLAMP_TO_EDGE: + case GL_REPEAT: + case GL_MIRRORED_REPEAT: + break; + + default: + return false; + }; + } + + return true; +} + #endif /* !defined(NDEBUG) */ /* Get the supported BGRA8 texture creation method. This is needed to correctly @@ -1214,6 +1271,81 @@ gl_texture_fini(GLuint *tex) *tex = 0; } +/* Initialise texture parameters. 'target' is either a 2D, a 3D or an external + * texture target. 'filters' points to an array of 2 values for respectively the + * texture minification and magnification filters. 'wrap_modes' points to an + * array of 3 values for the S, T and R texture wrap modes. The texture object + * bound to the given texture target (of the active texture) is updated if + * 'flush' is true, make sure it's properly bound in that case. The parameters + * and the flags bitfield can then directly be set and flushed when needed. + * + * filters are set to GL_NEAREST if 'filters' is NULL and wrap modes are set to + * GL_CLAMP_TO_EDGE if 'wrap_modes' is NULL. + * + * See gl_texture_parameters_flush(). + */ +void +gl_texture_parameters_init(struct gl_renderer *gr, + struct gl_texture_parameters *parameters, + GLenum target, + const GLint *filters, + const GLint *wrap_modes, + bool flush) +{ + GLint default_filters[] = { GL_NEAREST, GL_NEAREST }; + GLint default_wrap_modes[] = { GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, + GL_CLAMP_TO_EDGE }; + + assert(target == GL_TEXTURE_2D || + target == GL_TEXTURE_3D || + target == GL_TEXTURE_EXTERNAL_OES); + assert(target != GL_TEXTURE_3D || + gl_features_has(gr, FEATURE_TEXTURE_3D)); + assert(target != GL_TEXTURE_EXTERNAL_OES || + gl_extensions_has(gr, EXTENSION_OES_EGL_IMAGE_EXTERNAL)); + + parameters->target = target; + memcpy(¶meters->filters, filters ? filters : default_filters, + sizeof default_filters); + memcpy(¶meters->wrap_modes, wrap_modes ? wrap_modes : + default_wrap_modes, sizeof default_wrap_modes); + parameters->flags = TEXTURE_ALL_DIRTY; + + if (flush) + gl_texture_parameters_flush(gr, parameters); +} + +/* Flush texture parameters to the texture object currently bound to the texture + * target (of the active texture) set at initialisation. + * + * See gl_texture_parameters_init(). + */ +void +gl_texture_parameters_flush(struct gl_renderer *gr, + struct gl_texture_parameters *parameters) +{ + assert(are_valid_texture_parameters(gr, parameters)); + + if (parameters->flags & TEXTURE_FILTERS_DIRTY) { + glTexParameteri(parameters->target, GL_TEXTURE_MIN_FILTER, + parameters->filters.min); + glTexParameteri(parameters->target, GL_TEXTURE_MAG_FILTER, + parameters->filters.mag); + } + + if (parameters->flags & TEXTURE_WRAP_MODES_DIRTY) { + glTexParameteri(parameters->target, GL_TEXTURE_WRAP_S, + parameters->wrap_modes.s); + glTexParameteri(parameters->target, GL_TEXTURE_WRAP_T, + parameters->wrap_modes.t); + if (parameters->target == GL_TEXTURE_3D) + glTexParameteri(parameters->target, GL_TEXTURE_WRAP_R, + parameters->wrap_modes.r); + } + + parameters->flags = 0; +} + /* Check whether gl_fbo_init() supports FBO creation for a given * colour-renderable sized internal 'format' or not. */