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.
This commit is contained in:
Neil Roberts 2008-12-01 16:27:54 +00:00
parent f4465ccb05
commit be655b05ad

View File

@ -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) );
}
}