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>
32 #include "copyimage.h"
36 #include "textureview.h"
37 #include "glformats.h"
39 enum mesa_block_class
{
45 * Prepare the source or destination resource. This involves error
46 * checking and returning the relevant gl_texture_image or gl_renderbuffer.
47 * Note that one of the resulting tex_image or renderbuffer pointers will be
48 * NULL and the other will be non-null.
50 * \param name the texture or renderbuffer name
51 * \param target One of GL_TEXTURE_x target or GL_RENDERBUFFER
52 * \param level mipmap level
53 * \param z src or dest Z
54 * \param depth number of slices/faces/layers to copy
55 * \param tex_image returns a pointer to a texture image
56 * \param renderbuffer returns a pointer to a renderbuffer
57 * \return true if success, false if error
60 prepare_target(struct gl_context
*ctx
, GLuint name
, GLenum target
,
61 int level
, int z
, int depth
,
62 struct gl_texture_image
**tex_image
,
63 struct gl_renderbuffer
**renderbuffer
,
65 GLenum
*internalFormat
,
69 const char *dbg_prefix
)
72 _mesa_error(ctx
, GL_INVALID_VALUE
,
73 "glCopyImageSubData(%sName = %d)", dbg_prefix
, name
);
78 * INVALID_ENUM is generated
79 * * if either <srcTarget> or <dstTarget>
80 * - is not RENDERBUFFER or a valid non-proxy texture target
81 * - is TEXTURE_BUFFER, or
82 * - is one of the cubemap face selectors described in table 3.17,
86 /* Not a texture target, but valid */
88 case GL_TEXTURE_1D_ARRAY
:
91 case GL_TEXTURE_CUBE_MAP
:
92 case GL_TEXTURE_RECTANGLE
:
93 case GL_TEXTURE_2D_ARRAY
:
94 case GL_TEXTURE_CUBE_MAP_ARRAY
:
95 case GL_TEXTURE_2D_MULTISAMPLE
:
96 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
:
97 /* These are all valid */
99 case GL_TEXTURE_EXTERNAL_OES
:
100 /* Only exists in ES */
101 case GL_TEXTURE_BUFFER
:
103 _mesa_error(ctx
, GL_INVALID_ENUM
,
104 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
105 _mesa_enum_to_string(target
));
109 if (target
== GL_RENDERBUFFER
) {
110 struct gl_renderbuffer
*rb
= _mesa_lookup_renderbuffer(ctx
, name
);
113 _mesa_error(ctx
, GL_INVALID_VALUE
,
114 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
119 _mesa_error(ctx
, GL_INVALID_OPERATION
,
120 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
125 _mesa_error(ctx
, GL_INVALID_VALUE
,
126 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
131 *format
= rb
->Format
;
132 *internalFormat
= rb
->InternalFormat
;
134 *height
= rb
->Height
;
135 *num_samples
= rb
->NumSamples
;
138 struct gl_texture_object
*texObj
= _mesa_lookup_texture(ctx
, name
);
142 * From GL_ARB_copy_image specification:
143 * "INVALID_VALUE is generated if either <srcName> or <dstName> does
144 * not correspond to a valid renderbuffer or texture object according
145 * to the corresponding target parameter."
147 _mesa_error(ctx
, GL_INVALID_VALUE
,
148 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
152 /* The ARB_copy_image specification says:
154 * "INVALID_OPERATION is generated if either object is a texture and
155 * the texture is not complete (as defined in section 3.9.14)"
157 * The cited section says:
159 * "Using the preceding definitions, a texture is complete unless any
160 * of the following conditions hold true: [...]
162 * * The minification filter requires a mipmap (is neither NEAREST
163 * nor LINEAR), and the texture is not mipmap complete."
165 * This imposes the bizarre restriction that glCopyImageSubData requires
166 * mipmap completion at times, which dEQP mandates, and other drivers
167 * appear to implement. We don't have any texture units here, so we
168 * can't look at any bound separate sampler objects...it appears that
169 * you're supposed to use the sampler object which is built-in to the
172 * See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16224.
174 _mesa_test_texobj_completeness(ctx
, texObj
);
175 if (!_mesa_is_texture_complete(texObj
, &texObj
->Sampler
)) {
176 _mesa_error(ctx
, GL_INVALID_OPERATION
,
177 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
181 /* Note that target will not be a cube face name */
182 if (texObj
->Target
!= target
) {
184 * From GL_ARB_copy_image_specification:
185 * "INVALID_ENUM is generated if the target does not match the type
188 _mesa_error(ctx
, GL_INVALID_ENUM
,
189 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
190 _mesa_enum_to_string(target
));
194 if (level
< 0 || level
>= MAX_TEXTURE_LEVELS
) {
195 _mesa_error(ctx
, GL_INVALID_VALUE
,
196 "glCopyImageSubData(%sLevel = %d)", dbg_prefix
, level
);
200 if (target
== GL_TEXTURE_CUBE_MAP
) {
203 assert(z
< MAX_FACES
); /* should have been caught earlier */
205 /* make sure all the cube faces are present */
206 for (i
= 0; i
< depth
; i
++) {
207 if (!texObj
->Image
[z
+i
][level
]) {
208 /* missing cube face */
209 _mesa_error(ctx
, GL_INVALID_VALUE
,
210 "glCopyImageSubData(missing cube face)");
215 *tex_image
= texObj
->Image
[z
][level
];
218 *tex_image
= _mesa_select_tex_image(texObj
, target
, level
);
222 _mesa_error(ctx
, GL_INVALID_VALUE
,
223 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
227 *renderbuffer
= NULL
;
228 *format
= (*tex_image
)->TexFormat
;
229 *internalFormat
= (*tex_image
)->InternalFormat
;
230 *width
= (*tex_image
)->Width
;
231 *height
= (*tex_image
)->Height
;
232 *num_samples
= (*tex_image
)->NumSamples
;
240 * Check that the x,y,z,width,height,region is within the texture image
242 * \return true if bounds OK, false if regions is out of bounds
245 check_region_bounds(struct gl_context
*ctx
,
247 const struct gl_texture_image
*tex_image
,
248 const struct gl_renderbuffer
*renderbuffer
,
249 int x
, int y
, int z
, int width
, int height
, int depth
,
250 const char *dbg_prefix
)
252 int surfWidth
, surfHeight
, surfDepth
;
254 if (width
< 0 || height
< 0 || depth
< 0) {
255 _mesa_error(ctx
, GL_INVALID_VALUE
,
256 "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
257 dbg_prefix
, dbg_prefix
, dbg_prefix
);
261 if (x
< 0 || y
< 0 || z
< 0) {
262 _mesa_error(ctx
, GL_INVALID_VALUE
,
263 "glCopyImageSubData(%sX, %sY, or %sZ is negative)",
264 dbg_prefix
, dbg_prefix
, dbg_prefix
);
268 /* Check X direction */
269 if (target
== GL_RENDERBUFFER
) {
270 surfWidth
= renderbuffer
->Width
;
273 surfWidth
= tex_image
->Width
;
276 if (x
+ width
> surfWidth
) {
277 _mesa_error(ctx
, GL_INVALID_VALUE
,
278 "glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
279 dbg_prefix
, dbg_prefix
);
283 /* Check Y direction */
285 case GL_RENDERBUFFER
:
286 surfHeight
= renderbuffer
->Height
;
289 case GL_TEXTURE_1D_ARRAY
:
293 surfHeight
= tex_image
->Height
;
296 if (y
+ height
> surfHeight
) {
297 _mesa_error(ctx
, GL_INVALID_VALUE
,
298 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
299 dbg_prefix
, dbg_prefix
);
303 /* Check Z direction */
305 case GL_RENDERBUFFER
:
308 case GL_TEXTURE_2D_MULTISAMPLE
:
309 case GL_TEXTURE_RECTANGLE
:
312 case GL_TEXTURE_CUBE_MAP
:
315 case GL_TEXTURE_1D_ARRAY
:
316 surfDepth
= tex_image
->Height
;
319 surfDepth
= tex_image
->Depth
;
322 if (z
< 0 || z
+ depth
> surfDepth
) {
323 _mesa_error(ctx
, GL_INVALID_VALUE
,
324 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
325 dbg_prefix
, dbg_prefix
);
333 compressed_format_compatible(const struct gl_context
*ctx
,
334 GLenum compressedFormat
, GLenum otherFormat
)
336 enum mesa_block_class compressedClass
, otherClass
;
338 /* Two view-incompatible compressed formats are never compatible. */
339 if (_mesa_is_compressed_format(ctx
, otherFormat
)) {
344 * From ARB_copy_image spec:
345 * Table 4.X.1 (Compatible internal formats for copying between
346 * compressed and uncompressed internal formats)
347 * ---------------------------------------------------------------------
348 * | Texel / | Uncompressed | |
349 * | Block | internal format | Compressed internal format |
351 * ---------------------------------------------------------------------
352 * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, |
353 * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
354 * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, |
355 * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
356 * | | | COMPRESSED_RG_RGTC2, |
357 * | | | COMPRESSED_SIGNED_RG_RGTC2, |
358 * | | | COMPRESSED_RGBA_BPTC_UNORM, |
359 * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, |
360 * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, |
361 * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT |
362 * ---------------------------------------------------------------------
363 * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, |
364 * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, |
365 * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, |
366 * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
367 * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, |
368 * | | | COMPRESSED_SIGNED_RED_RGTC1 |
369 * ---------------------------------------------------------------------
372 switch (compressedFormat
) {
373 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
:
374 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
:
375 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
:
376 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
:
377 case GL_COMPRESSED_RG_RGTC2
:
378 case GL_COMPRESSED_SIGNED_RG_RGTC2
:
379 case GL_COMPRESSED_RGBA_BPTC_UNORM
:
380 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM
:
381 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT
:
382 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT
:
383 compressedClass
= BLOCK_CLASS_128_BITS
;
385 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT
:
386 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
:
387 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
:
388 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
:
389 case GL_COMPRESSED_RED_RGTC1
:
390 case GL_COMPRESSED_SIGNED_RED_RGTC1
:
391 compressedClass
= BLOCK_CLASS_64_BITS
;
393 case GL_COMPRESSED_RGBA8_ETC2_EAC
:
394 case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
:
395 case GL_COMPRESSED_RG11_EAC
:
396 case GL_COMPRESSED_SIGNED_RG11_EAC
:
397 if (_mesa_is_gles(ctx
))
398 compressedClass
= BLOCK_CLASS_128_BITS
;
402 case GL_COMPRESSED_RGB8_ETC2
:
403 case GL_COMPRESSED_SRGB8_ETC2
:
404 case GL_COMPRESSED_R11_EAC
:
405 case GL_COMPRESSED_SIGNED_R11_EAC
:
406 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
:
407 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
:
408 if (_mesa_is_gles(ctx
))
409 compressedClass
= BLOCK_CLASS_64_BITS
;
414 if (_mesa_is_gles(ctx
) && _mesa_is_astc_format(compressedFormat
))
415 compressedClass
= BLOCK_CLASS_128_BITS
;
421 switch (otherFormat
) {
425 otherClass
= BLOCK_CLASS_128_BITS
;
434 case GL_RGBA16_SNORM
:
435 otherClass
= BLOCK_CLASS_64_BITS
;
441 return compressedClass
== otherClass
;
445 copy_format_compatible(const struct gl_context
*ctx
,
446 GLenum srcFormat
, GLenum dstFormat
)
449 * From ARB_copy_image spec:
450 * For the purposes of CopyImageSubData, two internal formats
451 * are considered compatible if any of the following conditions are
453 * * the formats are the same,
454 * * the formats are considered compatible according to the
455 * compatibility rules used for texture views as defined in
456 * section 3.9.X. In particular, if both internal formats are listed
457 * in the same entry of Table 3.X.2, they are considered compatible, or
458 * * one format is compressed and the other is uncompressed and
459 * Table 4.X.1 lists the two formats in the same row.
462 if (_mesa_texture_view_compatible_format(ctx
, srcFormat
, dstFormat
)) {
463 /* Also checks if formats are equal. */
465 } else if (_mesa_is_compressed_format(ctx
, srcFormat
)) {
466 return compressed_format_compatible(ctx
, srcFormat
, dstFormat
);
467 } else if (_mesa_is_compressed_format(ctx
, dstFormat
)) {
468 return compressed_format_compatible(ctx
, dstFormat
, srcFormat
);
475 _mesa_CopyImageSubData(GLuint srcName
, GLenum srcTarget
, GLint srcLevel
,
476 GLint srcX
, GLint srcY
, GLint srcZ
,
477 GLuint dstName
, GLenum dstTarget
, GLint dstLevel
,
478 GLint dstX
, GLint dstY
, GLint dstZ
,
479 GLsizei srcWidth
, GLsizei srcHeight
, GLsizei srcDepth
)
481 GET_CURRENT_CONTEXT(ctx
);
482 struct gl_texture_image
*srcTexImage
, *dstTexImage
;
483 struct gl_renderbuffer
*srcRenderbuffer
, *dstRenderbuffer
;
484 mesa_format srcFormat
, dstFormat
;
485 GLenum srcIntFormat
, dstIntFormat
;
486 GLuint src_w
, src_h
, dst_w
, dst_h
;
487 GLuint src_bw
, src_bh
, dst_bw
, dst_bh
;
488 GLuint src_num_samples
, dst_num_samples
;
489 int dstWidth
, dstHeight
, dstDepth
;
492 if (MESA_VERBOSE
& VERBOSE_API
)
493 _mesa_debug(ctx
, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
494 "%u, %s, %d, %d, %d, %d, "
496 srcName
, _mesa_enum_to_string(srcTarget
), srcLevel
,
498 dstName
, _mesa_enum_to_string(dstTarget
), dstLevel
,
500 srcWidth
, srcHeight
, srcDepth
);
502 if (!ctx
->Extensions
.ARB_copy_image
) {
503 _mesa_error(ctx
, GL_INVALID_OPERATION
,
504 "glCopyImageSubData(extension not available)");
508 if (!prepare_target(ctx
, srcName
, srcTarget
, srcLevel
, srcZ
, srcDepth
,
509 &srcTexImage
, &srcRenderbuffer
, &srcFormat
,
510 &srcIntFormat
, &src_w
, &src_h
, &src_num_samples
, "src"))
513 if (!prepare_target(ctx
, dstName
, dstTarget
, dstLevel
, dstZ
, srcDepth
,
514 &dstTexImage
, &dstRenderbuffer
, &dstFormat
,
515 &dstIntFormat
, &dst_w
, &dst_h
, &dst_num_samples
, "dst"))
518 _mesa_get_format_block_size(srcFormat
, &src_bw
, &src_bh
);
520 /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
523 * An INVALID_VALUE error is generated if the dimensions of either
524 * subregion exceeds the boundaries of the corresponding image object,
525 * or if the image format is compressed and the dimensions of the
526 * subregion fail to meet the alignment constraints of the format.
528 * and Section 8.7 (Compressed Texture Images) says:
530 * An INVALID_OPERATION error is generated if any of the following
533 * * width is not a multiple of four, and width + xoffset is not
534 * equal to the value of TEXTURE_WIDTH.
535 * * height is not a multiple of four, and height + yoffset is not
536 * equal to the value of TEXTURE_HEIGHT.
538 * so we take that to mean that you can copy the "last" block of a
539 * compressed texture image even if it's smaller than the minimum block
542 if ((srcX
% src_bw
!= 0) || (srcY
% src_bh
!= 0) ||
543 (srcWidth
% src_bw
!= 0 && (srcX
+ srcWidth
) != src_w
) ||
544 (srcHeight
% src_bh
!= 0 && (srcY
+ srcHeight
) != src_h
)) {
545 _mesa_error(ctx
, GL_INVALID_VALUE
,
546 "glCopyImageSubData(unaligned src rectangle)");
550 _mesa_get_format_block_size(dstFormat
, &dst_bw
, &dst_bh
);
551 if ((dstX
% dst_bw
!= 0) || (dstY
% dst_bh
!= 0)) {
552 _mesa_error(ctx
, GL_INVALID_VALUE
,
553 "glCopyImageSubData(unaligned dst rectangle)");
557 /* From the GL_ARB_copy_image spec:
559 * "The dimensions are always specified in texels, even for compressed
560 * texture formats. But it should be noted that if only one of the
561 * source and destination textures is compressed then the number of
562 * texels touched in the compressed image will be a factor of the
563 * block size larger than in the uncompressed image."
565 * So, if copying from compressed to uncompressed, the dest region is
566 * shrunk by the src block size factor. If copying from uncompressed
567 * to compressed, the dest region is grown by the dest block size factor.
568 * Note that we're passed the _source_ width, height, depth and those
569 * dimensions are never changed.
571 dstWidth
= srcWidth
* dst_bw
/ src_bw
;
572 dstHeight
= srcHeight
* dst_bh
/ src_bh
;
575 if (!check_region_bounds(ctx
, srcTarget
, srcTexImage
, srcRenderbuffer
,
576 srcX
, srcY
, srcZ
, srcWidth
, srcHeight
, srcDepth
,
580 if (!check_region_bounds(ctx
, dstTarget
, dstTexImage
, dstRenderbuffer
,
581 dstX
, dstY
, dstZ
, dstWidth
, dstHeight
, dstDepth
,
585 /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
588 * An INVALID_OPERATION error is generated if either object is a texture
589 * and the texture is not complete, if the source and destination internal
590 * formats are not compatible, or if the number of samples do not match.
592 if (!copy_format_compatible(ctx
, srcIntFormat
, dstIntFormat
)) {
593 _mesa_error(ctx
, GL_INVALID_OPERATION
,
594 "glCopyImageSubData(internalFormat mismatch)");
598 if (src_num_samples
!= dst_num_samples
) {
599 _mesa_error(ctx
, GL_INVALID_OPERATION
,
600 "glCopyImageSubData(number of samples mismatch)");
604 /* loop over 2D slices/faces/layers */
605 for (i
= 0; i
< srcDepth
; ++i
) {
606 int newSrcZ
= srcZ
+ i
;
607 int newDstZ
= dstZ
+ i
;
610 srcTexImage
->TexObject
->Target
== GL_TEXTURE_CUBE_MAP
) {
611 /* need to update srcTexImage pointer for the cube face */
612 assert(srcZ
+ i
< MAX_FACES
);
613 srcTexImage
= srcTexImage
->TexObject
->Image
[srcZ
+ i
][srcLevel
];
619 dstTexImage
->TexObject
->Target
== GL_TEXTURE_CUBE_MAP
) {
620 /* need to update dstTexImage pointer for the cube face */
621 assert(dstZ
+ i
< MAX_FACES
);
622 dstTexImage
= dstTexImage
->TexObject
->Image
[dstZ
+ i
][dstLevel
];
627 ctx
->Driver
.CopyImageSubData(ctx
,
628 srcTexImage
, srcRenderbuffer
,
630 dstTexImage
, dstRenderbuffer
,
632 srcWidth
, srcHeight
);