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