summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/mesa/drivers/common/meta.h2
-rw-r--r--src/mesa/drivers/common/meta_copy_image.c103
-rw-r--r--src/mesa/drivers/dri/i965/intel_copy_image.c80
-rw-r--r--src/mesa/main/copyimage.c301
-rw-r--r--src/mesa/main/dd.h15
-rw-r--r--src/mesa/state_tracker/st_cb_texture.c33
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);
}