Bug 1196 - Texture border drawing problems

* clutter/cogl/gl/cogl-texture.c (_cogl_texture_upload_subregion_to_gl)
	(_cogl_texture_upload_to_gl):

	* clutter/cogl/gles/cogl-texture.c (_cogl_texture_upload_to_gl)
	(_cogl_texture_upload_subregion_to_gl):
	
	When uploading data to a sliced texture, fill the waste pixels
	with copies of the edge of the real texture data. Otherwise the
	value of the waste pixels are undefined so it will show artifacts
	when the texture is scaled with GL_LINEAR and the pixels are
	blended in.
This commit is contained in:
Neil Roberts 2008-10-27 12:39:22 +00:00
parent 73b6bd2f17
commit e43b7ddd3d
3 changed files with 418 additions and 24 deletions

View File

@ -1,3 +1,19 @@
2008-10-27 Neil Roberts <neil@linux.intel.com>
Bug 1196 - Texture border drawing problems
* clutter/cogl/gl/cogl-texture.c (_cogl_texture_upload_subregion_to_gl)
(_cogl_texture_upload_to_gl):
* clutter/cogl/gles/cogl-texture.c (_cogl_texture_upload_to_gl)
(_cogl_texture_upload_subregion_to_gl):
When uploading data to a sliced texture, fill the waste pixels
with copies of the edge of the real texture data. Otherwise the
value of the waste pixels are undefined so it will show artifacts
when the texture is scaled with GL_LINEAR and the pixels are
blended in.
2008-10-22 Thomas Wood <thomas@linux.intel.com>
* tests/test-actors.c: Don't adjust the radius based on the number of

View File

