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
39enum 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 */
59static bool
60prepare_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 */
223static bool
224check_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
311static bool
312compressed_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
423static bool
424copy_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
453void GLAPIENTRY
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