Update the GLES backend to have the layer filters in the material

This reflects the changes made in 54d8aadf1d for the GLES backend.
This commit is contained in:
Neil Roberts 2009-06-04 22:12:33 +01:00
parent eff82a546d
commit 6efbb92c58
2 changed files with 147 additions and 76 deletions

View File

@ -30,6 +30,7 @@
typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglTexSliceSpan CoglTexSliceSpan;
typedef struct _CoglSpanIter CoglSpanIter; typedef struct _CoglSpanIter CoglSpanIter;
typedef struct _CoglTexturePixel CoglTexturePixel;
struct _CoglTexSliceSpan struct _CoglTexSliceSpan
{ {
@ -55,6 +56,18 @@ struct _CoglSpanIter
gboolean intersects; gboolean intersects;
}; };
/* This is used to store the first pixel of each slice. This is only
used when glGenerateMipmap is not available */
struct _CoglTexturePixel
{
/* We need to store the format of the pixel because we store the
data in the source format which might end up being different for
each slice if a subregion is updated with a different format */
GLenum gl_format;
GLenum gl_type;
guint8 data[4];
};
struct _CoglTexture struct _CoglTexture
{ {
CoglHandleObject _parent; CoglHandleObject _parent;
@ -68,11 +81,17 @@ struct _CoglTexture
GArray *slice_y_spans; GArray *slice_y_spans;
GArray *slice_gl_handles; GArray *slice_gl_handles;
gint max_waste; gint max_waste;
CoglTextureFilter min_filter; GLenum min_filter;
CoglTextureFilter mag_filter; GLenum mag_filter;
gboolean is_foreign; gboolean is_foreign;
GLint wrap_mode; GLint wrap_mode;
gboolean auto_mipmap; gboolean auto_mipmap;
gboolean mipmaps_dirty;
/* This holds a copy of the first pixel in each slice. It is only
used to force an automatic update of the mipmaps when
glGenerateMipmap is not available. */
CoglTexturePixel *first_pixels;
}; };
/* To improve batching of geometry when submitting vertices to OpenGL we /* To improve batching of geometry when submitting vertices to OpenGL we
@ -93,6 +112,14 @@ void
_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
GLenum wrap_mode); GLenum wrap_mode);
void
_cogl_texture_set_filters (CoglHandle handle,
GLenum min_filter,
GLenum mag_filter);
void
_cogl_texture_ensure_mipmaps (CoglHandle handle);
gboolean gboolean
_cogl_texture_span_has_waste (CoglTexture *tex, _cogl_texture_span_has_waste (CoglTexture *tex,
gint x_span_index, gint x_span_index,

View File

@ -225,11 +225,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
/* Iterate horizontal slices */ /* Iterate horizontal slices */
for (x = 0; x < tex->slice_x_spans->len; ++x) for (x = 0; x < tex->slice_x_spans->len; ++x)
{ {
gint slice_num = y * tex->slice_x_spans->len + x;
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
/* Pick the gl texture object handle */ /* Pick the gl texture object handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
y * tex->slice_x_spans->len + x);
/* FIXME: might optimize by not copying to intermediate slice /* FIXME: might optimize by not copying to intermediate slice
bitmap when source rowstride = bpp * width and the texture bitmap when source rowstride = bpp * width and the texture
@ -258,6 +259,16 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
slice_bmp.width, slice_bmp.width,
slice_bmp.height); slice_bmp.height);
/* Keep a copy of the first pixel if needed */
if (tex->first_pixels)
{
memcpy (tex->first_pixels[slice_num].data,
slice_bmp.data,
bpp);
tex->first_pixels[slice_num].gl_format = tex->gl_format;
tex->first_pixels[slice_num].gl_type = tex->gl_type;
}
/* Upload new image data */ /* Upload new image data */
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) ); tex->gl_intformat) );
@ -338,9 +349,6 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
waste_buf) ); waste_buf) );
} }
if (tex->auto_mipmap)
cogl_wrap_glGenerateMipmap (tex->gl_target);
/* Free temp bitmap */ /* Free temp bitmap */
g_free (slice_bmp.data); g_free (slice_bmp.data);
} }
@ -349,6 +357,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
if (waste_buf) if (waste_buf)
g_free (waste_buf); g_free (waste_buf);
tex->mipmaps_dirty = TRUE;
return TRUE; return TRUE;
} }
@ -624,6 +634,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
_cogl_span_iter_next (&x_iter), _cogl_span_iter_next (&x_iter),
source_x += inter_w ) source_x += inter_w )
{ {
gint slice_num;
/* Discard slices out of the subregion early */ /* Discard slices out of the subregion early */
if (!x_iter.intersects) if (!x_iter.intersects)
{ {
@ -646,10 +658,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
local_y = (y_iter.intersect_start - local_y = (y_iter.intersect_start -
y_iter.pos); y_iter.pos);
slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index;
/* Pick slice GL handle */ /* Pick slice GL handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num);
y_iter.index * tex->slice_x_spans->len +
x_iter.index);
/* FIXME: might optimize by not copying to intermediate slice /* FIXME: might optimize by not copying to intermediate slice
bitmap when source rowstride = bpp * width and the texture bitmap when source rowstride = bpp * width and the texture
@ -678,6 +690,15 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
slice_bmp.width, slice_bmp.width,
slice_bmp.height); slice_bmp.height);
/* Keep a copy of the first pixel if needed */
if (tex->first_pixels && local_x == 0 && local_y == 0)
{
memcpy (tex->first_pixels[slice_num].data,
slice_bmp.data, bpp);
tex->first_pixels[slice_num].gl_format = source_gl_format;
tex->first_pixels[slice_num].gl_type = source_gl_type;
}
/* Upload new image data */ /* Upload new image data */
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
tex->gl_intformat) ); tex->gl_intformat) );
@ -787,9 +808,6 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
waste_buf) ); waste_buf) );
} }
if (tex->auto_mipmap)
cogl_wrap_glGenerateMipmap (tex->gl_target);
/* Free temp bitmap */ /* Free temp bitmap */
g_free (slice_bmp.data); g_free (slice_bmp.data);
} }
@ -798,6 +816,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
if (waste_buf) if (waste_buf)
g_free (waste_buf); g_free (waste_buf);
tex->mipmaps_dirty = TRUE;
return TRUE; return TRUE;
} }
@ -1055,6 +1075,14 @@ _cogl_texture_slices_create (CoglTexture *tex)
g_array_set_size (tex->slice_gl_handles, n_slices); g_array_set_size (tex->slice_gl_handles, n_slices);
/* Allocate some space to store a copy of the first pixel of each
slice. This is only needed to glGenerateMipmap (which is part of
the FBO extension) is not available */
if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
tex->first_pixels = NULL;
else
tex->first_pixels = g_new (CoglTexturePixel, n_slices);
/* Wrap mode not yet set */ /* Wrap mode not yet set */
tex->wrap_mode = GL_FALSE; tex->wrap_mode = GL_FALSE;
@ -1085,20 +1113,11 @@ _cogl_texture_slices_create (CoglTexture *tex)
GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, GE( cogl_gles2_wrapper_bind_texture (tex->gl_target,
gl_handles[y * n_x_slices + x], gl_handles[y * n_x_slices + x],
tex->gl_intformat) ); tex->gl_intformat) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER,
tex->mag_filter) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER,
tex->min_filter) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S,
tex->wrap_mode) ); tex->wrap_mode) );
GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T,
tex->wrap_mode) ); tex->wrap_mode) );
if (tex->auto_mipmap)
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP,
GL_TRUE) );
/* Pass NULL data to init size and internal format */ /* Pass NULL data to init size and internal format */
GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat, GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat,
x_span->size, y_span->size, 0, x_span->size, y_span->size, 0,
@ -1128,6 +1147,9 @@ _cogl_texture_slices_free (CoglTexture *tex)
g_array_free (tex->slice_gl_handles, TRUE); g_array_free (tex->slice_gl_handles, TRUE);
} }
if (tex->first_pixels != NULL)
g_free (tex->first_pixels);
} }
gboolean gboolean
@ -1307,7 +1329,8 @@ cogl_texture_new_with_size (guint width,
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
tex->is_foreign = FALSE; tex->is_foreign = FALSE;
tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
tex->mipmaps_dirty = TRUE;
tex->bitmap.width = width; tex->bitmap.width = width;
tex->bitmap.height = height; tex->bitmap.height = height;
@ -1325,8 +1348,9 @@ cogl_texture_new_with_size (guint width,
else else
tex->max_waste = COGL_TEXTURE_MAX_WASTE; tex->max_waste = COGL_TEXTURE_MAX_WASTE;
tex->min_filter = CGL_NEAREST; /* Unknown filter */
tex->mag_filter = CGL_NEAREST; tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* Find closest GL format match */ /* Find closest GL format match */
tex->bitmap.format = tex->bitmap.format =
@ -1371,7 +1395,8 @@ cogl_texture_new_from_data (guint width,
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
tex->is_foreign = FALSE; tex->is_foreign = FALSE;
tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
tex->mipmaps_dirty = TRUE;
tex->bitmap.width = width; tex->bitmap.width = width;
tex->bitmap.height = height; tex->bitmap.height = height;
@ -1389,8 +1414,9 @@ cogl_texture_new_from_data (guint width,
else else
tex->max_waste = COGL_TEXTURE_MAX_WASTE; tex->max_waste = COGL_TEXTURE_MAX_WASTE;
tex->min_filter = CGL_NEAREST; /* Unknown filter */
tex->mag_filter = CGL_NEAREST; tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* FIXME: If upload fails we should set some kind of /* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle (this * error flag but still return texture handle (this
@ -1432,7 +1458,8 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
tex->is_foreign = FALSE; tex->is_foreign = FALSE;
tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
tex->mipmaps_dirty = TRUE;
tex->bitmap = *bmp; tex->bitmap = *bmp;
tex->bitmap_owner = TRUE; tex->bitmap_owner = TRUE;
@ -1447,8 +1474,9 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle,
else else
tex->max_waste = COGL_TEXTURE_MAX_WASTE; tex->max_waste = COGL_TEXTURE_MAX_WASTE;
tex->min_filter = CGL_NEAREST; /* Unknown filter */
tex->mag_filter = CGL_NEAREST; tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
/* FIXME: If upload fails we should set some kind of /* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle if the * error flag but still return texture handle if the
@ -1524,8 +1552,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GLint gl_int_format = 0; GLint gl_int_format = 0;
GLint gl_width = 0; GLint gl_width = 0;
GLint gl_height = 0; GLint gl_height = 0;
GLint gl_min_filter;
GLint gl_mag_filter;
GLint gl_gen_mipmap; GLint gl_gen_mipmap;
guint bpp; guint bpp;
CoglTexture *tex; CoglTexture *tex;
@ -1572,14 +1598,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
gl_height = height + y_pot_waste; gl_height = height + y_pot_waste;
#endif #endif
GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MIN_FILTER,
&gl_min_filter) );
GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MAG_FILTER,
&gl_mag_filter) );
GE( glGetTexParameteriv (gl_target, GE( glGetTexParameteriv (gl_target,
GL_GENERATE_MIPMAP, GL_GENERATE_MIPMAP,
&gl_gen_mipmap) ); &gl_gen_mipmap) );
@ -1610,6 +1628,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
/* Setup bitmap info */ /* Setup bitmap info */
tex->is_foreign = TRUE; tex->is_foreign = TRUE;
tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE;
tex->mipmaps_dirty = TRUE;
bpp = _cogl_get_format_bpp (format); bpp = _cogl_get_format_bpp (format);
tex->bitmap.format = format; tex->bitmap.format = format;
@ -1623,8 +1642,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
tex->gl_format = gl_int_format; tex->gl_format = gl_int_format;
tex->gl_type = GL_UNSIGNED_BYTE; tex->gl_type = GL_UNSIGNED_BYTE;
tex->min_filter = gl_min_filter; /* Unknown filter */
tex->mag_filter = gl_mag_filter; tex->min_filter = GL_FALSE;
tex->mag_filter = GL_FALSE;
tex->max_waste = 0; tex->max_waste = 0;
/* Wrap mode not yet set */ /* Wrap mode not yet set */
@ -1770,36 +1790,10 @@ cogl_texture_get_gl_texture (CoglHandle handle,
return TRUE; return TRUE;
} }
CoglTextureFilter
cogl_texture_get_min_filter (CoglHandle handle)
{
CoglTexture *tex;
if (!cogl_is_texture (handle))
return 0;
tex = _cogl_texture_pointer_from_handle (handle);
return tex->min_filter;
}
CoglTextureFilter
cogl_texture_get_mag_filter (CoglHandle handle)
{
CoglTexture *tex;
if (!cogl_is_texture (handle))
return 0;
tex = _cogl_texture_pointer_from_handle (handle);
return tex->mag_filter;
}
void void
cogl_texture_set_filters (CoglHandle handle, _cogl_texture_set_filters (CoglHandle handle,
CoglTextureFilter min_filter, GLenum min_filter,
CoglTextureFilter mag_filter) GLenum mag_filter)
{ {
CoglTexture *tex; CoglTexture *tex;
GLuint gl_handle; GLuint gl_handle;
@ -1810,14 +1804,18 @@ cogl_texture_set_filters (CoglHandle handle,
tex = _cogl_texture_pointer_from_handle (handle); tex = _cogl_texture_pointer_from_handle (handle);
/* Store new values */
tex->min_filter = min_filter;
tex->mag_filter = mag_filter;
/* Make sure slices were created */ /* Make sure slices were created */
if (tex->slice_gl_handles == NULL) if (tex->slice_gl_handles == NULL)
return; return;
if (min_filter == tex->min_filter
&& mag_filter == tex->mag_filter)
return;
/* Store new values */
tex->min_filter = min_filter;
tex->mag_filter = mag_filter;
/* Apply new filters to every slice */ /* Apply new filters to every slice */
for (i=0; i<tex->slice_gl_handles->len; ++i) for (i=0; i<tex->slice_gl_handles->len; ++i)
{ {
@ -1830,6 +1828,52 @@ cogl_texture_set_filters (CoglHandle handle,
} }
} }
void
_cogl_texture_ensure_mipmaps (CoglHandle handle)
{
CoglTexture *tex;
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!cogl_is_texture (handle))
return;
tex = _cogl_texture_pointer_from_handle (handle);
/* Only update if the mipmaps are dirty */
if (!tex->auto_mipmap || !tex->mipmaps_dirty)
return;
/* Make sure slices were created */
if (tex->slice_gl_handles == NULL)
return;
/* Regenerate the mipmaps on every slice */
for (i = 0; i < tex->slice_gl_handles->len; i++)
{
GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i);
GE( glBindTexture (tex->gl_target, gl_handle) );
/* glGenerateMipmap is defined in the FBO extension */
if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
GE( cogl_wrap_glGenerateMipmap (tex->gl_target) );
else
{
CoglTexturePixel *pixel = tex->first_pixels + i;
/* Temporarily enable automatic mipmap generation and
re-upload the first pixel to cause a regeneration */
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) );
GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 1, 1,
pixel->gl_format, pixel->gl_type,
pixel->data) );
GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) );
}
}
tex->mipmaps_dirty = FALSE;
}
gboolean gboolean
cogl_texture_set_region (CoglHandle handle, cogl_texture_set_region (CoglHandle handle,
gint src_x, gint src_x,