diff options
author | Robert Bragg <robert@linux.intel.com> | 2012-11-09 17:55:54 +0000 |
---|---|---|
committer | Robert Bragg <robert@linux.intel.com> | 2012-11-27 19:04:15 +0000 |
commit | 3a336a8adcd406b53731a6de0e7d97ba7932c1a8 (patch) | |
tree | c1480c4ae9b2972dd1890428f679e4a79a28f0b6 | |
parent | 1206a05358dfedd96a865ec084229c69dd4f36d2 (diff) | |
download | cogl-3a336a8adcd406b53731a6de0e7d97ba7932c1a8.tar.gz |
texture: expose mipmap level in set region apis
cogl_texture_set_region() and cogl_texture_set_region_from_bitmap() now
have a level argument so image data can be uploaded to a specific mipmap
level.
The prototype for cogl_texture_set_region was also updated to simplify
the arguments.
The arguments for cogl_texture_set_region_from_bitmap were reordered to
be consistent with cogl_texture_set_region with the source related
arguments listed first followed by the destination arguments.
Reviewed-by: Neil Roberts <neil@linux.intel.com>
30 files changed, 597 insertions, 259 deletions
diff --git a/cogl-pango/cogl-pango-render.c b/cogl-pango/cogl-pango-render.c index 16f70b70..e296b2d8 100644 --- a/cogl-pango/cogl-pango-render.c +++ b/cogl-pango/cogl-pango-render.c @@ -572,17 +572,14 @@ cogl_pango_renderer_set_dirty_glyph (PangoFont *font, /* Copy the glyph to the texture */ cogl_texture_set_region (value->texture, - 0, /* src_x */ - 0, /* src_y */ - value->tx_pixel, /* dst_x */ - value->ty_pixel, /* dst_y */ - value->draw_width, /* dst_width */ - value->draw_height, /* dst_height */ - value->draw_width, /* width */ - value->draw_height, /* height */ + value->draw_width, + value->draw_height, format_cogl, cairo_image_surface_get_stride (surface), cairo_image_surface_get_data (surface), + value->tx_pixel, /* dst_x */ + value->ty_pixel, /* dst_y */ + 0, /* level */ NULL); /* don't catch errors */ cairo_surface_destroy (surface); diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c index db7b9277..e878a3a4 100644 --- a/cogl/cogl-atlas-texture.c +++ b/cogl/cogl-atlas-texture.c @@ -459,11 +459,12 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex, /* Copy the central data */ if (!cogl_texture_set_region_from_bitmap (atlas->texture, src_x, src_y, - dst_x + atlas_tex->rectangle.x + 1, - dst_y + atlas_tex->rectangle.y + 1, dst_width, dst_height, bmp, + dst_x + atlas_tex->rectangle.x + 1, + dst_y + atlas_tex->rectangle.y + 1, + 0, /* level 0 */ error)) return FALSE; @@ -471,42 +472,46 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex, if (dst_x == 0 && !cogl_texture_set_region_from_bitmap (atlas->texture, src_x, src_y, - atlas_tex->rectangle.x, - dst_y + atlas_tex->rectangle.y + 1, 1, dst_height, bmp, + atlas_tex->rectangle.x, + dst_y + atlas_tex->rectangle.y + 1, + 0, /* level 0 */ error)) return FALSE; /* Update the right edge pixels */ if (dst_x + dst_width == atlas_tex->rectangle.width - 2 && !cogl_texture_set_region_from_bitmap (atlas->texture, src_x + dst_width - 1, src_y, + 1, dst_height, + bmp, atlas_tex->rectangle.x + atlas_tex->rectangle.width - 1, dst_y + atlas_tex->rectangle.y + 1, - 1, dst_height, - bmp, + 0, /* level 0 */ error)) return FALSE; /* Update the top edge pixels */ if (dst_y == 0 && !cogl_texture_set_region_from_bitmap (atlas->texture, src_x, src_y, - dst_x + atlas_tex->rectangle.x + 1, - atlas_tex->rectangle.y, dst_width, 1, bmp, + dst_x + atlas_tex->rectangle.x + 1, + atlas_tex->rectangle.y, + 0, /* level 0 */ error)) return FALSE; /* Update the bottom edge pixels */ if (dst_y + dst_height == atlas_tex->rectangle.height - 2 && !cogl_texture_set_region_from_bitmap (atlas->texture, src_x, src_y + dst_height - 1, + dst_width, 1, + bmp, dst_x + atlas_tex->rectangle.x + 1, atlas_tex->rectangle.y + atlas_tex->rectangle.height - 1, - dst_width, 1, - bmp, + 0, /* level 0 */ error)) return FALSE; @@ -569,11 +574,15 @@ _cogl_atlas_texture_set_region (CoglTexture *tex, int dst_y, int dst_width, int dst_height, + int level, CoglBitmap *bmp, CoglError **error) { CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex); + if (level != 0 && atlas_tex->atlas) + _cogl_atlas_texture_migrate_out_of_atlas (atlas_tex); + /* If the texture is in the atlas then we need to copy the edge pixels to the border */ if (atlas_tex->atlas) @@ -602,9 +611,10 @@ _cogl_atlas_texture_set_region (CoglTexture *tex, /* Otherwise we can just forward on to the sub texture */ return cogl_texture_set_region_from_bitmap (atlas_tex->sub_texture, src_x, src_y, - dst_x, dst_y, dst_width, dst_height, bmp, + dst_x, dst_y, + level, error); } diff --git a/cogl/cogl-blit.c b/cogl/cogl-blit.c index 3e738a14..14f22790 100644 --- a/cogl/cogl-blit.c +++ b/cogl/cogl-blit.c @@ -252,10 +252,11 @@ _cogl_blit_copy_tex_sub_image_blit (CoglBlitData *data, int height) { _cogl_texture_2d_copy_from_framebuffer (COGL_TEXTURE_2D (data->dst_tex), + src_x, src_y, + width, height, data->src_fb, dst_x, dst_y, - src_x, src_y, - width, height); + 0); /* level */ } static void @@ -288,14 +289,16 @@ _cogl_blit_get_tex_data_blit (CoglBlitData *data, int height) { CoglError *ignore = NULL; + int rowstride = data->src_width * data->bpp; + int offset = rowstride * src_y + src_x * data->bpp; + cogl_texture_set_region (data->dst_tex, - src_x, src_y, - dst_x, dst_y, width, height, - data->src_width, data->src_height, data->format, - data->src_width * data->bpp, - data->image_data, + rowstride, + data->image_data + offset, + dst_x, dst_y, + 0, /* level */ &ignore); /* TODO: support chaining up errors during the blit */ } diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h index 6bfdcd6b..ba6e0304 100644 --- a/cogl/cogl-driver.h +++ b/cogl/cogl-driver.h @@ -168,13 +168,14 @@ struct _CoglDriverVtable */ void (* texture_2d_copy_from_framebuffer) (CoglTexture2D *tex_2d, - CoglFramebuffer *src_fb, - int dst_x, - int dst_y, int src_x, int src_y, int width, - int height); + int height, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int level); /* If the given texture has a corresponding OpenGL texture handle * then return that. @@ -196,13 +197,14 @@ struct _CoglDriverVtable */ CoglBool (* texture_2d_copy_from_bitmap) (CoglTexture2D *tex_2d, - CoglBitmap *bitmap, - int dst_x, - int dst_y, int src_x, int src_y, int width, int height, + CoglBitmap *bitmap, + int dst_x, + int dst_y, + int level, CoglError **error); /* Reads back the full contents of the given texture and write it to diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl-pipeline-layer-state.c index 5c05d166..e0dd294c 100644 --- a/cogl/cogl-pipeline-layer-state.c +++ b/cogl/cogl-pipeline-layer-state.c @@ -1477,6 +1477,9 @@ cogl_pipeline_set_layer_filters (CoglPipeline *pipeline, _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); + _COGL_RETURN_IF_FAIL (mag_filter == COGL_PIPELINE_FILTER_NEAREST || + mag_filter == COGL_PIPELINE_FILTER_LINEAR); + /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * diff --git a/cogl/cogl-pipeline-layer-state.h b/cogl/cogl-pipeline-layer-state.h index c8e0d0ed..32413265 100644 --- a/cogl/cogl-pipeline-layer-state.h +++ b/cogl/cogl-pipeline-layer-state.h @@ -340,6 +340,11 @@ cogl_pipeline_get_n_layers (CoglPipeline *pipeline); * Changes the decimation and interpolation filters used when a texture is * drawn at other scales than 100%. * + * <note>It is an error to pass anything other than + * %COGL_PIPELINE_FILTER_NEAREST or %COGL_PIPELINE_FILTER_LINEAR as + * magnification filters since magnification doesn't ever need to + * reference values stored in the mipmap chain.</note> + * * Since: 1.10 * Stability: unstable */ diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl-sub-texture.c index fb2cf8ee..915277fd 100644 --- a/cogl/cogl-sub-texture.c +++ b/cogl/cogl-sub-texture.c @@ -374,17 +374,32 @@ _cogl_sub_texture_set_region (CoglTexture *tex, int dst_y, int dst_width, int dst_height, + int level, CoglBitmap *bmp, CoglError **error) { CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + if (level != 0) + { + int full_width = cogl_texture_get_width (sub_tex->full_texture); + int full_height = cogl_texture_get_width (sub_tex->full_texture); + + _COGL_RETURN_VAL_IF_FAIL (sub_tex->sub_x == 0 && + cogl_texture_get_width (tex) == full_width, + FALSE); + _COGL_RETURN_VAL_IF_FAIL (sub_tex->sub_y == 0 && + cogl_texture_get_height (tex) == full_height, + FALSE); + } + return cogl_texture_set_region_from_bitmap (sub_tex->full_texture, src_x, src_y, - dst_x + sub_tex->sub_x, - dst_y + sub_tex->sub_y, dst_width, dst_height, bmp, + dst_x + sub_tex->sub_x, + dst_y + sub_tex->sub_y, + level, error); } diff --git a/cogl/cogl-texture-2d-private.h b/cogl/cogl-texture-2d-private.h index aa5a35e6..39c9f256 100644 --- a/cogl/cogl-texture-2d-private.h +++ b/cogl/cogl-texture-2d-private.h @@ -51,7 +51,7 @@ struct _CoglTexture2D * of driver private state. */ /* The internal format of the GL texture represented as a GL enum */ - GLenum gl_format; + GLenum gl_internal_format; /* The texture object number */ GLuint gl_texture; GLenum gl_legacy_texobj_min_filter; @@ -98,25 +98,27 @@ _cogl_texture_2d_externally_modified (CoglTexture *texture); /* * _cogl_texture_2d_copy_from_framebuffer: * @texture: A #CoglTexture2D pointer - * @src_fb: A source #CoglFramebuffer to copy from - * @dst_x: X-position to store the image within the texture - * @dst_y: Y-position to store the image within the texture * @src_x: X-position to within the framebuffer to read from * @src_y: Y-position to within the framebuffer to read from * @width: width of the rectangle to copy * @height: height of the rectangle to copy + * @src_fb: A source #CoglFramebuffer to copy from + * @dst_x: X-position to store the image within the texture + * @dst_y: Y-position to store the image within the texture + * @level: The mipmap level of @texture to copy too * * This copies a portion of the given @src_fb into the * texture. */ void _cogl_texture_2d_copy_from_framebuffer (CoglTexture2D *texture, - CoglFramebuffer *src_fb, - int dst_x, - int dst_y, int src_x, int src_y, int width, - int height); + int height, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int level); #endif /* __COGL_TEXTURE_2D_PRIVATE_H */ diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c index 29784544..6d1f5307 100644 --- a/cogl/cogl-texture-2d-sliced.c +++ b/cogl/cogl-texture-2d-sliced.c @@ -48,6 +48,7 @@ #include "cogl-pipeline-opengl-private.h" #include "cogl-primitive-texture.h" #include "cogl-error-private.h" +#include "cogl-texture-gl-private.h" #include <string.h> #include <stdlib.h> @@ -238,15 +239,16 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds, if (!cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), 0, /* src_x */ 0, /* src_y */ + x_span->waste, /* width */ + /* height */ + y_iter->intersect_end - + y_iter->intersect_start, + waste_bmp, /* dst_x */ x_span->size - x_span->waste, y_iter->intersect_start - y_span->start, /* dst_y */ - x_span->waste, /* dst_width */ - /* dst_height */ - y_iter->intersect_end - - y_iter->intersect_start, - waste_bmp, + 0, /* level */ error)) { cogl_object_unref (waste_bmp); @@ -298,14 +300,15 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds, if (!cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), 0, /* src_x */ 0, /* src_y */ + copy_width, /* width */ + y_span->waste, /* height */ + waste_bmp, /* dst_x */ x_iter->intersect_start - x_iter->pos, /* dst_y */ y_span->size - y_span->waste, - copy_width, /* dst_width */ - y_span->waste, /* dst_height */ - waste_bmp, + 0, /* level */ error)) { cogl_object_unref (waste_bmp); @@ -359,13 +362,14 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds, if (!cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), x_span->start, /* src x */ y_span->start, /* src y */ - 0, /* dst x */ - 0, /* dst y */ x_span->size - x_span->waste, /* width */ y_span->size - y_span->waste, /* height */ bmp, + 0, /* dst x */ + 0, /* dst y */ + 0, /* level */ error)) { if (waste_buf) @@ -495,11 +499,12 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds, if (!cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex), source_x, source_y, - local_x, /* dst x */ - local_y, /* dst y */ inter_w, /* width */ inter_h, /* height */ source_bmp, + local_x, /* dst x */ + local_y, /* dst y */ + 0, /* level */ error)) { if (waste_buf) @@ -1286,6 +1291,7 @@ _cogl_texture_2d_sliced_set_region (CoglTexture *tex, int dst_y, int dst_width, int dst_height, + int level, CoglBitmap *bmp, CoglError **error) { diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index 853e646f..9df370d4 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -343,24 +343,26 @@ _cogl_texture_2d_externally_modified (CoglTexture *texture) void _cogl_texture_2d_copy_from_framebuffer (CoglTexture2D *tex_2d, - CoglFramebuffer *src_fb, - int dst_x, - int dst_y, int src_x, int src_y, int width, - int height) + int height, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int level) { CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; ctx->driver_vtable->texture_2d_copy_from_framebuffer (tex_2d, - src_fb, - dst_x, - dst_y, src_x, src_y, width, - height); + height, + src_fb, + dst_x, + dst_y, + level); tex_2d->mipmaps_dirty = TRUE; } @@ -479,6 +481,7 @@ _cogl_texture_2d_set_region (CoglTexture *tex, int dst_y, int width, int height, + int level, CoglBitmap *bmp, CoglError **error) { @@ -486,13 +489,14 @@ _cogl_texture_2d_set_region (CoglTexture *tex, CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); if (!ctx->driver_vtable->texture_2d_copy_from_bitmap (tex_2d, - bmp, - dst_x, - dst_y, src_x, src_y, width, height, + bmp, + dst_x, + dst_y, + level, error)) { return FALSE; @@ -530,7 +534,7 @@ _cogl_texture_2d_get_format (CoglTexture *tex) static GLenum _cogl_texture_2d_get_gl_format (CoglTexture *tex) { - return COGL_TEXTURE_2D (tex)->gl_format; + return COGL_TEXTURE_2D (tex)->gl_internal_format; } static int diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c index 0b3fa817..e7a9051b 100644 --- a/cogl/cogl-texture-3d.c +++ b/cogl/cogl-texture-3d.c @@ -31,6 +31,7 @@ #include "cogl-texture-private.h" #include "cogl-texture-3d-private.h" #include "cogl-texture-3d.h" +#include "cogl-texture-gl-private.h" #include "cogl-texture-driver.h" #include "cogl-context-private.h" #include "cogl-object-private.h" @@ -547,17 +548,18 @@ _cogl_texture_3d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) && tex_3d->auto_mipmap && tex_3d->mipmaps_dirty) { - _cogl_bind_gl_texture_transient (GL_TEXTURE_3D, - tex_3d->gl_texture, - FALSE); /* glGenerateMipmap is defined in the FBO extension. If it's not available we'll fallback to temporarily enabling GL_GENERATE_MIPMAP and reuploading the first pixel */ if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) - ctx->texture_driver->gl_generate_mipmaps (ctx, GL_TEXTURE_3D); + _cogl_texture_gl_generate_mipmaps (tex); #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) else if (ctx->driver != COGL_DRIVER_GLES2) { + _cogl_bind_gl_texture_transient (GL_TEXTURE_3D, + tex_3d->gl_texture, + FALSE); + GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_TRUE) ); @@ -596,6 +598,7 @@ _cogl_texture_3d_set_region (CoglTexture *tex, int dst_y, int dst_width, int dst_height, + int level, CoglBitmap *bmp, CoglError **error) { diff --git a/cogl/cogl-texture-driver.h b/cogl/cogl-texture-driver.h index 780f40df..8ab8655d 100644 --- a/cogl/cogl-texture-driver.h +++ b/cogl/cogl-texture-driver.h @@ -65,8 +65,7 @@ struct _CoglTextureDriver */ CoglBool (* upload_subregion_to_gl) (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, + CoglTexture *texture, CoglBool is_foreign, int src_x, int src_y, @@ -74,6 +73,7 @@ struct _CoglTextureDriver int dst_y, int width, int height, + int level, CoglBitmap *source_bmp, GLuint source_gl_format, GLuint source_gl_type, @@ -183,15 +183,6 @@ struct _CoglTextureDriver GLenum gl_target); /* - * glGenerateMipmap semantics may need to be emulated for some - * drivers. E.g. by enabling auto mipmap generation an re-loading a - * number of known texels. - */ - void - (* gl_generate_mipmaps) (CoglContext *ctx, - GLenum texture_target); - - /* * The driver may impose constraints on what formats can be used to store * texture data read from textures. For example GLES currently only supports * RGBA_8888, and so we need to manually convert the data if the final diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h index 1619277a..a41d06c1 100644 --- a/cogl/cogl-texture-private.h +++ b/cogl/cogl-texture-private.h @@ -72,6 +72,7 @@ struct _CoglTextureVtable int dst_y, int dst_width, int dst_height, + int level, CoglBitmap *bitmap, CoglError **error); @@ -142,6 +143,7 @@ struct _CoglTexture CoglObject _parent; CoglContext *context; GList *framebuffers; + int max_level; const CoglTextureVtable *vtable; }; @@ -280,4 +282,14 @@ CoglBool _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format, CoglPixelFormat dst_format); +int +_cogl_texture_get_n_levels (CoglTexture *texture); + +void +_cogl_texture_get_level_size (CoglTexture *texture, + int level, + int *width, + int *height, + int *depth); + #endif /* __COGL_TEXTURE_PRIVATE_H */ diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c index e8bb965f..28dcd575 100644 --- a/cogl/cogl-texture-rectangle.c +++ b/cogl/cogl-texture-rectangle.c @@ -554,10 +554,10 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex, int dst_y, int dst_width, int dst_height, + int level, CoglBitmap *bmp, CoglError **error) { - CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex); GLenum gl_format; GLenum gl_type; CoglContext *ctx = tex->context; @@ -576,12 +576,12 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex, /* Send data to GL */ status = ctx->texture_driver->upload_subregion_to_gl (ctx, - GL_TEXTURE_RECTANGLE_ARB, - tex_rect->gl_texture, + tex, FALSE, src_x, src_y, dst_x, dst_y, dst_width, dst_height, + level, bmp, gl_format, gl_type, diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index 794c53a3..1c9da68c 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -43,6 +43,7 @@ #include "cogl-texture-2d-sliced-private.h" #include "cogl-texture-2d-private.h" #include "cogl-texture-2d-gl.h" +#include "cogl-texture-3d-private.h" #include "cogl-texture-rectangle-private.h" #include "cogl-sub-texture-private.h" #include "cogl-atlas-texture-private.h" @@ -103,6 +104,7 @@ _cogl_texture_init (CoglTexture *texture, const CoglTextureVtable *vtable) { texture->context = context; + texture->max_level = 0; texture->vtable = vtable; texture->framebuffers = NULL; } @@ -271,6 +273,61 @@ cogl_texture_get_max_waste (CoglTexture *texture) return texture->vtable->get_max_waste (texture); } +int +_cogl_texture_get_n_levels (CoglTexture *texture) +{ + int width = cogl_texture_get_width (texture); + int height = cogl_texture_get_height (texture); + int max_dimension = MAX (width, height); + + if (cogl_is_texture_3d (texture)) + { + CoglTexture3D *tex_3d = COGL_TEXTURE_3D (texture); + max_dimension = MAX (max_dimension, tex_3d->depth); + } + + return _cogl_util_fls (max_dimension); +} + +void +_cogl_texture_get_level_size (CoglTexture *texture, + int level, + int *width, + int *height, + int *depth) +{ + int current_width = cogl_texture_get_width (texture); + int current_height = cogl_texture_get_height (texture); + int current_depth; + int i; + + if (cogl_is_texture_3d (texture)) + { + CoglTexture3D *tex_3d = COGL_TEXTURE_3D (texture); + current_depth = tex_3d->depth; + } + else + current_depth = 0; + + /* NB: The OpenGL spec (like D3D) uses a floor() convention to + * round down the size of a mipmap level when dividing the size + * of the previous level results in a fraction... + */ + for (i = 0; i < level; i++) + { + current_width = MAX (1, current_width >> 1); + current_height = MAX (1, current_height >> 1); + current_depth = MAX (1, current_depth >> 1); + } + + if (width) + *width = current_width; + if (height) + *height = current_height; + if (depth) + *depth = current_depth; +} + CoglBool cogl_texture_is_sliced (CoglTexture *texture) { @@ -342,22 +399,21 @@ CoglBool cogl_texture_set_region_from_bitmap (CoglTexture *texture, int src_x, int src_y, + int width, + int height, + CoglBitmap *bmp, int dst_x, int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bmp, + int level, CoglError **error) { - CoglBool ret; - _COGL_RETURN_VAL_IF_FAIL ((cogl_bitmap_get_width (bmp) - src_x) - >= dst_width, FALSE); + >= width, FALSE); _COGL_RETURN_VAL_IF_FAIL ((cogl_bitmap_get_height (bmp) - src_y) - >= dst_height, FALSE); + >= height, FALSE); /* Shortcut out early if the image is empty */ - if (dst_width == 0 || dst_height == 0) + if (width == 0 || height == 0) return TRUE; /* Note that we don't prepare the bitmap for upload here because @@ -367,41 +423,32 @@ cogl_texture_set_region_from_bitmap (CoglTexture *texture, always stored in an RGBA texture even if the texture format is advertised as RGB. */ - ret = texture->vtable->set_region (texture, - src_x, src_y, - dst_x, dst_y, - dst_width, dst_height, - bmp, - error); - - return ret; + return texture->vtable->set_region (texture, + src_x, src_y, + dst_x, dst_y, + width, height, + level, + bmp, + error); } CoglBool cogl_texture_set_region (CoglTexture *texture, - int src_x, - int src_y, + int width, + int height, + CoglPixelFormat format, + int rowstride, + const uint8_t *data, int dst_x, int dst_y, - unsigned int dst_width, - unsigned int dst_height, - int width, - int height, - CoglPixelFormat format, - unsigned int rowstride, - const uint8_t *data, + int level, CoglError **error) { CoglContext *ctx = texture->context; CoglBitmap *source_bmp; CoglBool ret; - _COGL_RETURN_VAL_IF_FAIL ((width - src_x) >= dst_width, FALSE); - _COGL_RETURN_VAL_IF_FAIL ((height - src_y) >= dst_height, FALSE); - - /* Check for valid format */ - if (format == COGL_PIXEL_FORMAT_ANY) - return FALSE; + _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, FALSE); /* Rowstride from width if none specified */ if (rowstride == 0) @@ -415,10 +462,11 @@ cogl_texture_set_region (CoglTexture *texture, (uint8_t *) data); ret = cogl_texture_set_region_from_bitmap (texture, - src_x, src_y, - dst_x, dst_y, - dst_width, dst_height, + 0, 0, + width, height, source_bmp, + dst_x, dst_y, + level, error); cogl_object_unref (source_bmp); diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h index 77a269b3..0b5475f6 100644 --- a/cogl/cogl-texture.h +++ b/cogl/cogl-texture.h @@ -401,64 +401,111 @@ cogl_texture_draw_and_read_to_bitmap (CoglTexture *texture, /** * cogl_texture_set_region: * @texture a #CoglTexture. - * @src_x: upper left coordinate to use from source data. - * @src_y: upper left coordinate to use from source data. - * @dst_x: upper left destination horizontal coordinate. - * @dst_y: upper left destination vertical coordinate. - * @dst_width: width of destination region to write. (Must be less - * than or equal to @width) - * @dst_height: height of destination region to write. (Must be less - * than or equal to @height) - * @width: width of source data buffer. - * @height: height of source data buffer. - * @format: the #CoglPixelFormat used in the source buffer. - * @rowstride: rowstride of source buffer (computed from width if none - * specified) - * @data: the actual pixel data. + * @width: width of the region to set. + * @height: height of the region to set. + * @format: the #CoglPixelFormat used in the source @data buffer. + * @rowstride: rowstride in bytes of the source @data buffer (computed + * from @width and @format if it equals 0) + * @data: the source data, pointing to the first top-left pixel to set + * @dst_x: upper left destination x coordinate. + * @dst_y: upper left destination y coordinate. + * @level: The mipmap level to update (Normally 0 for the largest, + * base image) * @error: A #CoglError to return exceptional errors * - * Sets the pixels in a rectangular subregion of @texture from an in-memory - * buffer containing pixel data. + * Sets the pixels in a rectangular subregion of @texture from an + * in-memory buffer containing pixel @data. * - * <note>The region set can't be larger than the source @data</note> + * @data should point to the first pixel to copy corresponding + * to the top left of the region being set. + * + * The rowstride determines how many bytes between the first pixel of + * a row of @data and the first pixel of the next row. If @rowstride + * equals 0 then it will be automatically calculated from @width and + * the bytes-per-pixel for the given @format. + * + * A mipmap @level of 0 corresponds to the largest, base image of a + * texture and @level 1 is half the width and height of level 0. The + * size of any level can be calculated from the size of the base + * level as follows: + * + * |[ + * width = MAX (1, floor (base_width / 2 ^ level)); + * height = MAX (1, floor (base_height / 2 ^ level)); + * ]| + * + * Or more succinctly put using C: + * + * |[ + * width = MAX (1, base_width >> level); + * height = MAX (1, base_height >> level); + * ]| + * + * You can get the size of the base level using + * cogl_texture_get_width() and cogl_texture_get_height(). + * + * You can determine the number of mipmap levels for a given texture + * like this: + * + * |[ + * n_levels = 1 + floor (log2 (max_dimension)); + * ]| + * + * Or more succinctly in C using the fls() - "Find Last Set" - function: + * + * |[ + * n_levels = fls (max_dimension); + * ]| + + * Where %max_dimension is the larger of cogl_texture_get_width() and + * cogl_texture_get_height(). + * + * It is an error to pass a @level number >= the number of levels that + * @texture can have according to the above calculation. + * + * <note>Since the storage for a #CoglTexture is allocated lazily then + * if the given @texture has not previously been allocated then this + * api can return %FALSE and throw an exceptional @error if there is + * not enough memory to allocate storage for @texture.</note> * * Return value: %TRUE if the subregion upload was successful, and * %FALSE otherwise */ CoglBool cogl_texture_set_region (CoglTexture *texture, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int dst_width, - unsigned int dst_height, int width, int height, CoglPixelFormat format, - unsigned int rowstride, + int rowstride, const uint8_t *data, + int dst_x, + int dst_y, + int level, CoglError **error); /** * cogl_texture_set_region_from_bitmap: * @texture a #CoglTexture pointer - * @src_x: upper left coordinate to use from the source bitmap. - * @src_y: upper left coordinate to use from the source bitmap - * @dst_x: upper left destination horizontal coordinate. - * @dst_y: upper left destination vertical coordinate. - * @dst_width: width of destination region to write. (Must be less - * than or equal to the bitmap width) - * @dst_height: height of destination region to write. (Must be less - * than or equal to the bitmap height) - * @bitmap: The source bitmap to read from - * @error: A #CoglError to return exceptional errors - * - * Copies a specified source region from @bitmap to the position - * (@src_x, @src_y) of the given destination texture @handle. - * - * <note>The region updated can't be larger than the source - * bitmap</note> + * @src_x: upper left x coordinate of the region in the source bitmap. + * @src_y: upper left y coordinate of the region in the source bitmap + * @width: width of the region to copy. (Must be less than or equal to + * the bitmap width) + * @height: height of the region to copy. (Must be less than or equal + * to the bitmap height) + * @bitmap: The source bitmap to copy from + * @dst_x: upper left destination x coordinate to copy to. + * @dst_y: upper left destination y coordinate to copy to. + * @error: A #CoglError to return exceptional errors or %NULL + * + * Copies a rectangular region from @bitmap to the position + * (@dst_x, @dst_y) of the given destination @texture. + * + * The source region's top left coordinate is (@src_x, @src_y) within + * the source @bitmap and the region is @width pixels wide and @height + * pixels high. + * + * <note>The source region must not extend outside the bounds of the + * source @bitmap.</note> * * Return value: %TRUE if the subregion upload was successful, and * %FALSE otherwise @@ -470,11 +517,12 @@ CoglBool cogl_texture_set_region_from_bitmap (CoglTexture *texture, int src_x, int src_y, + int width, + int height, + CoglBitmap *bitmap, int dst_x, int dst_y, - unsigned int dst_width, - unsigned int dst_height, - CoglBitmap *bitmap, + int level, CoglError **error); COGL_END_DECLS diff --git a/cogl/cogl-util.h b/cogl/cogl-util.h index 1f3d2663..6e02ad7d 100644 --- a/cogl/cogl-util.h +++ b/cogl/cogl-util.h @@ -124,6 +124,7 @@ _cogl_util_one_at_a_time_mix (unsigned int hash); #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) #define COGL_UTIL_HAVE_BUILTIN_FFSL #define COGL_UTIL_HAVE_BUILTIN_POPCOUNTL +#define COGL_UTIL_HAVE_BUILTIN_CLZ #endif /* The 'ffs' function is part of C99 so it isn't always available */ @@ -148,6 +149,24 @@ int _cogl_util_ffsl_wrapper (long int num); #endif /* COGL_UTIL_HAVE_BUILTIN_FFSL */ +static inline unsigned int +_cogl_util_fls (unsigned int n) +{ +#ifdef COGL_UTIL_HAVE_BUILTIN_CLZ + return n == 0 ? 0 : sizeof (unsigned int) * 8 - __builtin_clz (n); +#else + unsigned int v = 1; + + if (n == 0) + return 0; + + while (n >>= 1) + v++; + + return v; +#endif +} + #ifdef COGL_UTIL_HAVE_BUILTIN_POPCOUNTL #define _cogl_util_popcountl __builtin_popcountl #else diff --git a/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/driver/gl/cogl-texture-2d-gl-private.h index ac0c89f0..d77f460e 100644 --- a/cogl/driver/gl/cogl-texture-2d-gl-private.h +++ b/cogl/driver/gl/cogl-texture-2d-gl-private.h @@ -79,13 +79,14 @@ _cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, void _cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d, - CoglFramebuffer *src_fb, - int dst_x, - int dst_y, int src_x, int src_y, int width, - int height); + int height, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int level); unsigned int _cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d); @@ -95,13 +96,14 @@ _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d); CoglBool _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, - CoglBitmap *bitmap, - int dst_x, - int dst_y, int src_x, int src_y, int width, int height, + CoglBitmap *bitmap, + int dst_x, + int dst_y, + int level, CoglError **error); void diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c index dd084016..dadbc192 100644 --- a/cogl/driver/gl/cogl-texture-2d-gl.c +++ b/cogl/driver/gl/cogl-texture-2d-gl.c @@ -35,6 +35,7 @@ #include "cogl-texture-2d-gl.h" #include "cogl-texture-2d-gl-private.h" #include "cogl-texture-2d-private.h" +#include "cogl-texture-gl-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-error-private.h" #include "cogl-util-gl-private.h" @@ -112,6 +113,9 @@ _cogl_texture_2d_gl_new_with_size (CoglContext *ctx, tex_2d->gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); + + tex_2d->gl_internal_format = gl_intformat; + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, tex_2d->is_foreign); @@ -205,7 +209,7 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp, return NULL; } - tex_2d->gl_format = gl_intformat; + tex_2d->gl_internal_format = gl_intformat; cogl_object_unref (dst_bmp); @@ -441,7 +445,7 @@ cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx, tex_2d->format = format; tex_2d->gl_texture = gl_handle; - tex_2d->gl_format = gl_int_format; + tex_2d->gl_internal_format = gl_int_format; /* Unknown filter */ tex_2d->gl_legacy_texobj_min_filter = GL_FALSE; @@ -452,13 +456,14 @@ cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx, void _cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d, - CoglFramebuffer *src_fb, - int dst_x, - int dst_y, int src_x, int src_y, int width, - int height) + int height, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int level) { CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; @@ -492,18 +497,18 @@ _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d) { CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture, - tex_2d->is_foreign); - /* glGenerateMipmap is defined in the FBO extension. If it's not available we'll fallback to temporarily enabling GL_GENERATE_MIPMAP and reuploading the first pixel */ if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) - ctx->texture_driver->gl_generate_mipmaps (ctx, GL_TEXTURE_2D); + _cogl_texture_gl_generate_mipmaps (COGL_TEXTURE (tex_2d)); #if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL) else { + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + tex_2d->gl_texture, + tex_2d->is_foreign); + GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE) ); @@ -520,13 +525,14 @@ _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d) CoglBool _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, - CoglBitmap *bmp, - int dst_x, - int dst_y, int src_x, int src_y, int width, int height, + CoglBitmap *bmp, + int dst_x, + int dst_y, + int level, CoglError **error) { CoglTexture *tex = COGL_TEXTURE (tex_2d); @@ -574,14 +580,13 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, } } - /* Send data to GL */ status = ctx->texture_driver->upload_subregion_to_gl (ctx, - GL_TEXTURE_2D, - tex_2d->gl_texture, + tex, FALSE, src_x, src_y, dst_x, dst_y, width, height, + level, bmp, gl_format, gl_type, @@ -589,6 +594,8 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, cogl_object_unref (bmp); + _cogl_texture_gl_maybe_update_max_level (tex, level); + return status; } diff --git a/cogl/driver/gl/cogl-texture-gl-private.h b/cogl/driver/gl/cogl-texture-gl-private.h index b44861c9..4ed671b4 100644 --- a/cogl/driver/gl/cogl-texture-gl-private.h +++ b/cogl/driver/gl/cogl-texture-gl-private.h @@ -46,4 +46,11 @@ _cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture, unsigned int min_filter, unsigned int mag_filter); +void +_cogl_texture_gl_maybe_update_max_level (CoglTexture *texture, + int max_level); + +void +_cogl_texture_gl_generate_mipmaps (CoglTexture *texture); + #endif /* _COGL_TEXTURE_GL_PRIVATE_H_ */ diff --git a/cogl/driver/gl/cogl-texture-gl.c b/cogl/driver/gl/cogl-texture-gl.c index a9f0d32b..7572fcbb 100644 --- a/cogl/driver/gl/cogl-texture-gl.c +++ b/cogl/driver/gl/cogl-texture-gl.c @@ -29,7 +29,9 @@ #include "cogl-internal.h" #include "cogl-context-private.h" #include "cogl-texture-gl-private.h" +#include "cogl-texture-3d-private.h" #include "cogl-util.h" +#include "cogl-pipeline-opengl-private.h" static inline int calculate_alignment (int rowstride) @@ -92,3 +94,44 @@ _cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture, texture->vtable->gl_flush_legacy_texobj_filters (texture, min_filter, mag_filter); } + +void +_cogl_texture_gl_maybe_update_max_level (CoglTexture *texture, + int max_level) +{ + if (texture->max_level < max_level) + { + CoglContext *ctx = texture->context; + GLuint gl_handle; + GLenum gl_target; + + cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); + + texture->max_level = max_level; + + _cogl_bind_gl_texture_transient (gl_target, + gl_handle, + _cogl_texture_is_foreign (texture)); + + GE( ctx, glTexParameteri (gl_target, + GL_TEXTURE_MAX_LEVEL, texture->max_level)); + } +} + +void +_cogl_texture_gl_generate_mipmaps (CoglTexture *texture) +{ + CoglContext *ctx = texture->context; + int n_levels = _cogl_texture_get_n_levels (texture); + GLuint gl_handle; + GLenum gl_target; + + _cogl_texture_gl_maybe_update_max_level (texture, n_levels - 1); + + cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); + + _cogl_bind_gl_texture_transient (gl_target, + gl_handle, + _cogl_texture_is_foreign (texture)); + GE( ctx, glGenerateMipmap (gl_target) ); +} diff --git a/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/driver/gl/gl/cogl-texture-driver-gl.c index 1f0e4136..4941549c 100644 --- a/cogl/driver/gl/gl/cogl-texture-driver-gl.c +++ b/cogl/driver/gl/gl/cogl-texture-driver-gl.c @@ -66,6 +66,14 @@ _cogl_texture_driver_gen (CoglContext *ctx, { case GL_TEXTURE_2D: case GL_TEXTURE_3D: + /* In case automatic mipmap generation gets disabled for this + * texture but a minification filter depending on mipmap + * interpolation is selected then we initialize the max mipmap + * level to 0 so OpenGL will consider the texture storage to be + * "complete". + */ + GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MAX_LEVEL, 0)); + /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */ GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MIN_FILTER, @@ -169,8 +177,7 @@ _cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx, static CoglBool _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, + CoglTexture *texture, CoglBool is_foreign, int src_x, int src_y, @@ -178,17 +185,24 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, int dst_y, int width, int height, + int level, CoglBitmap *source_bmp, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { + GLenum gl_target; + GLuint gl_handle; uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); GLenum gl_error; CoglBool status = TRUE; CoglError *internal_error = NULL; + int level_width; + int level_height; + + cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error); @@ -215,12 +229,58 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) ; - ctx->glTexSubImage2D (gl_target, 0, - dst_x, dst_y, - width, height, - source_gl_format, - source_gl_type, - data); + _cogl_texture_get_level_size (texture, + level, + &level_width, + &level_height, + NULL); + + if (level_width == width && level_height == height) + { + /* GL gets upset if you use glTexSubImage2D to initialize the + * contents of a mipmap level so we make sure to use + * glTexImage2D if we are uploading a full mipmap level. + */ + ctx->glTexImage2D (gl_target, + level, + _cogl_texture_get_gl_format (texture), + width, + height, + 0, + source_gl_format, + source_gl_type, + data); + + } + else + { + /* GL gets upset if you use glTexSubImage2D to initialize the + * contents of a mipmap level so if this is the first time + * we've seen a request to upload to this level we call + * glTexImage2D first to assert that the storage for this + * level exists. + */ + if (texture->max_level < level) + { + ctx->glTexImage2D (gl_target, + level, + _cogl_texture_get_gl_format (texture), + level_width, + level_height, + 0, + source_gl_format, + source_gl_type, + NULL); + } + + ctx->glTexSubImage2D (gl_target, + level, + dst_x, dst_y, + width, height, + source_gl_format, + source_gl_type, + data); + } if (_cogl_gl_util_catch_out_of_memory (ctx, error)) status = FALSE; @@ -441,13 +501,6 @@ _cogl_texture_driver_allows_foreign_gl_target (CoglContext *ctx, return TRUE; } -static void -_cogl_texture_driver_gl_generate_mipmaps (CoglContext *ctx, - GLenum gl_target) -{ - GE( ctx, glGenerateMipmap (gl_target) ); -} - static CoglPixelFormat _cogl_texture_driver_find_best_gl_get_data_format (CoglContext *context, @@ -476,6 +529,5 @@ _cogl_texture_driver_gl = _cogl_texture_driver_size_supported_3d, _cogl_texture_driver_try_setting_gl_border_color, _cogl_texture_driver_allows_foreign_gl_target, - _cogl_texture_driver_gl_generate_mipmaps, _cogl_texture_driver_find_best_gl_get_data_format }; diff --git a/cogl/driver/gl/gles/cogl-texture-driver-gles.c b/cogl/driver/gl/gles/cogl-texture-driver-gles.c index 360d46a8..ed7e92bc 100644 --- a/cogl/driver/gl/gles/cogl-texture-driver-gles.c +++ b/cogl/driver/gl/gles/cogl-texture-driver-gles.c @@ -81,6 +81,14 @@ _cogl_texture_driver_gen (CoglContext *ctx, { case GL_TEXTURE_2D: case GL_TEXTURE_3D: + /* In case automatic mipmap generation gets disabled for this + * texture but a minification filter depending on mipmap + * interpolation is selected then we initialize the max mipmap + * level to 0 so OpenGL will consider the texture storage to be + * "complete". + */ + GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MAX_LEVEL, 0)); + /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */ GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MIN_FILTER, @@ -172,8 +180,7 @@ prepare_bitmap_alignment_for_upload (CoglContext *ctx, static CoglBool _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, + CoglTexture *texture, CoglBool is_foreign, int src_x, int src_y, @@ -181,11 +188,14 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, int dst_y, int width, int height, + int level, CoglBitmap *source_bmp, GLuint source_gl_format, GLuint source_gl_type, CoglError **error) { + GLenum gl_target; + GLuint gl_handle; uint8_t *data; CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); @@ -194,6 +204,10 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, GLenum gl_error; CoglBool status = TRUE; CoglError *internal_error = NULL; + int level_width; + int level_height; + + cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); /* If we have the GL_EXT_unpack_subimage extension then we can upload from subregions directly. Otherwise we may need to copy @@ -254,12 +268,57 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) ; - ctx->glTexSubImage2D (gl_target, 0, - dst_x, dst_y, - width, height, - source_gl_format, - source_gl_type, - data); + _cogl_texture_get_level_size (texture, + level, + &level_width, + &level_height, + NULL); + + if (level_width == width && level_height == height) + { + /* GL gets upset if you use glTexSubImage2D to define the + * contents of a mipmap level so we make sure to use + * glTexImage2D if we are uploading a full mipmap level. + */ + ctx->glTexImage2D (gl_target, + level, + _cogl_texture_get_gl_format (texture), + width, + height, + 0, + source_gl_format, + source_gl_type, + data); + } + else + { + /* GL gets upset if you use glTexSubImage2D to initialize the + * contents of a mipmap level so if this is the first time + * we've seen a request to upload to this level we call + * glTexImage2D first to assert that the storage for this + * level exists. + */ + if (texture->max_level < level) + { + ctx->glTexImage2D (gl_target, + level, + _cogl_texture_get_gl_format (texture), + level_width, + level_height, + 0, + source_gl_format, + source_gl_type, + NULL); + } + + ctx->glTexSubImage2D (gl_target, + level, + dst_x, dst_y, + width, height, + source_gl_format, + source_gl_type, + data); + } if (_cogl_gl_util_catch_out_of_memory (ctx, error)) status = FALSE; @@ -551,14 +610,6 @@ _cogl_texture_driver_allows_foreign_gl_target (CoglContext *ctx, return TRUE; } -static void -_cogl_texture_driver_gl_generate_mipmaps (CoglContext *ctx, - GLenum gl_target) -{ - if (ctx->driver == COGL_DRIVER_GLES2) - GE( ctx, glGenerateMipmap (gl_target) ); -} - static CoglPixelFormat _cogl_texture_driver_find_best_gl_get_data_format (CoglContext *context, @@ -588,6 +639,5 @@ _cogl_texture_driver_gles = _cogl_texture_driver_size_supported_3d, _cogl_texture_driver_try_setting_gl_border_color, _cogl_texture_driver_allows_foreign_gl_target, - _cogl_texture_driver_gl_generate_mipmaps, _cogl_texture_driver_find_best_gl_get_data_format }; diff --git a/cogl/driver/nop/cogl-texture-2d-nop-private.h b/cogl/driver/nop/cogl-texture-2d-nop-private.h index 957a1944..2e79e667 100644 --- a/cogl/driver/nop/cogl-texture-2d-nop-private.h +++ b/cogl/driver/nop/cogl-texture-2d-nop-private.h @@ -79,13 +79,14 @@ _cogl_texture_2d_nop_flush_legacy_texobj_wrap_modes (CoglTexture *tex, void _cogl_texture_2d_nop_copy_from_framebuffer (CoglTexture2D *tex_2d, - CoglFramebuffer *src_fb, - int dst_x, - int dst_y, int src_x, int src_y, int width, - int height); + int height, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int level); unsigned int _cogl_texture_2d_nop_get_gl_handle (CoglTexture2D *tex_2d); @@ -95,13 +96,14 @@ _cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d); CoglBool _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d, - CoglBitmap *bitmap, - int dst_x, - int dst_y, int src_x, int src_y, int width, int height, + CoglBitmap *bitmap, + int dst_x, + int dst_y, + int level, CoglError **error); void diff --git a/cogl/driver/nop/cogl-texture-2d-nop.c b/cogl/driver/nop/cogl-texture-2d-nop.c index 5118e26d..948d6209 100644 --- a/cogl/driver/nop/cogl-texture-2d-nop.c +++ b/cogl/driver/nop/cogl-texture-2d-nop.c @@ -114,13 +114,14 @@ _cogl_texture_2d_nop_flush_legacy_texobj_wrap_modes (CoglTexture *tex, void _cogl_texture_2d_nop_copy_from_framebuffer (CoglTexture2D *tex_2d, - CoglFramebuffer *src_fb, - int dst_x, - int dst_y, int src_x, int src_y, int width, - int height) + int height, + CoglFramebuffer *src_fb, + int dst_x, + int dst_y, + int level) { } @@ -137,13 +138,14 @@ _cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d) CoglBool _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d, - CoglBitmap *bitmap, - int dst_x, - int dst_y, int src_x, int src_y, int width, int height, + CoglBitmap *bitmap, + int dst_x, + int dst_y, + int level, CoglError **error) { return TRUE; diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c index 4f642375..f5b31692 100644 --- a/cogl/winsys/cogl-texture-pixmap-x11.c +++ b/cogl/winsys/cogl-texture-pixmap-x11.c @@ -49,6 +49,7 @@ #include "cogl-xlib.h" #include "cogl-error-private.h" #include "cogl-texture-gl-private.h" +#include "cogl-private.h" #include <X11/Xlib.h> #include <X11/Xutil.h> @@ -481,6 +482,8 @@ _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap) XImage *image; int src_x, src_y; int x, y, width, height; + int bpp; + int offset; CoglError *ignore = NULL; display = cogl_xlib_get_display (); @@ -589,14 +592,17 @@ _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap) image->bits_per_pixel, image->byte_order == LSBFirst); + bpp = _cogl_pixel_format_get_bytes_per_pixel (image_format); + offset = image->bytes_per_line * src_y + bpp * src_x; + cogl_texture_set_region (tex_pixmap->tex, - src_x, src_y, - x, y, width, height, - image->width, - image->height, + width, + height, image_format, image->bytes_per_line, - (const uint8_t *) image->data, + ((const uint8_t *) image->data) + offset, + x, y, + 0, /* level */ &ignore); /* If we have a shared memory segment then the XImage would be a @@ -690,6 +696,7 @@ _cogl_texture_pixmap_x11_set_region (CoglTexture *tex, int dst_y, int dst_width, int dst_height, + int level, CoglBitmap *bmp, CoglError **error) { diff --git a/tests/conform/test-alpha-textures.c b/tests/conform/test-alpha-textures.c index 1861536f..659815c8 100644 --- a/tests/conform/test-alpha-textures.c +++ b/tests/conform/test-alpha-textures.c @@ -64,13 +64,12 @@ test_alpha_textures (void) create_pipeline (&tex2, &pipeline2); cogl_texture_set_region (tex2, - 0, 0, /* src_x/y */ - 1, 1, /* dst_x/y */ - 1, 1, /* dst_width / dst_height */ 1, 1, /* width / height */ COGL_PIXEL_FORMAT_A_8, 1, /* rowstride */ replacement_data, + 1, 1, /* dst_x/y */ + 0, /* level */ NULL); /* abort on error */ cogl_framebuffer_draw_rectangle (test_fb, diff --git a/tests/conform/test-premult.c b/tests/conform/test-premult.c index 32983b75..a960409a 100644 --- a/tests/conform/test-premult.c +++ b/tests/conform/test-premult.c @@ -68,13 +68,12 @@ set_region (CoglTexture *tex, guchar *tex_data = gen_tex_data (color); cogl_texture_set_region (tex, - 0, 0, /* src x, y */ - 0, 0, /* dst x, y */ - QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */ - QUAD_WIDTH, QUAD_WIDTH, /* src width, height */ + QUAD_WIDTH, QUAD_WIDTH, /* height */ format, 0, /* auto compute row stride */ tex_data, + 0, 0, /* dst x,y */ + 0, /* level */ NULL); /* don't catch errors */ } diff --git a/tests/conform/test-sub-texture.c b/tests/conform/test-sub-texture.c index 58585562..e81f7b1c 100644 --- a/tests/conform/test-sub-texture.c +++ b/tests/conform/test-sub-texture.c @@ -266,10 +266,14 @@ validate_result (TestState *state) /* Update the center half of the sub texture */ texture_data = create_update_data (); cogl_texture_set_region (COGL_TEXTURE (sub_texture), - 0, 0, 32, 32, 64, 64, 256, 256, - COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4, + 64, 64, + COGL_PIXEL_FORMAT_RGBA_8888_PRE, + 256 * 4, texture_data, + 32, 32, /* dst x, y */ + 0, /* level */ NULL); /* don't catch errors */ + g_free (texture_data); cogl_object_unref (sub_texture); /* Get the texture data */ diff --git a/tests/conform/test-write-texture-formats.c b/tests/conform/test-write-texture-formats.c index 80002f1b..87450147 100644 --- a/tests/conform/test-write-texture-formats.c +++ b/tests/conform/test-write-texture-formats.c @@ -38,13 +38,12 @@ test_write_byte (CoglPixelFormat format, CoglTexture *texture = test_utils_create_color_texture (test_ctx, 0); cogl_texture_set_region (texture, - 0, 0, /* src_x / src_y */ - 0, 0, /* dst_x / dst_y */ - 1, 1, /* dst_w / dst_h */ 1, 1, /* width / height */ format, 1, /* rowstride */ &byte, + 0, 0, /* dst_x, dst_y */ + 0, /* level */ NULL); /* don't catch errors */ test_color (texture, expected_pixel); @@ -60,13 +59,12 @@ test_write_short (CoglPixelFormat format, CoglTexture *texture = test_utils_create_color_texture (test_ctx, 0); cogl_texture_set_region (texture, - 0, 0, /* src_x / src_y */ - 0, 0, /* dst_x / dst_y */ - 1, 1, /* dst_w / dst_h */ 1, 1, /* width / height */ format, 2, /* rowstride */ (uint8_t *) &value, + 0, 0, /* dst_x, dst_y */ + 0, /* level */ NULL); /* don't catch errors */ test_color (texture, expected_pixel); @@ -84,13 +82,12 @@ test_write_bytes (CoglPixelFormat format, value = GUINT32_TO_BE (value); cogl_texture_set_region (texture, - 0, 0, /* src_x / src_y */ - 0, 0, /* dst_x / dst_y */ - 1, 1, /* dst_w / dst_h */ 1, 1, /* width / height */ format, 4, /* rowstride */ (uint8_t *) &value, + 0, 0, /* dst_x, dst_y */ + 0, /* level */ NULL); /* don't catch errors */ test_color (texture, expected_pixel); @@ -124,13 +121,12 @@ test_write_int (CoglPixelFormat format, va_end (ap); cogl_texture_set_region (texture, - 0, 0, /* src_x / src_y */ - 0, 0, /* dst_x / dst_y */ - 1, 1, /* dst_w / dst_h */ 1, 1, /* width / height */ format, 4, /* rowstride */ (uint8_t *) &tex_data, + 0, 0, /* dst_x, dst_y */ + 0, /* level */ NULL); /* don't catch errors */ test_color (texture, expected_pixel); |