1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2014 Intel Corporation. All Rights Reserved.
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
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.
23 *
24 * Authors:
25 * Jason Ekstrand <jason.ekstrand@intel.com>
26 */
27
28 #include "context.h"
29 #include "glheader.h"
30 #include "errors.h"
31 #include "enums.h"
32 #include "copyimage.h"
33 #include "teximage.h"
34 #include "texobj.h"
35 #include "fbobject.h"
36 #include "textureview.h"
37 #include "glformats.h"
38
39 enum mesa_block_class {
40 BLOCK_CLASS_128_BITS,
41 BLOCK_CLASS_64_BITS
42 };
43
44 /**
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.
49 *
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
58 */
59 static bool
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,GLuint * width,GLuint * height,GLuint * num_samples,const char * dbg_prefix)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,
64 mesa_format *format,
65 GLenum *internalFormat,
66 GLuint *width,
67 GLuint *height,
68 GLuint *num_samples,
69 const char *dbg_prefix)
70 {
71 if (name == 0) {
72 _mesa_error(ctx, GL_INVALID_VALUE,
73 "glCopyImageSubData(%sName = %d)", dbg_prefix, name);
74 return false;
75 }
76
77 /*
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,
83 */
84 switch (target) {
85 case GL_RENDERBUFFER:
86 /* Not a texture target, but valid */
87 case GL_TEXTURE_1D:
88 case GL_TEXTURE_1D_ARRAY:
89 case GL_TEXTURE_2D:
90 case GL_TEXTURE_3D:
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 */
98 break;
99 case GL_TEXTURE_EXTERNAL_OES:
100 /* Only exists in ES */
101 case GL_TEXTURE_BUFFER:
102 default:
103 _mesa_error(ctx, GL_INVALID_ENUM,
104 "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
105 _mesa_enum_to_string(target));
106 return false;
107 }
108
109 if (target == GL_RENDERBUFFER) {
110 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
111
112 if (!rb) {
113 _mesa_error(ctx, GL_INVALID_VALUE,
114 "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
115 return false;
116 }
117
118 if (!rb->Name) {
119 _mesa_error(ctx, GL_INVALID_OPERATION,
120 "glCopyImageSubData(%sName incomplete)", dbg_prefix);
121 return false;
122 }
123
124 if (level != 0) {
125 _mesa_error(ctx, GL_INVALID_VALUE,
126 "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
127 return false;
128 }
129
130 *renderbuffer = rb;
131 *format = rb->Format;
132 *internalFormat = rb->InternalFormat;
133 *width = rb->Width;
134 *height = rb->Height;
135 *num_samples = rb->NumSamples;
136 *tex_image = NULL;
137 } else {
138 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
139
140 if (!texObj) {
141 /*
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."
146 */
147 _mesa_error(ctx, GL_INVALID_VALUE,
148 "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
149 return false;
150 }
151
152 _mesa_test_texobj_completeness(ctx, texObj);
153 if (!texObj->_BaseComplete ||
154 (level != 0 && !texObj->_MipmapComplete)) {
155 _mesa_error(ctx, GL_INVALID_OPERATION,
156 "glCopyImageSubData(%sName incomplete)", dbg_prefix);
157 return false;
158 }
159
160 /* Note that target will not be a cube face name */
161 if (texObj->Target != target) {
162 /*
163 * From GL_ARB_copy_image_specification:
164 * "INVALID_ENUM is generated if the target does not match the type
165 * of the object."
166 */
167 _mesa_error(ctx, GL_INVALID_ENUM,
168 "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
169 _mesa_enum_to_string(target));
170 return false;
171 }
172
173 if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
174 _mesa_error(ctx, GL_INVALID_VALUE,
175 "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level);
176 return false;
177 }
178
179 if (target == GL_TEXTURE_CUBE_MAP) {
180 int i;
181
182 assert(z < MAX_FACES); /* should have been caught earlier */
183
184 /* make sure all the cube faces are present */
185 for (i = 0; i < depth; i++) {
186 if (!texObj->Image[z+i][level]) {
187 /* missing cube face */
188 _mesa_error(ctx, GL_INVALID_VALUE,
189 "glCopyImageSubData(missing cube face)");
190 return false;
191 }
192 }
193
194 *tex_image = texObj->Image[z][level];
195 }
196 else {
197 *tex_image = _mesa_select_tex_image(texObj, target, level);
198 }
199
200 if (!*tex_image) {
201 _mesa_error(ctx, GL_INVALID_VALUE,
202 "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
203 return false;
204 }
205
206 *renderbuffer = NULL;
207 *format = (*tex_image)->TexFormat;
208 *internalFormat = (*tex_image)->InternalFormat;
209 *width = (*tex_image)->Width;
210 *height = (*tex_image)->Height;
211 *num_samples = (*tex_image)->NumSamples;
212 }
213
214 return true;
215 }
216
217
218 /**
219 * Check that the x,y,z,width,height,region is within the texture image
220 * dimensions.
221 * \return true if bounds OK, false if regions is out of bounds
222 */
223 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)224 check_region_bounds(struct gl_context *ctx,
225 GLenum target,
226 const struct gl_texture_image *tex_image,
227 const struct gl_renderbuffer *renderbuffer,
228 int x, int y, int z, int width, int height, int depth,
229 const char *dbg_prefix)
230 {
231 int surfWidth, surfHeight, surfDepth;
232
233 if (width < 0 || height < 0 || depth < 0) {
234 _mesa_error(ctx, GL_INVALID_VALUE,
235 "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
236 dbg_prefix, dbg_prefix, dbg_prefix);
237 return false;
238 }
239
240 if (x < 0 || y < 0 || z < 0) {
241 _mesa_error(ctx, GL_INVALID_VALUE,
242 "glCopyImageSubData(%sX, %sY, or %sZ is negative)",
243 dbg_prefix, dbg_prefix, dbg_prefix);
244 return false;
245 }
246
247 /* Check X direction */
248 if (target == GL_RENDERBUFFER) {
249 surfWidth = renderbuffer->Width;
250 }
251 else {
252 surfWidth = tex_image->Width;
253 }
254
255 if (x + width > surfWidth) {
256 _mesa_error(ctx, GL_INVALID_VALUE,
257 "glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
258 dbg_prefix, dbg_prefix);
259 return false;
260 }
261
262 /* Check Y direction */
263 switch (target) {
264 case GL_RENDERBUFFER:
265 surfHeight = renderbuffer->Height;
266 break;
267 case GL_TEXTURE_1D:
268 case GL_TEXTURE_1D_ARRAY:
269 surfHeight = 1;
270 break;
271 default:
272 surfHeight = tex_image->Height;
273 }
274
275 if (y + height > surfHeight) {
276 _mesa_error(ctx, GL_INVALID_VALUE,
277 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
278 dbg_prefix, dbg_prefix);
279 return false;
280 }
281
282 /* Check Z direction */
283 switch (target) {
284 case GL_RENDERBUFFER:
285 case GL_TEXTURE_1D:
286 case GL_TEXTURE_2D:
287 case GL_TEXTURE_2D_MULTISAMPLE:
288 case GL_TEXTURE_RECTANGLE:
289 surfDepth = 1;
290 break;
291 case GL_TEXTURE_CUBE_MAP:
292 surfDepth = 6;
293 break;
294 case GL_TEXTURE_1D_ARRAY:
295 surfDepth = tex_image->Height;
296 break;
297 default:
298 surfDepth = tex_image->Depth;
299 }
300
301 if (z < 0 || z + depth > surfDepth) {
302 _mesa_error(ctx, GL_INVALID_VALUE,
303 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
304 dbg_prefix, dbg_prefix);
305 return false;
306 }
307
308 return true;
309 }
310
311 static bool
compressed_format_compatible(const struct gl_context * ctx,GLenum compressedFormat,GLenum otherFormat)312 compressed_format_compatible(const struct gl_context *ctx,
313 GLenum compressedFormat, GLenum otherFormat)
314 {
315 enum mesa_block_class compressedClass, otherClass;
316
317 /* Two view-incompatible compressed formats are never compatible. */
318 if (_mesa_is_compressed_format(ctx, otherFormat)) {
319 return false;
320 }
321
322 /*
323 * From ARB_copy_image spec:
324 * Table 4.X.1 (Compatible internal formats for copying between
325 * compressed and uncompressed internal formats)
326 * ---------------------------------------------------------------------
327 * | Texel / | Uncompressed | |
328 * | Block | internal format | Compressed internal format |
329 * | size | | |
330 * ---------------------------------------------------------------------
331 * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, |
332 * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
333 * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, |
334 * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
335 * | | | COMPRESSED_RG_RGTC2, |
336 * | | | COMPRESSED_SIGNED_RG_RGTC2, |
337 * | | | COMPRESSED_RGBA_BPTC_UNORM, |
338 * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, |
339 * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, |
340 * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT |
341 * ---------------------------------------------------------------------
342 * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, |
343 * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, |
344 * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, |
345 * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
346 * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, |
347 * | | | COMPRESSED_SIGNED_RED_RGTC1 |
348 * ---------------------------------------------------------------------
349 */
350
351 switch (compressedFormat) {
352 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
353 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
354 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
355 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
356 case GL_COMPRESSED_RG_RGTC2:
357 case GL_COMPRESSED_SIGNED_RG_RGTC2:
358 case GL_COMPRESSED_RGBA_BPTC_UNORM:
359 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
360 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
361 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
362 compressedClass = BLOCK_CLASS_128_BITS;
363 break;
364 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
365 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
366 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
367 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
368 case GL_COMPRESSED_RED_RGTC1:
369 case GL_COMPRESSED_SIGNED_RED_RGTC1:
370 compressedClass = BLOCK_CLASS_64_BITS;
371 break;
372 case GL_COMPRESSED_RGBA8_ETC2_EAC:
373 case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
374 case GL_COMPRESSED_RG11_EAC:
375 case GL_COMPRESSED_SIGNED_RG11_EAC:
376 if (_mesa_is_gles(ctx))
377 compressedClass = BLOCK_CLASS_128_BITS;
378 else
379 return false;
380 break;
381 case GL_COMPRESSED_RGB8_ETC2:
382 case GL_COMPRESSED_SRGB8_ETC2:
383 case GL_COMPRESSED_R11_EAC:
384 case GL_COMPRESSED_SIGNED_R11_EAC:
385 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
386 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
387 if (_mesa_is_gles(ctx))
388 compressedClass = BLOCK_CLASS_64_BITS;
389 else
390 return false;
391 break;
392 default:
393 if (_mesa_is_gles(ctx) && _mesa_is_astc_format(compressedFormat))
394 compressedClass = BLOCK_CLASS_128_BITS;
395 else
396 return false;
397 break;
398 }
399
400 switch (otherFormat) {
401 case GL_RGBA32UI:
402 case GL_RGBA32I:
403 case GL_RGBA32F:
404 otherClass = BLOCK_CLASS_128_BITS;
405 break;
406 case GL_RGBA16F:
407 case GL_RG32F:
408 case GL_RGBA16UI:
409 case GL_RG32UI:
410 case GL_RGBA16I:
411 case GL_RG32I:
412 case GL_RGBA16:
413 case GL_RGBA16_SNORM:
414 otherClass = BLOCK_CLASS_64_BITS;
415 break;
416 default:
417 return false;
418 }
419
420 return compressedClass == otherClass;
421 }
422
423 static bool
copy_format_compatible(const struct gl_context * ctx,GLenum srcFormat,GLenum dstFormat)424 copy_format_compatible(const struct gl_context *ctx,
425 GLenum srcFormat, GLenum dstFormat)
426 {
427 /*
428 * From ARB_copy_image spec:
429 * For the purposes of CopyImageSubData, two internal formats
430 * are considered compatible if any of the following conditions are
431 * met:
432 * * the formats are the same,
433 * * the formats are considered compatible according to the
434 * compatibility rules used for texture views as defined in
435 * section 3.9.X. In particular, if both internal formats are listed
436 * in the same entry of Table 3.X.2, they are considered compatible, or
437 * * one format is compressed and the other is uncompressed and
438 * Table 4.X.1 lists the two formats in the same row.
439 */
440
441 if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) {
442 /* Also checks if formats are equal. */
443 return true;
444 } else if (_mesa_is_compressed_format(ctx, srcFormat)) {
445 return compressed_format_compatible(ctx, srcFormat, dstFormat);
446 } else if (_mesa_is_compressed_format(ctx, dstFormat)) {
447 return compressed_format_compatible(ctx, dstFormat, srcFormat);
448 }
449
450 return false;
451 }
452
453 void GLAPIENTRY
_mesa_CopyImageSubData(GLuint srcName,GLenum srcTarget,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLuint dstName,GLenum dstTarget,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)454 _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,
455 GLint srcX, GLint srcY, GLint srcZ,
456 GLuint dstName, GLenum dstTarget, GLint dstLevel,
457 GLint dstX, GLint dstY, GLint dstZ,
458 GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
459 {
460 GET_CURRENT_CONTEXT(ctx);
461 struct gl_texture_image *srcTexImage, *dstTexImage;
462 struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
463 mesa_format srcFormat, dstFormat;
464 GLenum srcIntFormat, dstIntFormat;
465 GLuint src_w, src_h, dst_w, dst_h;
466 GLuint src_bw, src_bh, dst_bw, dst_bh;
467 GLuint src_num_samples, dst_num_samples;
468 int dstWidth, dstHeight, dstDepth;
469 int i;
470
471 if (MESA_VERBOSE & VERBOSE_API)
472 _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
473 "%u, %s, %d, %d, %d, %d, "
474 "%d, %d, %d)\n",
475 srcName, _mesa_enum_to_string(srcTarget), srcLevel,
476 srcX, srcY, srcZ,
477 dstName, _mesa_enum_to_string(dstTarget), dstLevel,
478 dstX, dstY, dstZ,
479 srcWidth, srcHeight, srcDepth);
480
481 if (!ctx->Extensions.ARB_copy_image) {
482 _mesa_error(ctx, GL_INVALID_OPERATION,
483 "glCopyImageSubData(extension not available)");
484 return;
485 }
486
487 if (!prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth,
488 &srcTexImage, &srcRenderbuffer, &srcFormat,
489 &srcIntFormat, &src_w, &src_h, &src_num_samples, "src"))
490 return;
491
492 if (!prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth,
493 &dstTexImage, &dstRenderbuffer, &dstFormat,
494 &dstIntFormat, &dst_w, &dst_h, &dst_num_samples, "dst"))
495 return;
496
497 _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh);
498
499 /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
500 * spec says:
501 *
502 * An INVALID_VALUE error is generated if the dimensions of either
503 * subregion exceeds the boundaries of the corresponding image object,
504 * or if the image format is compressed and the dimensions of the
505 * subregion fail to meet the alignment constraints of the format.
506 *
507 * and Section 8.7 (Compressed Texture Images) says:
508 *
509 * An INVALID_OPERATION error is generated if any of the following
510 * conditions occurs:
511 *
512 * * width is not a multiple of four, and width + xoffset is not
513 * equal to the value of TEXTURE_WIDTH.
514 * * height is not a multiple of four, and height + yoffset is not
515 * equal to the value of TEXTURE_HEIGHT.
516 *
517 * so we take that to mean that you can copy the "last" block of a
518 * compressed texture image even if it's smaller than the minimum block
519 * dimensions.
520 */
521 if ((srcX % src_bw != 0) || (srcY % src_bh != 0) ||
522 (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) ||
523 (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) {
524 _mesa_error(ctx, GL_INVALID_VALUE,
525 "glCopyImageSubData(unaligned src rectangle)");
526 return;
527 }
528
529 _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh);
530 if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) {
531 _mesa_error(ctx, GL_INVALID_VALUE,
532 "glCopyImageSubData(unaligned dst rectangle)");
533 return;
534 }
535
536 /* From the GL_ARB_copy_image spec:
537 *
538 * "The dimensions are always specified in texels, even for compressed
539 * texture formats. But it should be noted that if only one of the
540 * source and destination textures is compressed then the number of
541 * texels touched in the compressed image will be a factor of the
542 * block size larger than in the uncompressed image."
543 *
544 * So, if copying from compressed to uncompressed, the dest region is
545 * shrunk by the src block size factor. If copying from uncompressed
546 * to compressed, the dest region is grown by the dest block size factor.
547 * Note that we're passed the _source_ width, height, depth and those
548 * dimensions are never changed.
549 */
550 dstWidth = srcWidth * dst_bw / src_bw;
551 dstHeight = srcHeight * dst_bh / src_bh;
552 dstDepth = srcDepth;
553
554 if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer,
555 srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth,
556 "src"))
557 return;
558
559 if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer,
560 dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth,
561 "dst"))
562 return;
563
564 /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
565 * spec says:
566 *
567 * An INVALID_OPERATION error is generated if either object is a texture
568 * and the texture is not complete, if the source and destination internal
569 * formats are not compatible, or if the number of samples do not match.
570 */
571 if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) {
572 _mesa_error(ctx, GL_INVALID_OPERATION,
573 "glCopyImageSubData(internalFormat mismatch)");
574 return;
575 }
576
577 if (src_num_samples != dst_num_samples) {
578 _mesa_error(ctx, GL_INVALID_OPERATION,
579 "glCopyImageSubData(number of samples mismatch)");
580 return;
581 }
582
583 /* loop over 2D slices/faces/layers */
584 for (i = 0; i < srcDepth; ++i) {
585 int newSrcZ = srcZ + i;
586 int newDstZ = dstZ + i;
587
588 if (srcTexImage &&
589 srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
590 /* need to update srcTexImage pointer for the cube face */
591 assert(srcZ + i < MAX_FACES);
592 srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel];
593 assert(srcTexImage);
594 newSrcZ = 0;
595 }
596
597 if (dstTexImage &&
598 dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
599 /* need to update dstTexImage pointer for the cube face */
600 assert(dstZ + i < MAX_FACES);
601 dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel];
602 assert(dstTexImage);
603 newDstZ = 0;
604 }
605
606 ctx->Driver.CopyImageSubData(ctx,
607 srcTexImage, srcRenderbuffer,
608 srcX, srcY, newSrcZ,
609 dstTexImage, dstRenderbuffer,
610 dstX, dstY, newDstZ,
611 srcWidth, srcHeight);
612 }
613 }
614