diff --git a/ChangeLog b/ChangeLog index 1b2b02a66..46109caf9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2008-12-01 Neil Roberts + + Bug 1305 - NPOT textures unaligned to a pixel sometimes have + border artifacts + + * clutter/cogl/gl/cogl-texture.c: Set the wrap mode of a texture + on demand + + Instead of setting the wrap mode once per texture at creation, it + is now changed whenever the texture is drawn. The previous value + is cached so that it isn't changed if the value is the same. + + This is used in _cogl_texture_quad_hw to only enable GL_REPEAT + mode when the coordinates are not in the range [0,1]. Otherwise it + can pull in pixels from the other edge when the texture is + rendered off-pixel. + 2008-11-28 Neil Roberts * tests/conform/test-backface-culling.c (TEXTURE_SIZE): Don't set diff --git a/clutter/cogl/gl/cogl-texture.c b/clutter/cogl/gl/cogl-texture.c index bf2eef304..a1c5e7d75 100644 --- a/clutter/cogl/gl/cogl-texture.c +++ b/clutter/cogl/gl/cogl-texture.c @@ -763,6 +763,29 @@ _cogl_texture_size_supported (GLenum gl_target, } } +static void +_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, + GLenum wrap_mode) +{ + /* Only set the wrap mode if it's different from the current + value to avoid too many GL calls */ + if (tex->wrap_mode != wrap_mode) + { + int i; + + for (i = 0; i < tex->slice_gl_handles->len; i++) + { + GLuint texnum = g_array_index (tex->slice_gl_handles, GLuint, i); + + GE( glBindTexture (tex->gl_target, texnum) ); + GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, wrap_mode) ); + GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, wrap_mode) ); + } + + tex->wrap_mode = wrap_mode; + } +} + static gboolean _cogl_texture_slices_create (CoglTexture *tex) { @@ -890,15 +913,10 @@ _cogl_texture_slices_create (CoglTexture *tex) n_slices); g_array_set_size (tex->slice_gl_handles, n_slices); - - - /* Hardware repeated tiling if supported, else tile in software*/ - if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) - && n_slices == 1) - tex->wrap_mode = GL_REPEAT; - else - tex->wrap_mode = GL_CLAMP_TO_EDGE; - + + /* Wrap mode not yet set */ + tex->wrap_mode = GL_FALSE; + /* Generate a "working set" of GL texture objects * (some implementations might supported faster * re-binding between textures inside a set) */ @@ -930,11 +948,6 @@ _cogl_texture_slices_create (CoglTexture *tex) GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, tex->min_filter) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, - tex->wrap_mode) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, - tex->wrap_mode) ); - if (tex->auto_mipmap) GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) ); @@ -1507,7 +1520,10 @@ cogl_texture_new_from_foreign (GLuint gl_handle, tex->min_filter = gl_min_filter; tex->mag_filter = gl_mag_filter; tex->max_waste = 0; - + + /* Wrap mode not yet set */ + tex->wrap_mode = GL_FALSE; + /* Create slice arrays */ tex->slice_x_spans = g_array_sized_new (FALSE, FALSE, @@ -1533,24 +1549,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle, g_array_append_val (tex->slice_y_spans, y_span); g_array_append_val (tex->slice_gl_handles, gl_handle); - - /* Force appropriate wrap parameter */ - if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && - gl_target == GL_TEXTURE_2D) - { - /* Hardware repeated tiling */ - tex->wrap_mode = GL_REPEAT; - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GL_REPEAT) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GL_REPEAT) ); - } - else - { - /* Any tiling will be done in software */ - tex->wrap_mode = GL_CLAMP_TO_EDGE; - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) ); - } - + return _cogl_texture_handle_new (tex); } @@ -1952,6 +1951,10 @@ _cogl_texture_quad_sw (CoglTexture *tex, cogl_enable (enable_flags); + /* We can't use hardware repeat so we need to set clamp to edge + otherwise it might pull in edge pixels from the other side */ + _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE); + /* If the texture coordinates are backwards then swap both the geometry and texture coordinates so that the texture will be flipped but we can still use the same algorithm to iterate the @@ -2129,7 +2132,19 @@ _cogl_texture_quad_hw (CoglTexture *tex, enable_flags |= COGL_ENABLE_BACKFACE_CULLING; cogl_enable (enable_flags); - + + + /* If the texture coords are all in the range [0,1] then we want to + clamp the coords to the edge otherwise it can pull in edge pixels + from the wrong side when scaled */ + if (tx1 >= 0 && tx1 <= COGL_FIXED_1 + && tx2 >= 0 && tx2 <= COGL_FIXED_1 + && ty1 >= 0 && ty1 <= COGL_FIXED_1 + && ty2 >= 0 && ty2 <= COGL_FIXED_1) + _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE); + else + _cogl_texture_set_wrap_mode_parameter (tex, GL_REPEAT); + GE( glTexCoordPointer (2, GL_FLOAT, 0, tex_coords) ); GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords) ); @@ -2295,15 +2310,7 @@ cogl_texture_polygon (CoglHandle handle, /* Temporarily change the wrapping mode on all of the slices to use a transparent border */ - for (i = 0; i < tex->slice_gl_handles->len; i++) - { - GE( glBindTexture (tex->gl_target, - g_array_index (tex->slice_gl_handles, GLuint, i)) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_BORDER) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_BORDER) ); - } + _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER); tex_num = 0; @@ -2350,13 +2357,4 @@ cogl_texture_polygon (CoglHandle handle, GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); } } - - /* Restore the wrapping mode */ - for (i = 0; i < tex->slice_gl_handles->len; i++) - { - GE( glBindTexture (tex->gl_target, - g_array_index (tex->slice_gl_handles, GLuint, i)) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, tex->wrap_mode) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, tex->wrap_mode) ); - } }