2 * Mesa 3-D graphics library
4 * Copyright (C) 2014 Intel Corporation. All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
25 * Jason Ekstrand <jason.ekstrand@intel.com>
31 #include "copyimage.h"
35 #include "textureview.h"
36 #include "glformats.h"
38 enum mesa_block_class
{
44 * Prepare the source or destination resource. This involves error
45 * checking and returning the relevant gl_texture_image or gl_renderbuffer.
46 * Note that one of the resulting tex_image or renderbuffer pointers will be
47 * NULL and the other will be non-null.
49 * \param name the texture or renderbuffer name
50 * \param target One of GL_TEXTURE_x target or GL_RENDERBUFFER
51 * \param level mipmap level
52 * \param z src or dest Z
53 * \param depth number of slices/faces/layers to copy
54 * \param tex_image returns a pointer to a texture image
55 * \param renderbuffer returns a pointer to a renderbuffer
56 * \return true if success, false if error
59 prepare_target(struct gl_context
*ctx
, GLuint name
, GLenum target
,
60 int level
, int z
, int depth
,
61 struct gl_texture_image
**tex_image
,
62 struct gl_renderbuffer
**renderbuffer
,
64 GLenum
*internalFormat
,
65 const char *dbg_prefix
)
68 _mesa_error(ctx
, GL_INVALID_VALUE
,
69 "glCopyImageSubData(%sName = %d)", dbg_prefix
, name
);
74 * INVALID_ENUM is generated
75 * * if either <srcTarget> or <dstTarget>
76 * - is not RENDERBUFFER or a valid non-proxy texture target
77 * - is TEXTURE_BUFFER, or
78 * - is one of the cubemap face selectors described in table 3.17,
82 /* Not a texture target, but valid */
84 case GL_TEXTURE_1D_ARRAY
:
87 case GL_TEXTURE_CUBE_MAP
:
88 case GL_TEXTURE_RECTANGLE
:
89 case GL_TEXTURE_2D_ARRAY
:
90 case GL_TEXTURE_CUBE_MAP_ARRAY
:
91 case GL_TEXTURE_2D_MULTISAMPLE
:
92 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
:
93 /* These are all valid */
95 case GL_TEXTURE_EXTERNAL_OES
:
96 /* Only exists in ES */
97 case GL_TEXTURE_BUFFER
:
99 _mesa_error(ctx
, GL_INVALID_ENUM
,
100 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
101 _mesa_enum_to_string(target
));
105 if (target
== GL_RENDERBUFFER
) {
106 struct gl_renderbuffer
*rb
= _mesa_lookup_renderbuffer(ctx
, name
);
109 _mesa_error(ctx
, GL_INVALID_VALUE
,
110 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
115 _mesa_error(ctx
, GL_INVALID_OPERATION
,
116 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
121 _mesa_error(ctx
, GL_INVALID_VALUE
,
122 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
127 *format
= rb
->Format
;
128 *internalFormat
= rb
->InternalFormat
;
131 struct gl_texture_object
*texObj
= _mesa_lookup_texture(ctx
, name
);
134 _mesa_error(ctx
, GL_INVALID_VALUE
,
135 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
139 _mesa_test_texobj_completeness(ctx
, texObj
);
140 if (!texObj
->_BaseComplete
||
141 (level
!= 0 && !texObj
->_MipmapComplete
)) {
142 _mesa_error(ctx
, GL_INVALID_OPERATION
,
143 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
147 /* Note that target will not be a cube face name */
148 if (texObj
->Target
!= target
) {
150 * From GL_ARB_copy_image specification:
151 * "INVALID_VALUE is generated if either <srcName> or <dstName> does
152 * not correspond to a valid renderbuffer or texture object according
153 * to the corresponding target parameter."
155 _mesa_error(ctx
, GL_INVALID_VALUE
,
156 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
157 _mesa_enum_to_string(target
));
161 if (level
< 0 || level
>= MAX_TEXTURE_LEVELS
) {
162 _mesa_error(ctx
, GL_INVALID_VALUE
,
163 "glCopyImageSubData(%sLevel = %d)", dbg_prefix
, level
);
167 if (target
== GL_TEXTURE_CUBE_MAP
) {
170 assert(z
< MAX_FACES
); /* should have been caught earlier */
172 /* make sure all the cube faces are present */
173 for (i
= 0; i
< depth
; i
++) {
174 if (!texObj
->Image
[z
+i
][level
]) {
175 /* missing cube face */
176 _mesa_error(ctx
, GL_INVALID_OPERATION
,
177 "glCopyImageSubData(missing cube face)");
182 *tex_image
= texObj
->Image
[z
][level
];
185 *tex_image
= _mesa_select_tex_image(texObj
, target
, level
);
189 _mesa_error(ctx
, GL_INVALID_VALUE
,
190 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
194 *renderbuffer
= NULL
;
195 *format
= (*tex_image
)->TexFormat
;
196 *internalFormat
= (*tex_image
)->InternalFormat
;
204 * Check that the x,y,z,width,height,region is within the texture image
206 * \return true if bounds OK, false if regions is out of bounds
209 check_region_bounds(struct gl_context
*ctx
,
211 const struct gl_texture_image
*tex_image
,
212 const struct gl_renderbuffer
*renderbuffer
,
213 int x
, int y
, int z
, int width
, int height
, int depth
,
214 const char *dbg_prefix
)
216 int surfWidth
, surfHeight
, surfDepth
;
218 if (width
< 0 || height
< 0 || depth
< 0) {
219 _mesa_error(ctx
, GL_INVALID_VALUE
,
220 "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
221 dbg_prefix
, dbg_prefix
, dbg_prefix
);
225 if (x
< 0 || y
< 0 || z
< 0) {
226 _mesa_error(ctx
, GL_INVALID_VALUE
,
227 "glCopyImageSubData(%sX, %sY, or %sZ is negative)",
228 dbg_prefix
, dbg_prefix
, dbg_prefix
);
232 /* Check X direction */
233 if (target
== GL_RENDERBUFFER
) {
234 surfWidth
= renderbuffer
->Width
;
237 surfWidth
= tex_image
->Width
;
240 if (x
+ width
> surfWidth
) {
241 _mesa_error(ctx
, GL_INVALID_VALUE
,
242 "glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
243 dbg_prefix
, dbg_prefix
);
247 /* Check Y direction */
249 case GL_RENDERBUFFER
:
250 surfHeight
= renderbuffer
->Height
;
253 case GL_TEXTURE_1D_ARRAY
:
257 surfHeight
= tex_image
->Height
;
260 if (y
+ height
> surfHeight
) {
261 _mesa_error(ctx
, GL_INVALID_VALUE
,
262 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
263 dbg_prefix
, dbg_prefix
);
267 /* Check Z direction */
269 case GL_RENDERBUFFER
:
272 case GL_TEXTURE_2D_MULTISAMPLE
:
273 case GL_TEXTURE_RECTANGLE
:
276 case GL_TEXTURE_CUBE_MAP
:
279 case GL_TEXTURE_1D_ARRAY
:
280 surfDepth
= tex_image
->Height
;
283 surfDepth
= tex_image
->Depth
;
286 if (z
< 0 || z
+ depth
> surfDepth
) {
287 _mesa_error(ctx
, GL_INVALID_VALUE
,
288 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
289 dbg_prefix
, dbg_prefix
);
297 compressed_format_compatible(const struct gl_context
*ctx
,
298 GLenum compressedFormat
, GLenum otherFormat
)
300 enum mesa_block_class compressedClass
, otherClass
;
302 /* Two view-incompatible compressed formats are never compatible. */
303 if (_mesa_is_compressed_format(ctx
, otherFormat
)) {
308 * From ARB_copy_image spec:
309 * Table 4.X.1 (Compatible internal formats for copying between
310 * compressed and uncompressed internal formats)
311 * ---------------------------------------------------------------------
312 * | Texel / | Uncompressed | |
313 * | Block | internal format | Compressed internal format |
315 * ---------------------------------------------------------------------
316 * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, |
317 * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
318 * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, |
319 * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
320 * | | | COMPRESSED_RG_RGTC2, |
321 * | | | COMPRESSED_SIGNED_RG_RGTC2, |
322 * | | | COMPRESSED_RGBA_BPTC_UNORM, |
323 * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, |
324 * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, |
325 * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT |
326 * ---------------------------------------------------------------------
327 * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, |
328 * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, |
329 * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, |
330 * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
331 * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, |
332 * | | | COMPRESSED_SIGNED_RED_RGTC1 |
333 * ---------------------------------------------------------------------
336 switch (compressedFormat
) {
337 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
:
338 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
:
339 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
:
340 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
:
341 case GL_COMPRESSED_RG_RGTC2
:
342 case GL_COMPRESSED_SIGNED_RG_RGTC2
:
343 case GL_COMPRESSED_RGBA_BPTC_UNORM
:
344 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM
:
345 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT
:
346 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT
:
347 compressedClass
= BLOCK_CLASS_128_BITS
;
349 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT
:
350 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
:
351 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
:
352 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
:
353 case GL_COMPRESSED_RED_RGTC1
:
354 case GL_COMPRESSED_SIGNED_RED_RGTC1
:
355 compressedClass
= BLOCK_CLASS_64_BITS
;
361 switch (otherFormat
) {
365 otherClass
= BLOCK_CLASS_128_BITS
;
374 case GL_RGBA16_SNORM
:
375 otherClass
= BLOCK_CLASS_64_BITS
;
381 return compressedClass
== otherClass
;
385 copy_format_compatible(const struct gl_context
*ctx
,
386 GLenum srcFormat
, GLenum dstFormat
)
389 * From ARB_copy_image spec:
390 * For the purposes of CopyImageSubData, two internal formats
391 * are considered compatible if any of the following conditions are
393 * * the formats are the same,
394 * * the formats are considered compatible according to the
395 * compatibility rules used for texture views as defined in
396 * section 3.9.X. In particular, if both internal formats are listed
397 * in the same entry of Table 3.X.2, they are considered compatible, or
398 * * one format is compressed and the other is uncompressed and
399 * Table 4.X.1 lists the two formats in the same row.
402 if (_mesa_texture_view_compatible_format(ctx
, srcFormat
, dstFormat
)) {
403 /* Also checks if formats are equal. */
405 } else if (_mesa_is_compressed_format(ctx
, srcFormat
)) {
406 return compressed_format_compatible(ctx
, srcFormat
, dstFormat
);
407 } else if (_mesa_is_compressed_format(ctx
, dstFormat
)) {
408 return compressed_format_compatible(ctx
, dstFormat
, srcFormat
);
415 _mesa_CopyImageSubData(GLuint srcName
, GLenum srcTarget
, GLint srcLevel
,
416 GLint srcX
, GLint srcY
, GLint srcZ
,
417 GLuint dstName
, GLenum dstTarget
, GLint dstLevel
,
418 GLint dstX
, GLint dstY
, GLint dstZ
,
419 GLsizei srcWidth
, GLsizei srcHeight
, GLsizei srcDepth
)
421 GET_CURRENT_CONTEXT(ctx
);
422 struct gl_texture_image
*srcTexImage
, *dstTexImage
;
423 struct gl_renderbuffer
*srcRenderbuffer
, *dstRenderbuffer
;
424 mesa_format srcFormat
, dstFormat
;
425 GLenum srcIntFormat
, dstIntFormat
;
426 GLuint src_bw
, src_bh
, dst_bw
, dst_bh
;
427 int dstWidth
, dstHeight
, dstDepth
;
430 if (MESA_VERBOSE
& VERBOSE_API
)
431 _mesa_debug(ctx
, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
432 "%u, %s, %d, %d, %d, %d, "
434 srcName
, _mesa_enum_to_string(srcTarget
), srcLevel
,
436 dstName
, _mesa_enum_to_string(dstTarget
), dstLevel
,
438 srcWidth
, srcHeight
, srcDepth
);
440 if (!ctx
->Extensions
.ARB_copy_image
) {
441 _mesa_error(ctx
, GL_INVALID_OPERATION
,
442 "glCopyImageSubData(extension not available)");
446 if (!prepare_target(ctx
, srcName
, srcTarget
, srcLevel
, srcZ
, srcDepth
,
447 &srcTexImage
, &srcRenderbuffer
, &srcFormat
,
448 &srcIntFormat
, "src"))
451 if (!prepare_target(ctx
, dstName
, dstTarget
, dstLevel
, dstZ
, srcDepth
,
452 &dstTexImage
, &dstRenderbuffer
, &dstFormat
,
453 &dstIntFormat
, "dst"))
456 _mesa_get_format_block_size(srcFormat
, &src_bw
, &src_bh
);
457 if ((srcX
% src_bw
!= 0) || (srcY
% src_bh
!= 0) ||
458 (srcWidth
% src_bw
!= 0) || (srcHeight
% src_bh
!= 0)) {
459 _mesa_error(ctx
, GL_INVALID_VALUE
,
460 "glCopyImageSubData(unaligned src rectangle)");
464 _mesa_get_format_block_size(dstFormat
, &dst_bw
, &dst_bh
);
465 if ((dstX
% dst_bw
!= 0) || (dstY
% dst_bh
!= 0)) {
466 _mesa_error(ctx
, GL_INVALID_VALUE
,
467 "glCopyImageSubData(unaligned dst rectangle)");
471 /* From the GL_ARB_copy_image spec:
473 * "The dimensions are always specified in texels, even for compressed
474 * texture formats. But it should be noted that if only one of the
475 * source and destination textures is compressed then the number of
476 * texels touched in the compressed image will be a factor of the
477 * block size larger than in the uncompressed image."
479 * So, if copying from compressed to uncompressed, the dest region is
480 * shrunk by the src block size factor. If copying from uncompressed
481 * to compressed, the dest region is grown by the dest block size factor.
482 * Note that we're passed the _source_ width, height, depth and those
483 * dimensions are never changed.
485 dstWidth
= srcWidth
* dst_bw
/ src_bw
;
486 dstHeight
= srcHeight
* dst_bh
/ src_bh
;
489 if (!check_region_bounds(ctx
, srcTarget
, srcTexImage
, srcRenderbuffer
,
490 srcX
, srcY
, srcZ
, srcWidth
, srcHeight
, srcDepth
,
494 if (!check_region_bounds(ctx
, dstTarget
, dstTexImage
, dstRenderbuffer
,
495 dstX
, dstY
, dstZ
, dstWidth
, dstHeight
, dstDepth
,
499 if (!copy_format_compatible(ctx
, srcIntFormat
, dstIntFormat
)) {
500 _mesa_error(ctx
, GL_INVALID_OPERATION
,
501 "glCopyImageSubData(internalFormat mismatch)");
505 /* loop over 2D slices/faces/layers */
506 for (i
= 0; i
< srcDepth
; ++i
) {
507 int newSrcZ
= srcZ
+ i
;
508 int newDstZ
= dstZ
+ i
;
511 srcTexImage
->TexObject
->Target
== GL_TEXTURE_CUBE_MAP
) {
512 /* need to update srcTexImage pointer for the cube face */
513 assert(srcZ
+ i
< MAX_FACES
);
514 srcTexImage
= srcTexImage
->TexObject
->Image
[srcZ
+ i
][srcLevel
];
520 dstTexImage
->TexObject
->Target
== GL_TEXTURE_CUBE_MAP
) {
521 /* need to update dstTexImage pointer for the cube face */
522 assert(dstZ
+ i
< MAX_FACES
);
523 dstTexImage
= dstTexImage
->TexObject
->Image
[dstZ
+ i
][dstLevel
];
528 ctx
->Driver
.CopyImageSubData(ctx
,
529 srcTexImage
, srcRenderbuffer
,
531 dstTexImage
, dstRenderbuffer
,
533 srcWidth
, srcHeight
);