@ -212,6 +212,35 @@ _cogl_subregion_gl_store_rules (gint bmp_rowstride,
GE( glPixelStorei (SKIP_PIXELS, src_x) );
}
static guchar *
_cogl_texture_allocate_waste_buffer (CoglTexture *tex)
{
CoglTexSliceSpan *last_x_span;
CoglTexSliceSpan *last_y_span;
guchar *waste_buf = NULL;
/* If the texture has any waste then allocate a buffer big enough to
fill the gaps */
last_x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan,
tex->slice_x_spans->len - 1);
last_y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan,
tex->slice_y_spans->len - 1);
if (last_x_span->waste > 0 || last_y_span->waste > 0)
{
gint bpp = _cogl_get_format_bpp (tex->bitmap.format);
CoglTexSliceSpan *first_x_span
= &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
CoglTexSliceSpan *first_y_span
= &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
guint right_size = first_y_span->size * last_x_span->waste;
guint bottom_size = first_x_span->size * last_y_span->waste;
waste_buf = g_malloc (MAX (right_size, bottom_size) * bpp);
}
return waste_buf;
}
static gboolean
_cogl_texture_upload_to_gl (CoglTexture *tex)
{
@ -220,9 +249,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
GLuint gl_handle;
gint bpp;
gint x,y;
guchar *waste_buf;
bpp = _cogl_get_format_bpp (tex->bitmap.format);
waste_buf = _cogl_texture_allocate_waste_buffer (tex);
/* Iterate vertical slices */
for (y = 0; y < tex->slice_y_spans->len; ++y)
{
@ -253,9 +285,78 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
y_span->size - y_span->waste,
tex->gl_format, tex->gl_type,
tex->bitmap.data) );
/* Fill the waste with a copies of the rightmost pixels */
if (x_span->waste > 0)
{
const guchar *src = tex->bitmap.data
+ y_span->start * tex->bitmap.rowstride
+ (x_span->start + x_span->size - x_span->waste - 1) * bpp;
guchar *dst = waste_buf;
guint wx, wy;
for (wy = 0; wy < y_span->size - y_span->waste; wy++)
{
for (wx = 0; wx < x_span->waste; wx++)
{
memcpy (dst, src, bpp);
dst += bpp;
}
src += tex->bitmap.rowstride;
}
_cogl_subregion_gl_store_rules (x_span->waste * bpp,
x_span->waste,
bpp,
0, 0, FALSE);
GE( glTexSubImage2D (tex->gl_target, 0,
x_span->size - x_span->waste, 0,
x_span->waste,
y_span->size - y_span->waste,
tex->gl_format, tex->gl_type,
waste_buf) );
}
if (y_span->waste > 0)
{
const guchar *src = tex->bitmap.data
+ ((y_span->start + y_span->size - y_span->waste - 1)
* tex->bitmap.rowstride)
+ x_span->start * bpp;
guchar *dst = waste_buf;
guint wy, wx;
for (wy = 0; wy < y_span->waste; wy++)
{
memcpy (dst, src, (x_span->size - x_span->waste) * bpp);
dst += (x_span->size - x_span->waste) * bpp;
for (wx = 0; wx < x_span->waste; wx++)
{
memcpy (dst, dst - bpp, bpp);
dst += bpp;
}
}
_cogl_subregion_gl_store_rules (x_span->size * bpp,
x_span->size,
bpp,
0, 0, FALSE);
GE( glTexSubImage2D (tex->gl_target, 0,
0, y_span->size - y_span->waste,
x_span->size,
y_span->waste,
tex->gl_format, tex->gl_type,
waste_buf) );
}
}
}
if (waste_buf)
g_free (waste_buf);
return TRUE;
}
@ -374,16 +475,21 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
GLuint source_gl_format,
GLuint source_gl_type)
{
gint bpp;
CoglSpanIter x_iter;
CoglSpanIter y_iter;
GLuint gl_handle;
gint source_x = 0, source_y = 0;
gint inter_w = 0, inter_h = 0;
gint local_x = 0, local_y = 0;
CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span;
gint bpp;
CoglSpanIter x_iter;
CoglSpanIter y_iter;
GLuint gl_handle;
gint source_x = 0, source_y = 0;
gint inter_w = 0, inter_h = 0;
gint local_x = 0, local_y = 0;
guchar *waste_buf;
bpp = _cogl_get_format_bpp (source_bmp->format);
waste_buf = _cogl_texture_allocate_waste_buffer (tex);
/* Iterate vertical spans */
for (source_y = src_y,
_cogl_span_iter_begin (&y_iter, tex->slice_y_spans,
@ -402,6 +508,9 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
continue;
}
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan,
y_iter.index);
/* Iterate horizontal spans */
for (source_x = src_x,
_cogl_span_iter_begin (&x_iter, tex->slice_x_spans,
@ -420,6 +529,9 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
continue;
}
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan,
x_iter.index);
/* Pick intersection width and height */
inter_w = CLUTTER_FIXED_TO_INT (x_iter.intersect_end -
x_iter.intersect_start);
@ -455,9 +567,96 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
source_gl_format,
source_gl_type,
source_bmp->data) );
/* If the x_span is sliced and the upload touches the
rightmost pixels then fill the waste with copies of the
pixels */
if (x_span->waste > 0
&& local_x < x_span->size - x_span->waste
&& local_x + inter_w >= x_span->size - x_span->waste)
{
const guchar *src = source_bmp->data
+ (src_y + CLUTTER_FIXED_TO_INT (y_iter.intersect_start)
- dst_y) * source_bmp->rowstride
+ (src_x + x_span->start + x_span->size - x_span->waste
- dst_x - 1) * bpp;
guchar *dst = waste_buf;
guint wx, wy;
for (wy = 0; wy < inter_h; wy++)
{
for (wx = 0; wx < x_span->waste; wx++)
{
memcpy (dst, src, bpp);
dst += bpp;
}
src += source_bmp->rowstride;
}
_cogl_subregion_gl_store_rules (x_span->waste * bpp,
x_span->waste,
bpp,
0, 0, FALSE);
GE( glTexSubImage2D (tex->gl_target, 0,
x_span->size - x_span->waste, local_y,
x_span->waste,
inter_h,
source_gl_format,
source_gl_type,
waste_buf) );
}
/* same for the bottom-most pixels */
if (y_span->waste > 0
&& local_y < y_span->size - y_span->waste
&& local_y + inter_h >= y_span->size - y_span->waste)
{
const guchar *src = source_bmp->data
+ (src_x + CLUTTER_FIXED_TO_INT (x_iter.intersect_start)
- dst_x) * bpp
+ (src_y + y_span->start + y_span->size - y_span->waste
- dst_y - 1) * source_bmp->rowstride;
guchar *dst = waste_buf;
guint wy, wx;
guint copy_width;
if (local_x + inter_w >= x_span->size - x_span->waste)
copy_width = x_span->size - local_x;
else
copy_width = inter_w;
for (wy = 0; wy < y_span->waste; wy++)
{
memcpy (dst, src, inter_w * bpp);
dst += inter_w * bpp;
for (wx = inter_w; wx < copy_width; wx++)
{
memcpy (dst, dst - bpp, bpp);
dst += bpp;
}
}
_cogl_subregion_gl_store_rules (copy_width * bpp,
copy_width,
bpp,
0, 0, FALSE);
GE( glTexSubImage2D (tex->gl_target, 0,
local_x, y_span->size - y_span->waste,
copy_width,
y_span->waste,
source_gl_format,
source_gl_type,
waste_buf) );
}
}
}
if (waste_buf)
g_free (waste_buf);
return TRUE;
}

