mesa: add copy_texture_sub_image_no_error() helper
[mesa.git] / src / mesa / main / copyimage.c
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
60 prepare_target_err(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 static void
218 prepare_target(struct gl_context *ctx, GLuint name, GLenum target,
219 int level, int z,
220 struct gl_texture_image **texImage,
221 struct gl_renderbuffer **renderbuffer)
222 {
223 if (target == GL_RENDERBUFFER) {
224 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
225
226 *renderbuffer = rb;
227 *texImage = NULL;
228 } else {
229 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
230
231 if (target == GL_TEXTURE_CUBE_MAP) {
232 *texImage = texObj->Image[z][level];
233 }
234 else {
235 *texImage = _mesa_select_tex_image(texObj, target, level);
236 }
237
238 *renderbuffer = NULL;
239 }
240 }
241
242 /**
243 * Check that the x,y,z,width,height,region is within the texture image
244 * dimensions.
245 * \return true if bounds OK, false if regions is out of bounds
246 */
247 static bool
248 check_region_bounds(struct gl_context *ctx,
249 GLenum target,
250 const struct gl_texture_image *tex_image,
251 const struct gl_renderbuffer *renderbuffer,
252 int x, int y, int z, int width, int height, int depth,
253 const char *dbg_prefix)
254 {
255 int surfWidth, surfHeight, surfDepth;
256
257 if (width < 0 || height < 0 || depth < 0) {
258 _mesa_error(ctx, GL_INVALID_VALUE,
259 "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
260 dbg_prefix, dbg_prefix, dbg_prefix);
261 return false;
262 }
263
264 if (x < 0 || y < 0 || z < 0) {
265 _mesa_error(ctx, GL_INVALID_VALUE,
266 "glCopyImageSubData(%sX, %sY, or %sZ is negative)",
267 dbg_prefix, dbg_prefix, dbg_prefix);
268 return false;
269 }
270
271 /* Check X direction */
272 if (target == GL_RENDERBUFFER) {
273 surfWidth = renderbuffer->Width;
274 }
275 else {
276 surfWidth = tex_image->Width;
277 }
278
279 if (x + width > surfWidth) {
280 _mesa_error(ctx, GL_INVALID_VALUE,
281 "glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
282 dbg_prefix, dbg_prefix);
283 return false;
284 }
285
286 /* Check Y direction */
287 switch (target) {
288 case GL_RENDERBUFFER:
289 surfHeight = renderbuffer->Height;
290 break;
291 case GL_TEXTURE_1D:
292 case GL_TEXTURE_1D_ARRAY:
293 surfHeight = 1;
294 break;
295 default:
296 surfHeight = tex_image->Height;
297 }
298
299 if (y + height > surfHeight) {
300 _mesa_error(ctx, GL_INVALID_VALUE,
301 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
302 dbg_prefix, dbg_prefix);
303 return false;
304 }
305
306 /* Check Z direction */
307 switch (target) {
308 case GL_RENDERBUFFER:
309 case GL_TEXTURE_1D:
310 case GL_TEXTURE_2D:
311 case GL_TEXTURE_2D_MULTISAMPLE:
312 case GL_TEXTURE_RECTANGLE:
313 surfDepth = 1;
314 break;
315 case GL_TEXTURE_CUBE_MAP:
316 surfDepth = 6;
317 break;
318 case GL_TEXTURE_1D_ARRAY:
319 surfDepth = tex_image->Height;
320 break;
321 default:
322 surfDepth = tex_image->Depth;
323 }
324
325 if (z < 0 || z + depth > surfDepth) {
326 _mesa_error(ctx, GL_INVALID_VALUE,
327 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
328 dbg_prefix, dbg_prefix);
329 return false;
330 }
331
332 return true;
333 }
334
335 static bool
336 compressed_format_compatible(const struct gl_context *ctx,
337 GLenum compressedFormat, GLenum otherFormat)
338 {
339 enum mesa_block_class compressedClass, otherClass;
340
341 /* Two view-incompatible compressed formats are never compatible. */
342 if (_mesa_is_compressed_format(ctx, otherFormat)) {
343 return false;
344 }
345
346 /*
347 * From ARB_copy_image spec:
348 * Table 4.X.1 (Compatible internal formats for copying between
349 * compressed and uncompressed internal formats)
350 * ---------------------------------------------------------------------
351 * | Texel / | Uncompressed | |
352 * | Block | internal format | Compressed internal format |
353 * | size | | |
354 * ---------------------------------------------------------------------
355 * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, |
356 * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
357 * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, |
358 * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
359 * | | | COMPRESSED_RG_RGTC2, |
360 * | | | COMPRESSED_SIGNED_RG_RGTC2, |
361 * | | | COMPRESSED_RGBA_BPTC_UNORM, |
362 * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, |
363 * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, |
364 * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT |
365 * ---------------------------------------------------------------------
366 * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, |
367 * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, |
368 * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, |
369 * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
370 * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, |
371 * | | | COMPRESSED_SIGNED_RED_RGTC1 |
372 * ---------------------------------------------------------------------
373 */
374
375 switch (compressedFormat) {
376 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
377 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
378 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
379 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
380 case GL_COMPRESSED_RG_RGTC2:
381 case GL_COMPRESSED_SIGNED_RG_RGTC2:
382 case GL_COMPRESSED_RGBA_BPTC_UNORM:
383 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
384 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
385 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
386 compressedClass = BLOCK_CLASS_128_BITS;
387 break;
388 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
389 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
390 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
391 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
392 case GL_COMPRESSED_RED_RGTC1:
393 case GL_COMPRESSED_SIGNED_RED_RGTC1:
394 compressedClass = BLOCK_CLASS_64_BITS;
395 break;
396 case GL_COMPRESSED_RGBA8_ETC2_EAC:
397 case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
398 case GL_COMPRESSED_RG11_EAC:
399 case GL_COMPRESSED_SIGNED_RG11_EAC:
400 if (_mesa_is_gles(ctx))
401 compressedClass = BLOCK_CLASS_128_BITS;
402 else
403 return false;
404 break;
405 case GL_COMPRESSED_RGB8_ETC2:
406 case GL_COMPRESSED_SRGB8_ETC2:
407 case GL_COMPRESSED_R11_EAC:
408 case GL_COMPRESSED_SIGNED_R11_EAC:
409 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
410 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
411 if (_mesa_is_gles(ctx))
412 compressedClass = BLOCK_CLASS_64_BITS;
413 else
414 return false;
415 break;
416 default:
417 if (_mesa_is_gles(ctx) && _mesa_is_astc_format(compressedFormat))
418 compressedClass = BLOCK_CLASS_128_BITS;
419 else
420 return false;
421 break;
422 }
423
424 switch (otherFormat) {
425 case GL_RGBA32UI:
426 case GL_RGBA32I:
427 case GL_RGBA32F:
428 otherClass = BLOCK_CLASS_128_BITS;
429 break;
430 case GL_RGBA16F:
431 case GL_RG32F:
432 case GL_RGBA16UI:
433 case GL_RG32UI:
434 case GL_RGBA16I:
435 case GL_RG32I:
436 case GL_RGBA16:
437 case GL_RGBA16_SNORM:
438 otherClass = BLOCK_CLASS_64_BITS;
439 break;
440 default:
441 return false;
442 }
443
444 return compressedClass == otherClass;
445 }
446
447 static bool
448 copy_format_compatible(const struct gl_context *ctx,
449 GLenum srcFormat, GLenum dstFormat)
450 {
451 /*
452 * From ARB_copy_image spec:
453 * For the purposes of CopyImageSubData, two internal formats
454 * are considered compatible if any of the following conditions are
455 * met:
456 * * the formats are the same,
457 * * the formats are considered compatible according to the
458 * compatibility rules used for texture views as defined in
459 * section 3.9.X. In particular, if both internal formats are listed
460 * in the same entry of Table 3.X.2, they are considered compatible, or
461 * * one format is compressed and the other is uncompressed and
462 * Table 4.X.1 lists the two formats in the same row.
463 */
464
465 if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) {
466 /* Also checks if formats are equal. */
467 return true;
468 } else if (_mesa_is_compressed_format(ctx, srcFormat)) {
469 return compressed_format_compatible(ctx, srcFormat, dstFormat);
470 } else if (_mesa_is_compressed_format(ctx, dstFormat)) {
471 return compressed_format_compatible(ctx, dstFormat, srcFormat);
472 }
473
474 return false;
475 }
476
477 static void
478 copy_image_subdata(struct gl_context *ctx,
479 struct gl_texture_image *srcTexImage,
480 struct gl_renderbuffer *srcRenderbuffer,
481 int srcX, int srcY, int srcZ, int srcLevel,
482 struct gl_texture_image *dstTexImage,
483 struct gl_renderbuffer *dstRenderbuffer,
484 int dstX, int dstY, int dstZ, int dstLevel,
485 int srcWidth, int srcHeight, int srcDepth)
486 {
487 /* loop over 2D slices/faces/layers */
488 for (int i = 0; i < srcDepth; ++i) {
489 int newSrcZ = srcZ + i;
490 int newDstZ = dstZ + i;
491
492 if (srcTexImage &&
493 srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
494 /* need to update srcTexImage pointer for the cube face */
495 assert(srcZ + i < MAX_FACES);
496 srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel];
497 assert(srcTexImage);
498 newSrcZ = 0;
499 }
500
501 if (dstTexImage &&
502 dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
503 /* need to update dstTexImage pointer for the cube face */
504 assert(dstZ + i < MAX_FACES);
505 dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel];
506 assert(dstTexImage);
507 newDstZ = 0;
508 }
509
510 ctx->Driver.CopyImageSubData(ctx,
511 srcTexImage, srcRenderbuffer,
512 srcX, srcY, newSrcZ,
513 dstTexImage, dstRenderbuffer,
514 dstX, dstY, newDstZ,
515 srcWidth, srcHeight);
516 }
517 }
518
519 void GLAPIENTRY
520 _mesa_CopyImageSubData_no_error(GLuint srcName, GLenum srcTarget, GLint srcLevel,
521 GLint srcX, GLint srcY, GLint srcZ,
522 GLuint dstName, GLenum dstTarget, GLint dstLevel,
523 GLint dstX, GLint dstY, GLint dstZ,
524 GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
525 {
526 struct gl_texture_image *srcTexImage, *dstTexImage;
527 struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
528
529 GET_CURRENT_CONTEXT(ctx);
530
531 prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, &srcTexImage,
532 &srcRenderbuffer);
533
534 prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, &dstTexImage,
535 &dstRenderbuffer);
536
537 copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ,
538 srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ,
539 dstLevel, srcWidth, srcHeight, srcDepth);
540 }
541
542 void GLAPIENTRY
543 _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,
544 GLint srcX, GLint srcY, GLint srcZ,
545 GLuint dstName, GLenum dstTarget, GLint dstLevel,
546 GLint dstX, GLint dstY, GLint dstZ,
547 GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
548 {
549 GET_CURRENT_CONTEXT(ctx);
550 struct gl_texture_image *srcTexImage, *dstTexImage;
551 struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
552 mesa_format srcFormat, dstFormat;
553 GLenum srcIntFormat, dstIntFormat;
554 GLuint src_w, src_h, dst_w, dst_h;
555 GLuint src_bw, src_bh, dst_bw, dst_bh;
556 GLuint src_num_samples, dst_num_samples;
557 int dstWidth, dstHeight, dstDepth;
558
559 if (MESA_VERBOSE & VERBOSE_API)
560 _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
561 "%u, %s, %d, %d, %d, %d, "
562 "%d, %d, %d)\n",
563 srcName, _mesa_enum_to_string(srcTarget), srcLevel,
564 srcX, srcY, srcZ,
565 dstName, _mesa_enum_to_string(dstTarget), dstLevel,
566 dstX, dstY, dstZ,
567 srcWidth, srcHeight, srcDepth);
568
569 if (!ctx->Extensions.ARB_copy_image) {
570 _mesa_error(ctx, GL_INVALID_OPERATION,
571 "glCopyImageSubData(extension not available)");
572 return;
573 }
574
575 if (!prepare_target_err(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth,
576 &srcTexImage, &srcRenderbuffer, &srcFormat,
577 &srcIntFormat, &src_w, &src_h, &src_num_samples,
578 "src"))
579 return;
580
581 if (!prepare_target_err(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth,
582 &dstTexImage, &dstRenderbuffer, &dstFormat,
583 &dstIntFormat, &dst_w, &dst_h, &dst_num_samples,
584 "dst"))
585 return;
586
587 _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh);
588
589 /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
590 * spec says:
591 *
592 * An INVALID_VALUE error is generated if the dimensions of either
593 * subregion exceeds the boundaries of the corresponding image object,
594 * or if the image format is compressed and the dimensions of the
595 * subregion fail to meet the alignment constraints of the format.
596 *
597 * and Section 8.7 (Compressed Texture Images) says:
598 *
599 * An INVALID_OPERATION error is generated if any of the following
600 * conditions occurs:
601 *
602 * * width is not a multiple of four, and width + xoffset is not
603 * equal to the value of TEXTURE_WIDTH.
604 * * height is not a multiple of four, and height + yoffset is not
605 * equal to the value of TEXTURE_HEIGHT.
606 *
607 * so we take that to mean that you can copy the "last" block of a
608 * compressed texture image even if it's smaller than the minimum block
609 * dimensions.
610 */
611 if ((srcX % src_bw != 0) || (srcY % src_bh != 0) ||
612 (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) ||
613 (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) {
614 _mesa_error(ctx, GL_INVALID_VALUE,
615 "glCopyImageSubData(unaligned src rectangle)");
616 return;
617 }
618
619 _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh);
620 if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) {
621 _mesa_error(ctx, GL_INVALID_VALUE,
622 "glCopyImageSubData(unaligned dst rectangle)");
623 return;
624 }
625
626 /* From the GL_ARB_copy_image spec:
627 *
628 * "The dimensions are always specified in texels, even for compressed
629 * texture formats. But it should be noted that if only one of the
630 * source and destination textures is compressed then the number of
631 * texels touched in the compressed image will be a factor of the
632 * block size larger than in the uncompressed image."
633 *
634 * So, if copying from compressed to uncompressed, the dest region is
635 * shrunk by the src block size factor. If copying from uncompressed
636 * to compressed, the dest region is grown by the dest block size factor.
637 * Note that we're passed the _source_ width, height, depth and those
638 * dimensions are never changed.
639 */
640 dstWidth = srcWidth * dst_bw / src_bw;
641 dstHeight = srcHeight * dst_bh / src_bh;
642 dstDepth = srcDepth;
643
644 if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer,
645 srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth,
646 "src"))
647 return;
648
649 if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer,
650 dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth,
651 "dst"))
652 return;
653
654 /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
655 * spec says:
656 *
657 * An INVALID_OPERATION error is generated if either object is a texture
658 * and the texture is not complete, if the source and destination internal
659 * formats are not compatible, or if the number of samples do not match.
660 */
661 if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) {
662 _mesa_error(ctx, GL_INVALID_OPERATION,
663 "glCopyImageSubData(internalFormat mismatch)");
664 return;
665 }
666
667 if (src_num_samples != dst_num_samples) {
668 _mesa_error(ctx, GL_INVALID_OPERATION,
669 "glCopyImageSubData(number of samples mismatch)");
670 return;
671 }
672
673 copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ,
674 srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ,
675 dstLevel, srcWidth, srcHeight, srcDepth);
676 }