diff options
-rw-r--r-- | src/mesa/drivers/common/meta.h | 2 | ||||
-rw-r--r-- | src/mesa/drivers/common/meta_copy_image.c | 103 | ||||
-rw-r--r-- | src/mesa/drivers/dri/i965/intel_copy_image.c | 80 | ||||
-rw-r--r-- | src/mesa/main/copyimage.c | 301 | ||||
-rw-r--r-- | src/mesa/main/dd.h | 15 | ||||
-rw-r--r-- | src/mesa/state_tracker/st_cb_texture.c | 33 |
6 files changed, 363 insertions, 171 deletions
diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h index fe439153aa0..23fa209905d 100644 --- a/src/mesa/drivers/common/meta.h +++ b/src/mesa/drivers/common/meta.h @@ -494,8 +494,10 @@ _mesa_meta_and_swrast_BlitFramebuffer(struct gl_context *ctx, bool _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx, struct gl_texture_image *src_tex_image, + struct gl_renderbuffer *src_renderbuffer, int src_x, int src_y, int src_z, struct gl_texture_image *dst_tex_image, + struct gl_renderbuffer *dst_renderbuffer, int dst_x, int dst_y, int dst_z, int src_width, int src_height); diff --git a/src/mesa/drivers/common/meta_copy_image.c b/src/mesa/drivers/common/meta_copy_image.c index 149ed18503c..33490ee6615 100644 --- a/src/mesa/drivers/common/meta_copy_image.c +++ b/src/mesa/drivers/common/meta_copy_image.c @@ -35,6 +35,46 @@ #include "mtypes.h" #include "meta.h" +/** + * Create a texture image that wraps a renderbuffer. + */ +static struct gl_texture_image * +wrap_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) +{ + GLenum texTarget; + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + + if (rb->NumSamples > 1) + texTarget = GL_TEXTURE_2D_MULTISAMPLE; + else + texTarget = GL_TEXTURE_2D; + + /* Texture ID is not significant since it never goes into the hash table */ + texObj = ctx->Driver.NewTextureObject(ctx, 0, texTarget); + assert(texObj); + if (!texObj) + return NULL; + + texImage = _mesa_get_tex_image(ctx, texObj, texTarget, 0); + assert(texImage); + if (!texImage) + return NULL; + + if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) { + _mesa_problem(ctx, "Failed to create texture from renderbuffer"); + return NULL; + } + + if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) { + rb->NeedsFinishRenderTexture = true; + ctx->Driver.FinishRenderTexture(ctx, rb); + } + + return texImage; +} + + /* This function makes a texture view without bothering with all of the API * checks. Most of them are the same for CopyTexSubImage so checking would * be redundant. The one major difference is that we don't check for @@ -112,11 +152,15 @@ make_view(struct gl_context *ctx, struct gl_texture_image *tex_image, bool _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx, struct gl_texture_image *src_tex_image, + struct gl_renderbuffer *src_renderbuffer, int src_x, int src_y, int src_z, struct gl_texture_image *dst_tex_image, + struct gl_renderbuffer *dst_renderbuffer, int dst_x, int dst_y, int dst_z, int src_width, int src_height) { + mesa_format src_format, dst_format; + GLint src_internal_format, dst_internal_format; GLuint src_view_texture = 0; struct gl_texture_image *src_view_tex_image; GLuint fbos[2]; @@ -124,15 +168,37 @@ _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx, GLbitfield mask; GLenum status, attachment; - if (_mesa_is_format_compressed(dst_tex_image->TexFormat)) + if (src_renderbuffer) { + src_format = src_renderbuffer->Format; + src_internal_format = src_renderbuffer->InternalFormat; + } else { + assert(src_tex_image); + src_format = src_tex_image->TexFormat; + src_internal_format = src_tex_image->InternalFormat; + } + + if (dst_renderbuffer) { + dst_format = dst_renderbuffer->Format; + dst_internal_format = dst_renderbuffer->InternalFormat; + } else { + assert(dst_tex_image); + dst_format = dst_tex_image->TexFormat; + dst_internal_format = dst_tex_image->InternalFormat; + } + + if (_mesa_is_format_compressed(src_format)) return false; - if (_mesa_is_format_compressed(src_tex_image->TexFormat)) + if (_mesa_is_format_compressed(dst_format)) return false; - if (src_tex_image->InternalFormat == dst_tex_image->InternalFormat) { + if (src_internal_format == dst_internal_format) { src_view_tex_image = src_tex_image; } else { + if (src_renderbuffer) { + assert(src_tex_image == NULL); + src_tex_image = wrap_renderbuffer(ctx, src_renderbuffer); + } if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture, dst_tex_image->InternalFormat)) goto cleanup; @@ -145,7 +211,7 @@ _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx, _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); - switch (_mesa_get_format_base_format(src_tex_image->TexFormat)) { + switch (_mesa_get_format_base_format(src_format)) { case GL_DEPTH_COMPONENT: attachment = GL_DEPTH_ATTACHMENT; mask = GL_DEPTH_BUFFER_BIT; @@ -165,15 +231,32 @@ _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx, _mesa_ReadBuffer(GL_COLOR_ATTACHMENT0); } - _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, attachment, - src_view_tex_image, src_z); + if (src_view_tex_image) { + /* Prever the tex image because, even if we have a renderbuffer, we may + * have had to wrap it in a texture view. + */ + _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, attachment, + src_view_tex_image, src_z); + } else { + _mesa_FramebufferRenderbuffer(GL_READ_FRAMEBUFFER, + attachment, + GL_RENDERBUFFER, + src_renderbuffer->Name); + } status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; - _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, attachment, - dst_tex_image, dst_z); + if (dst_renderbuffer) { + _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, + attachment, + GL_RENDERBUFFER, + dst_renderbuffer->Name); + } else { + _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, attachment, + dst_tex_image, dst_z); + } status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) @@ -205,5 +288,9 @@ meta_end: cleanup: _mesa_DeleteTextures(1, &src_view_texture); + /* If we got a renderbuffer source, delete the temporary texture */ + if (src_renderbuffer && src_tex_image) + ctx->Driver.DeleteTexture(ctx, src_tex_image->TexObject); + return success; } diff --git a/src/mesa/drivers/dri/i965/intel_copy_image.c b/src/mesa/drivers/dri/i965/intel_copy_image.c index ac2738f59a0..d57651cef5f 100644 --- a/src/mesa/drivers/dri/i965/intel_copy_image.c +++ b/src/mesa/drivers/dri/i965/intel_copy_image.c @@ -25,10 +25,12 @@ * Jason Ekstrand <[email protected]> */ +#include "intel_fbo.h" #include "intel_tex.h" #include "intel_blit.h" #include "intel_mipmap_tree.h" #include "main/formats.h" +#include "main/teximage.h" #include "drivers/common/meta.h" static bool @@ -196,54 +198,86 @@ copy_image_with_memcpy(struct brw_context *brw, } } + static void intel_copy_image_sub_data(struct gl_context *ctx, struct gl_texture_image *src_image, + struct gl_renderbuffer *src_renderbuffer, int src_x, int src_y, int src_z, struct gl_texture_image *dst_image, + struct gl_renderbuffer *dst_renderbuffer, int dst_x, int dst_y, int dst_z, int src_width, int src_height) { struct brw_context *brw = brw_context(ctx); - struct intel_texture_image *intel_src_image = intel_texture_image(src_image); - struct intel_texture_image *intel_dst_image = intel_texture_image(dst_image); + struct intel_mipmap_tree *src_mt, *dst_mt; + unsigned src_level, dst_level; if (_mesa_meta_CopyImageSubData_uncompressed(ctx, - src_image, src_x, src_y, src_z, - dst_image, dst_x, dst_y, dst_z, + src_image, src_renderbuffer, + src_x, src_y, src_z, + dst_image, dst_renderbuffer, + dst_x, dst_y, dst_z, src_width, src_height)) { return; } - if (intel_src_image->mt->num_samples > 0 || - intel_dst_image->mt->num_samples > 0) { + if (src_image) { + src_mt = intel_texture_image(src_image)->mt; + } else { + assert(src_renderbuffer); + src_mt = intel_renderbuffer(src_renderbuffer)->mt; + src_image = src_renderbuffer->TexImage; + } + + if (dst_image) { + dst_mt = intel_texture_image(dst_image)->mt; + } else { + assert(dst_renderbuffer); + dst_mt = intel_renderbuffer(dst_renderbuffer)->mt; + src_image = src_renderbuffer->TexImage; + } + + if (src_mt->num_samples > 0 || dst_mt->num_samples > 0) { _mesa_problem(ctx, "Failed to copy multisampled texture with meta path\n"); return; } - /* Cube maps actually have different images per face */ - if (src_image->TexObject->Target == GL_TEXTURE_CUBE_MAP) - src_z = src_image->Face; - if (dst_image->TexObject->Target == GL_TEXTURE_CUBE_MAP) - dst_z = dst_image->Face; + if (src_image) { + src_level = src_image->Level + src_image->TexObject->MinLevel; + + /* Cube maps actually have different images per face */ + if (src_image->TexObject->Target == GL_TEXTURE_CUBE_MAP) + src_z = src_image->Face; + } else { + src_level = 0; + } + + if (dst_image) { + dst_level = dst_image->Level + dst_image->TexObject->MinLevel; + + /* Cube maps actually have different images per face */ + if (dst_image->TexObject->Target == GL_TEXTURE_CUBE_MAP) + dst_z = dst_image->Face; + } else { + dst_level = 0; + } /* We are now going to try and copy the texture using the blitter. If * that fails, we will fall back mapping the texture and using memcpy. * In either case, we need to do a full resolve. */ - intel_miptree_all_slices_resolve_hiz(brw, intel_src_image->mt); - intel_miptree_all_slices_resolve_depth(brw, intel_src_image->mt); - intel_miptree_resolve_color(brw, intel_src_image->mt); + intel_miptree_all_slices_resolve_hiz(brw, src_mt); + intel_miptree_all_slices_resolve_depth(brw, src_mt); + intel_miptree_resolve_color(brw, src_mt); - intel_miptree_all_slices_resolve_hiz(brw, intel_dst_image->mt); - intel_miptree_all_slices_resolve_depth(brw, intel_dst_image->mt); - intel_miptree_resolve_color(brw, intel_dst_image->mt); + intel_miptree_all_slices_resolve_hiz(brw, dst_mt); + intel_miptree_all_slices_resolve_depth(brw, dst_mt); + intel_miptree_resolve_color(brw, dst_mt); - unsigned src_level = src_image->Level + src_image->TexObject->MinLevel; - unsigned dst_level = dst_image->Level + dst_image->TexObject->MinLevel; - if (copy_image_with_blitter(brw, intel_src_image->mt, src_level, + if (copy_image_with_blitter(brw, src_mt, src_level, src_x, src_y, src_z, - intel_dst_image->mt, dst_level, + dst_mt, dst_level, dst_x, dst_y, dst_z, src_width, src_height)) return; @@ -251,9 +285,9 @@ intel_copy_image_sub_data(struct gl_context *ctx, /* This is a worst-case scenario software fallback that maps the two * textures and does a memcpy between them. */ - copy_image_with_memcpy(brw, intel_src_image->mt, src_level, + copy_image_with_memcpy(brw, src_mt, src_level, src_x, src_y, src_z, - intel_dst_image->mt, dst_level, + dst_mt, dst_level, dst_x, dst_y, dst_z, src_width, src_height); } diff --git a/src/mesa/main/copyimage.c b/src/mesa/main/copyimage.c index 05bc50dd2c6..f02e842f34d 100644 --- a/src/mesa/main/copyimage.c +++ b/src/mesa/main/copyimage.c @@ -41,22 +41,27 @@ enum mesa_block_class { }; /** - * Prepare the source or destination resource, including: - * - Error checking - * - Creating texture wrappers for renderbuffers + * Prepare the source or destination resource. This involves error + * checking and returning the relevant gl_texture_image or gl_renderbuffer. + * Note that one of the resulting tex_image or renderbuffer pointers will be + * NULL and the other will be non-null. + * * \param name the texture or renderbuffer name - * \param target GL_TEXTURE target or GL_RENDERBUFFER. For the later, will - * be changed to a compatible GL_TEXTURE target. + * \param target One of GL_TEXTURE_x target or GL_RENDERBUFFER * \param level mipmap level - * \param tex_obj returns a pointer to a texture object + * \param z src or dest Z + * \param depth number of slices/faces/layers to copy * \param tex_image returns a pointer to a texture image - * \param tmp_tex returns temporary texture object name + * \param renderbuffer returns a pointer to a renderbuffer * \return true if success, false if error */ static bool -prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level, - struct gl_texture_object **tex_obj, - struct gl_texture_image **tex_image, GLuint *tmp_tex, +prepare_target(struct gl_context *ctx, GLuint name, GLenum target, + int level, int z, int depth, + struct gl_texture_image **tex_image, + struct gl_renderbuffer **renderbuffer, + mesa_format *format, + GLenum *internalFormat, const char *dbg_prefix) { if (name == 0) { @@ -72,7 +77,7 @@ prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level, * - is TEXTURE_BUFFER, or * - is one of the cubemap face selectors described in table 3.17, */ - switch (*target) { + switch (target) { case GL_RENDERBUFFER: /* Not a texture target, but valid */ case GL_TEXTURE_1D: @@ -93,12 +98,13 @@ prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level, default: _mesa_error(ctx, GL_INVALID_ENUM, "glCopyImageSubData(%sTarget = %s)", dbg_prefix, - _mesa_enum_to_string(*target)); + _mesa_enum_to_string(target)); return false; } - if (*target == GL_RENDERBUFFER) { + if (target == GL_RENDERBUFFER) { struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); + if (!rb) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %u)", dbg_prefix, name); @@ -117,49 +123,38 @@ prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level, return false; } - if (rb->NumSamples > 1) - *target = GL_TEXTURE_2D_MULTISAMPLE; - else - *target = GL_TEXTURE_2D; - - *tmp_tex = 0; - _mesa_GenTextures(1, tmp_tex); - if (*tmp_tex == 0) - return false; /* Error already set by GenTextures */ - - _mesa_BindTexture(*target, *tmp_tex); - *tex_obj = _mesa_lookup_texture(ctx, *tmp_tex); - *tex_image = _mesa_get_tex_image(ctx, *tex_obj, *target, 0); - - if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, *tex_image)) { - _mesa_problem(ctx, "Failed to create texture from renderbuffer"); - return false; - } - - if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) { - rb->NeedsFinishRenderTexture = true; - ctx->Driver.FinishRenderTexture(ctx, rb); - } + *renderbuffer = rb; + *format = rb->Format; + *internalFormat = rb->InternalFormat; + *tex_image = NULL; } else { - *tex_obj = _mesa_lookup_texture(ctx, name); - if (!*tex_obj) { + struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name); + + if (!texObj) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %u)", dbg_prefix, name); return false; } - _mesa_test_texobj_completeness(ctx, *tex_obj); - if (!(*tex_obj)->_BaseComplete || - (level != 0 && !(*tex_obj)->_MipmapComplete)) { + _mesa_test_texobj_completeness(ctx, texObj); + if (!texObj->_BaseComplete || + (level != 0 && !texObj->_MipmapComplete)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(%sName incomplete)", dbg_prefix); return false; } - if ((*tex_obj)->Target != *target) { - _mesa_error(ctx, GL_INVALID_ENUM, + /* Note that target will not be a cube face name */ + if (texObj->Target != target) { + /* + * From GL_ARB_copy_image specification: + * "INVALID_VALUE is generated if either <srcName> or <dstName> does + * not correspond to a valid renderbuffer or texture object according + * to the corresponding target parameter." + */ + _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sTarget = %s)", dbg_prefix, - _mesa_enum_to_string(*target)); + _mesa_enum_to_string(target)); return false; } @@ -169,12 +164,36 @@ prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level, return false; } - *tex_image = _mesa_select_tex_image(*tex_obj, *target, level); + if (target == GL_TEXTURE_CUBE_MAP) { + int i; + + assert(z < MAX_FACES); /* should have been caught earlier */ + + /* make sure all the cube faces are present */ + for (i = 0; i < depth; i++) { + if (!texObj->Image[z+i][level]) { + /* missing cube face */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyImageSubData(missing cube face)"); + return false; + } + } + + *tex_image = texObj->Image[z][level]; + } + else { + *tex_image = _mesa_select_tex_image(texObj, target, level); + } + if (!*tex_image) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); return false; } + + *renderbuffer = NULL; + *format = (*tex_image)->TexFormat; + *internalFormat = (*tex_image)->InternalFormat; } return true; @@ -188,10 +207,14 @@ prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level, */ static bool check_region_bounds(struct gl_context *ctx, + GLenum target, const struct gl_texture_image *tex_image, + const struct gl_renderbuffer *renderbuffer, int x, int y, int z, int width, int height, int depth, const char *dbg_prefix) { + int surfWidth, surfHeight, surfDepth; + if (width < 0 || height < 0 || depth < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)", @@ -207,7 +230,14 @@ check_region_bounds(struct gl_context *ctx, } /* Check X direction */ - if (x + width > tex_image->Width) { + if (target == GL_RENDERBUFFER) { + surfWidth = renderbuffer->Width; + } + else { + surfWidth = tex_image->Width; + } + + if (x + width > surfWidth) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sX or %sWidth exceeds image bounds)", dbg_prefix, dbg_prefix); @@ -215,66 +245,49 @@ check_region_bounds(struct gl_context *ctx, } /* Check Y direction */ - switch (tex_image->TexObject->Target) { + switch (target) { + case GL_RENDERBUFFER: + surfHeight = renderbuffer->Height; + break; case GL_TEXTURE_1D: case GL_TEXTURE_1D_ARRAY: - if (y != 0 || height != 1) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyImageSubData(%sY or %sHeight exceeds image bounds)", - dbg_prefix, dbg_prefix); - return false; - } + surfHeight = 1; break; default: - if (y + height > tex_image->Height) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyImageSubData(%sY or %sHeight exceeds image bounds)", - dbg_prefix, dbg_prefix); - return false; - } - break; + surfHeight = tex_image->Height; + } + + if (y + height > surfHeight) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sY or %sHeight exceeds image bounds)", + dbg_prefix, dbg_prefix); + return false; } /* Check Z direction */ - switch (tex_image->TexObject->Target) { + switch (target) { + case GL_RENDERBUFFER: case GL_TEXTURE_1D: case GL_TEXTURE_2D: case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_RECTANGLE: - if (z != 0 || depth != 1) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", - dbg_prefix, dbg_prefix); - return false; - } + surfDepth = 1; break; case GL_TEXTURE_CUBE_MAP: - if (z < 0 || z + depth > 6) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", - dbg_prefix, dbg_prefix); - return false; - } + surfDepth = 6; break; case GL_TEXTURE_1D_ARRAY: - if (z < 0 || z + depth > tex_image->Height) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", - dbg_prefix, dbg_prefix); - return false; - } - break; - case GL_TEXTURE_CUBE_MAP_ARRAY: - case GL_TEXTURE_2D_ARRAY: - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - case GL_TEXTURE_3D: - if (z < 0 || z + depth > tex_image->Depth) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", - dbg_prefix, dbg_prefix); - return false; - } + surfDepth = tex_image->Height; break; + default: + surfDepth = tex_image->Depth; + } + + if (z < 0 || z + depth > surfDepth) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", + dbg_prefix, dbg_prefix); + return false; } return true; @@ -406,10 +419,12 @@ _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { GET_CURRENT_CONTEXT(ctx); - GLuint tmpTexNames[2] = { 0, 0 }; - struct gl_texture_object *srcTexObj, *dstTexObj; struct gl_texture_image *srcTexImage, *dstTexImage; + struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer; + mesa_format srcFormat, dstFormat; + GLenum srcIntFormat, dstIntFormat; GLuint src_bw, src_bh, dst_bw, dst_bh; + int dstWidth, dstHeight, dstDepth; int i; if (MESA_VERBOSE & VERBOSE_API) @@ -420,7 +435,7 @@ _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, srcX, srcY, srcZ, dstName, _mesa_enum_to_string(dstTarget), dstLevel, dstX, dstY, dstZ, - srcWidth, srcHeight, srcWidth); + srcWidth, srcHeight, srcDepth); if (!ctx->Extensions.ARB_copy_image) { _mesa_error(ctx, GL_INVALID_OPERATION, @@ -428,67 +443,93 @@ _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, return; } - if (!prepare_target(ctx, srcName, &srcTarget, srcLevel, - &srcTexObj, &srcTexImage, &tmpTexNames[0], "src")) - goto cleanup; + if (!prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth, + &srcTexImage, &srcRenderbuffer, &srcFormat, + &srcIntFormat, "src")) + return; - if (!prepare_target(ctx, dstName, &dstTarget, dstLevel, - &dstTexObj, &dstTexImage, &tmpTexNames[1], "dst")) - goto cleanup; + if (!prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth, + &dstTexImage, &dstRenderbuffer, &dstFormat, + &dstIntFormat, "dst")) + return; - _mesa_get_format_block_size(srcTexImage->TexFormat, &src_bw, &src_bh); + _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh); if ((srcX % src_bw != 0) || (srcY % src_bh != 0) || (srcWidth % src_bw != 0) || (srcHeight % src_bh != 0)) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(unaligned src rectangle)"); - goto cleanup; + return; } - _mesa_get_format_block_size(dstTexImage->TexFormat, &dst_bw, &dst_bh); + _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh); if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(unaligned dst rectangle)"); - goto cleanup; + return; } - if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ, - srcWidth, srcHeight, srcDepth, "src")) - goto cleanup; + /* From the GL_ARB_copy_image spec: + * + * "The dimensions are always specified in texels, even for compressed + * texture formats. But it should be noted that if only one of the + * source and destination textures is compressed then the number of + * texels touched in the compressed image will be a factor of the + * block size larger than in the uncompressed image." + * + * So, if copying from compressed to uncompressed, the dest region is + * shrunk by the src block size factor. If copying from uncompressed + * to compressed, the dest region is grown by the dest block size factor. + * Note that we're passed the _source_ width, height, depth and those + * dimensions are never changed. + */ + dstWidth = srcWidth * dst_bw / src_bw; + dstHeight = srcHeight * dst_bh / src_bh; + dstDepth = srcDepth; + + if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer, + srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth, + "src")) + return; - if (!check_region_bounds(ctx, dstTexImage, dstX, dstY, dstZ, - (srcWidth / src_bw) * dst_bw, - (srcHeight / src_bh) * dst_bh, srcDepth, "dst")) - goto cleanup; + if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer, + dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth, + "dst")) + return; - if (!copy_format_compatible(ctx, srcTexImage->InternalFormat, - dstTexImage->InternalFormat)) { + if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(internalFormat mismatch)"); - goto cleanup; + return; } + /* loop over 2D slices/faces/layers */ for (i = 0; i < srcDepth; ++i) { - int srcNewZ, dstNewZ; - - if (srcTexObj->Target == GL_TEXTURE_CUBE_MAP) { - srcTexImage = srcTexObj->Image[i + srcZ][srcLevel]; - srcNewZ = 0; - } else { - srcNewZ = srcZ + i; + int newSrcZ = srcZ + i; + int newDstZ = dstZ + i; + + if (srcTexImage && + srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) { + /* need to update srcTexImage pointer for the cube face */ + assert(srcZ + i < MAX_FACES); + srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel]; + assert(srcTexImage); + newSrcZ = 0; } - if (dstTexObj->Target == GL_TEXTURE_CUBE_MAP) { - dstTexImage = dstTexObj->Image[i + dstZ][dstLevel]; - dstNewZ = 0; - } else { - dstNewZ = dstZ + i; + if (dstTexImage && + dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) { + /* need to update dstTexImage pointer for the cube face */ + assert(dstZ + i < MAX_FACES); + dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel]; + assert(dstTexImage); + newDstZ = 0; } - ctx->Driver.CopyImageSubData(ctx, srcTexImage, srcX, srcY, srcNewZ, - dstTexImage, dstX, dstY, dstNewZ, + ctx->Driver.CopyImageSubData(ctx, + srcTexImage, srcRenderbuffer, + srcX, srcY, newSrcZ, + dstTexImage, dstRenderbuffer, + dstX, dstY, newDstZ, srcWidth, srcHeight); } - -cleanup: - _mesa_DeleteTextures(2, tmpTexNames); } diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 87eb63ea374..2c746fc45de 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -269,20 +269,25 @@ struct dd_function_table { struct gl_renderbuffer *rb, GLint x, GLint y, GLsizei width, GLsizei height); - /** * Called by glCopyImageSubData(). * - * This function should copy one 2-D slice from srcTexImage to - * dstTexImage. If one of the textures is 3-D or is a 1-D or 2-D array + * This function should copy one 2-D slice from src_teximage or + * src_renderbuffer to dst_teximage or dst_renderbuffer. Either the + * teximage or renderbuffer pointer will be non-null to indicate which + * is the real src/dst. + * + * If one of the textures is 3-D or is a 1-D or 2-D array * texture, this function will be called multiple times: once for each * slice. If one of the textures is a cube map, this function will be * called once for each face to be copied. */ void (*CopyImageSubData)(struct gl_context *ctx, - struct gl_texture_image *src_image, + struct gl_texture_image *src_teximage, + struct gl_renderbuffer *src_renderbuffer, int src_x, int src_y, int src_z, - struct gl_texture_image *dstTexImage, + struct gl_texture_image *dst_teximage, + struct gl_renderbuffer *dst_renderbuffer, int dst_x, int dst_y, int dst_z, int src_width, int src_height); diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index 93335aefe6c..5d25fed317e 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -1879,22 +1879,45 @@ st_TextureView(struct gl_context *ctx, static void st_CopyImageSubData(struct gl_context *ctx, struct gl_texture_image *src_image, + struct gl_renderbuffer *src_renderbuffer, int src_x, int src_y, int src_z, struct gl_texture_image *dst_image, + struct gl_renderbuffer *dst_renderbuffer, int dst_x, int dst_y, int dst_z, int src_width, int src_height) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; - struct st_texture_image *src = st_texture_image(src_image); - struct st_texture_image *dst = st_texture_image(dst_image); - + struct pipe_resource *src_res, *dst_res; struct pipe_box box; + int src_level, dst_level; + + if (src_image) { + struct st_texture_image *src = st_texture_image(src_image); + src_res = src->pt; + src_level = src_image->Level; + } + else { + struct st_renderbuffer *src = st_renderbuffer(src_renderbuffer); + src_res = src->texture; + src_level = 0; + } + + if (dst_image) { + struct st_texture_image *dst = st_texture_image(dst_image); + dst_res = dst->pt; + dst_level = dst_image->Level; + } + else { + struct st_renderbuffer *dst = st_renderbuffer(dst_renderbuffer); + dst_res = dst->texture; + dst_level = 0; + } u_box_2d_zslice(src_x, src_y, src_z, src_width, src_height, &box); - pipe->resource_copy_region(pipe, dst->pt, dst_image->Level, + pipe->resource_copy_region(pipe, dst_res, dst_level, dst_x, dst_y, dst_z, - src->pt, src_image->Level, + src_res, src_level, &box); } |