View File

@ -174,6 +174,35 @@ _cogl_span_iter_end (CoglSpanIter *iter)
return iter->pos >= iter->cover_end;
}
static guchar *
_cogl_texture_allocate_waste_buffer (CoglTexture *tex)
{
CoglTexSliceSpan *last_x_span;
CoglTexSliceSpan *last_y_span;
guchar *waste_buf = NULL;
/* If the texture has any waste then allocate a buffer big enough to
fill the gaps */
last_x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan,
tex->slice_x_spans->len - 1);
last_y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan,
tex->slice_y_spans->len - 1);
if (last_x_span->waste > 0 || last_y_span->waste > 0)
{
gint bpp = _cogl_get_format_bpp (tex->bitmap.format);
CoglTexSliceSpan *first_x_span
= &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
CoglTexSliceSpan *first_y_span
= &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
guint right_size = first_y_span->size * last_x_span->waste;
guint bottom_size = first_x_span->size * last_y_span->waste;
waste_buf = g_malloc (MAX (right_size, bottom_size) * bpp);
}
return waste_buf;
}
static gboolean
_cogl_texture_upload_to_gl (CoglTexture *tex)
{
@ -182,6 +211,7 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
GLuint gl_handle;
gint bpp;
gint x,y;
guchar *waste_buf;
CoglBitmap slice_bmp;
/* FIXME: might optimize by not copying to intermediate slice
@ -190,6 +220,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
bpp = _cogl_get_format_bpp (tex->bitmap.format);
waste_buf = _cogl_texture_allocate_waste_buffer (tex);
/* Iterate vertical slices */
for (y = 0; y < tex->slice_y_spans->len; ++y)
{
@ -233,6 +265,62 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
tex->gl_format, tex->gl_type,
slice_bmp.data) );
/* Fill the waste with a copies of the rightmost pixels */
if (x_span->waste > 0)
{
const guchar *src = tex->bitmap.data
+ y_span->start * tex->bitmap.rowstride
+ (x_span->start + x_span->size - x_span->waste - 1) * bpp;
guchar *dst = waste_buf;
guint wx, wy;
for (wy = 0; wy < y_span->size - y_span->waste; wy++)
{
for (wx = 0; wx < x_span->waste; wx++)
{
memcpy (dst, src, bpp);
dst += bpp;
}
src += tex->bitmap.rowstride;
}
GE( glTexSubImage2D (tex->gl_target, 0,
x_span->size - x_span->waste, 0,
x_span->waste,
y_span->size - y_span->waste,
tex->gl_format, tex->gl_type,
waste_buf) );
}
if (y_span->waste > 0)
{
const guchar *src = tex->bitmap.data
+ ((y_span->start + y_span->size - y_span->waste - 1)
* tex->bitmap.rowstride)
+ x_span->start * bpp;
guchar *dst = waste_buf;
guint wy, wx;
for (wy = 0; wy < y_span->waste; wy++)
{
memcpy (dst, src, (x_span->size - x_span->waste) * bpp);
dst += (x_span->size - x_span->waste) * bpp;
for (wx = 0; wx < x_span->waste; wx++)
{
memcpy (dst, dst - bpp, bpp);
dst += bpp;
}
}
GE( glTexSubImage2D (tex->gl_target, 0,
0, y_span->size - y_span->waste,
x_span->size,
y_span->waste,
tex->gl_format, tex->gl_type,
waste_buf) );
}
if (tex->auto_mipmap)
cogl_wrap_glGenerateMipmap (tex->gl_target);
@ -240,7 +328,10 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
g_free (slice_bmp.data);
}
}
if (waste_buf)
g_free (waste_buf);
return TRUE;
}
@ -494,17 +585,22 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
GLuint source_gl_format,
GLuint source_gl_type)
{
gint bpp;
CoglSpanIter x_iter;
CoglSpanIter y_iter;
GLuint gl_handle;
gint source_x = 0, source_y = 0;
gint inter_w = 0, inter_h = 0;
gint local_x = 0, local_y = 0;
CoglBitmap slice_bmp;
CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span;
gint bpp;
CoglSpanIter x_iter;
CoglSpanIter y_iter;
GLuint gl_handle;
gint source_x = 0, source_y = 0;
gint inter_w = 0, inter_h = 0;
gint local_x = 0, local_y = 0;
guchar *waste_buf;
CoglBitmap slice_bmp;
bpp = _cogl_get_format_bpp (source_bmp->format);
waste_buf = _cogl_texture_allocate_waste_buffer (tex);
/* FIXME: might optimize by not copying to intermediate slice
bitmap when source rowstride = bpp * width and the texture
image is not sliced */
@ -526,7 +622,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
inter_h = 0;
continue;
}
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan,
y_iter.index);
/* Iterate horizontal spans */
for (source_x = src_x,
_cogl_span_iter_begin (&x_iter, tex->slice_x_spans,
@ -544,7 +643,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
inter_w = 0;
continue;
}
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan,
x_iter.index);
/* Pick intersection width and height */
inter_w = CLUTTER_FIXED_TO_INT (x_iter.intersect_end -
x_iter.intersect_start);
@ -591,7 +693,81 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
source_gl_format,
source_gl_type,
slice_bmp.data) );
/* If the x_span is sliced and the upload touches the
rightmost pixels then fill the waste with copies of the
pixels */
if (x_span->waste > 0
&& local_x < x_span->size - x_span->waste
&& local_x + inter_w >= x_span->size - x_span->waste)
{
const guchar *src = source_bmp->data
+ (src_y + CLUTTER_FIXED_TO_INT (y_iter.intersect_start)
- dst_y) * source_bmp->rowstride
+ (src_x + x_span->start + x_span->size - x_span->waste
- dst_x - 1) * bpp;
guchar *dst = waste_buf;
guint wx, wy;
for (wy = 0; wy < inter_h; wy++)
{
for (wx = 0; wx < x_span->waste; wx++)
{
memcpy (dst, src, bpp);
dst += bpp;
}
src += source_bmp->rowstride;
}
GE( glTexSubImage2D (tex->gl_target, 0,
x_span->size - x_span->waste, local_y,
x_span->waste,
inter_h,
source_gl_format,
source_gl_type,
waste_buf) );
}
/* same for the bottom-most pixels */
if (y_span->waste > 0
&& local_y < y_span->size - y_span->waste
&& local_y + inter_h >= y_span->size - y_span->waste)
{
const guchar *src = source_bmp->data
+ (src_x + CLUTTER_FIXED_TO_INT (x_iter.intersect_start)
- dst_x) * bpp
+ (src_y + y_span->start + y_span->size - y_span->waste
- dst_y - 1) * source_bmp->rowstride;
guchar *dst = waste_buf;
guint wy, wx;
guint copy_width;
if (local_x + inter_w >= x_span->size - x_span->waste)
copy_width = x_span->size - local_x;
else
copy_width = inter_w;
for (wy = 0; wy < y_span->waste; wy++)
{
memcpy (dst, src, inter_w * bpp);
dst += inter_w * bpp;
for (wx = inter_w; wx < copy_width; wx++)
{
memcpy (dst, dst - bpp, bpp);
dst += bpp;
}
}
GE( glTexSubImage2D (tex->gl_target, 0,
local_x, y_span->size - y_span->waste,
copy_width,
y_span->waste,
source_gl_format,
source_gl_type,
waste_buf) );
}
if (tex->auto_mipmap)
cogl_wrap_glGenerateMipmap (tex->gl_target);
@ -599,7 +775,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
g_free (slice_bmp.data);
}
}
if (waste_buf)
g_free (waste_buf);
return TRUE;
}