xref: /aosp_15_r20/external/mesa3d/src/mesa/main/copyimage.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 
25 #include "context.h"
26 #include "util/glheader.h"
27 #include "errors.h"
28 #include "enums.h"
29 #include "teximage.h"
30 #include "texobj.h"
31 #include "fbobject.h"
32 #include "textureview.h"
33 #include "glformats.h"
34 #include "api_exec_decl.h"
35 
36 #include "state_tracker/st_cb_copyimage.h"
37 
38 enum mesa_block_class {
39    BLOCK_CLASS_128_BITS,
40    BLOCK_CLASS_64_BITS
41 };
42 
43 /**
44  * Prepare the source or destination resource.  This involves error
45  * checking and returning the relevant gl_texture_image or gl_renderbuffer.
46  * Note that one of the resulting tex_image or renderbuffer pointers will be
47  * NULL and the other will be non-null.
48  *
49  * \param name  the texture or renderbuffer name
50  * \param target  One of GL_TEXTURE_x target or GL_RENDERBUFFER
51  * \param level  mipmap level
52  * \param z  src or dest Z
53  * \param depth  number of slices/faces/layers to copy
54  * \param tex_image  returns a pointer to a texture image
55  * \param renderbuffer  returns a pointer to a renderbuffer
56  * \return true if success, false if error
57  */
58 static bool
prepare_target_err(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,bool is_arb_version)59 prepare_target_err(struct gl_context *ctx, GLuint name, GLenum target,
60                    int level, int z, int depth,
61                    struct gl_texture_image **tex_image,
62                    struct gl_renderbuffer **renderbuffer,
63                    mesa_format *format,
64                    GLenum *internalFormat,
65                    GLuint *width,
66                    GLuint *height,
67                    GLuint *num_samples,
68                    const char *dbg_prefix,
69                    bool is_arb_version)
70 {
71    const char *suffix = is_arb_version ? "" : "NV";
72 
73    if (name == 0) {
74       _mesa_error(ctx, GL_INVALID_VALUE,
75                   "glCopyImageSubData%s(%sName = %d)", suffix, dbg_prefix, name);
76       return false;
77    }
78 
79    /*
80     * INVALID_ENUM is generated
81     *  * if either <srcTarget> or <dstTarget>
82     *   - is not RENDERBUFFER or a valid non-proxy texture target
83     *   - is TEXTURE_BUFFER, or
84     *   - is one of the cubemap face selectors described in table 3.17,
85     */
86    switch (target) {
87    case GL_RENDERBUFFER:
88       /* Not a texture target, but valid */
89    case GL_TEXTURE_1D:
90    case GL_TEXTURE_1D_ARRAY:
91    case GL_TEXTURE_2D:
92    case GL_TEXTURE_3D:
93    case GL_TEXTURE_CUBE_MAP:
94    case GL_TEXTURE_RECTANGLE:
95    case GL_TEXTURE_2D_ARRAY:
96    case GL_TEXTURE_CUBE_MAP_ARRAY:
97    case GL_TEXTURE_2D_MULTISAMPLE:
98    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
99       /* These are all valid */
100       break;
101    case GL_TEXTURE_EXTERNAL_OES:
102       /* Only exists in ES */
103       if (_mesa_is_gles(ctx))
104          break;
105       FALLTHROUGH;
106    case GL_TEXTURE_BUFFER:
107    default:
108       _mesa_error(ctx, GL_INVALID_ENUM,
109                   "glCopyImageSubData%s(%sTarget = %s)", suffix, dbg_prefix,
110                   _mesa_enum_to_string(target));
111       return false;
112    }
113 
114    if (target == GL_RENDERBUFFER) {
115       struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
116 
117       if (!rb) {
118          _mesa_error(ctx, GL_INVALID_VALUE,
119                      "glCopyImageSubData%s(%sName = %u)", suffix, dbg_prefix, name);
120          return false;
121       }
122 
123       if (!rb->Name) {
124          _mesa_error(ctx, GL_INVALID_OPERATION,
125                      "glCopyImageSubData%s(%sName incomplete)", suffix, dbg_prefix);
126          return false;
127       }
128 
129       if (level != 0) {
130          _mesa_error(ctx, GL_INVALID_VALUE,
131                      "glCopyImageSubData%s(%sLevel = %u)", suffix, dbg_prefix, level);
132          return false;
133       }
134 
135       *renderbuffer = rb;
136       *format = rb->Format;
137       *internalFormat = rb->InternalFormat;
138       *width = rb->Width;
139       *height = rb->Height;
140       *num_samples = rb->NumSamples;
141       *tex_image = NULL;
142    } else {
143       struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
144 
145       if (!texObj) {
146          /*
147           * From GL_ARB_copy_image specification:
148           * "INVALID_VALUE is generated if either <srcName> or <dstName> does
149           * not correspond to a valid renderbuffer or texture object according
150           * to the corresponding target parameter."
151           */
152          _mesa_error(ctx, GL_INVALID_VALUE,
153                      "glCopyImageSubData%s(%sName = %u)", suffix, dbg_prefix, name);
154          return false;
155       }
156 
157       /* The ARB_copy_image specification says:
158        *
159        *    "INVALID_OPERATION is generated if either object is a texture and
160        *     the texture is not complete (as defined in section 3.9.14)"
161        *
162        * The cited section says:
163        *
164        *    "Using the preceding definitions, a texture is complete unless any
165        *     of the following conditions hold true: [...]
166        *
167        *     * The minification filter requires a mipmap (is neither NEAREST
168        *       nor LINEAR), and the texture is not mipmap complete."
169        *
170        * This imposes the bizarre restriction that glCopyImageSubData requires
171        * mipmap completion based on the sampler minification filter, even
172        * though the call fundamentally ignores the sampler.  Additionally, it
173        * doesn't work with texture units, so it can't consider any bound
174        * separate sampler objects.  It appears that you're supposed to use
175        * the sampler object which is built-in to the texture object.
176        *
177        * dEQP and the Android CTS mandate this behavior, and the Khronos
178        * GL and ES working groups both affirmed that this is unfortunate but
179        * correct.  See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16224.
180        *
181        * Integer textures with filtering cause another completeness snag:
182        *
183        *    "Any of:
184        *     – The internal format of the texture is integer (see table 8.12).
185        *     – The internal format is STENCIL_INDEX.
186        *     – The internal format is DEPTH_STENCIL, and the value of
187        *       DEPTH_STENCIL_TEXTURE_MODE for the texture is STENCIL_INDEX.
188        *     and either the magnification filter is not NEAREST, or the
189        *     minification filter is neither NEAREST nor
190        *     NEAREST_MIPMAP_NEAREST."
191        *
192        * However, applications in the wild (such as "Total War: WARHAMMER")
193        * appear to call glCopyImageSubData with integer textures and the
194        * default mipmap filters of GL_LINEAR and GL_NEAREST_MIPMAP_LINEAR,
195        * which would be considered incomplete, but expect this to work.  In
196        * fact, until VK-GL-CTS commit fef80039ff875a51806b54d151c5f2d0c12da,
197        * the GL 4.5 CTS contained three tests which did the exact same thing
198        * by accident, and all conformant implementations allowed it.
199        *
200        * A proposal was made to amend the spec to say "is not complete (as
201        * defined in section <X>, but ignoring format-based completeness
202        * rules)" to allow this case.  It makes some sense, given that
203        * glCopyImageSubData copies raw data without considering format.
204        * While the official edits have not yet been made, the OpenGL
205        * working group agreed with the idea of allowing this behavior.
206        *
207        * To ignore formats, we check texObj->_MipmapComplete directly
208        * rather than calling _mesa_is_texture_complete().
209        */
210       _mesa_test_texobj_completeness(ctx, texObj);
211       const bool texture_complete_aside_from_formats =
212          _mesa_is_mipmap_filter(&texObj->Sampler) ? texObj->_MipmapComplete
213                                                   : texObj->_BaseComplete;
214       if (!texture_complete_aside_from_formats) {
215          _mesa_error(ctx, GL_INVALID_OPERATION,
216                      "glCopyImageSubData%s(%sName incomplete)", suffix, dbg_prefix);
217          return false;
218       }
219 
220       /* Note that target will not be a cube face name */
221       if (texObj->Target != target) {
222          /*
223           * From GL_ARB_copy_image_specification:
224           * "INVALID_ENUM is generated if the target does not match the type
225           * of the object."
226           */
227          _mesa_error(ctx, GL_INVALID_ENUM,
228                      "glCopyImageSubData%s(%sTarget = %s)", suffix, dbg_prefix,
229                      _mesa_enum_to_string(target));
230          return false;
231       }
232 
233       if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
234          _mesa_error(ctx, GL_INVALID_VALUE,
235                      "glCopyImageSubData%s(%sLevel = %d)", suffix, dbg_prefix, level);
236          return false;
237       }
238 
239       if (target == GL_TEXTURE_CUBE_MAP) {
240          int i;
241 
242          if (z < 0 || z >= MAX_FACES) {
243             _mesa_error(ctx, GL_INVALID_VALUE,
244                         "glCopyImageSubData(cube face (%sZ = %d)", dbg_prefix, z);
245             return false;
246          }
247 
248          /* make sure all the cube faces are present */
249          for (i = 0; i < depth; i++) {
250             if (!texObj->Image[z+i][level]) {
251                /* missing cube face */
252                _mesa_error(ctx, GL_INVALID_VALUE,
253                            "glCopyImageSubData(missing cube face)");
254                return false;
255             }
256          }
257 
258          *tex_image = texObj->Image[z][level];
259       }
260       else {
261          *tex_image = _mesa_select_tex_image(texObj, target, level);
262       }
263 
264       if (!*tex_image) {
265          _mesa_error(ctx, GL_INVALID_VALUE,
266                      "glCopyImageSubData%s(%sLevel = %u)", suffix, dbg_prefix, level);
267          return false;
268       }
269 
270       *renderbuffer = NULL;
271       *format = (*tex_image)->TexFormat;
272       *internalFormat = (*tex_image)->InternalFormat;
273       *width = (*tex_image)->Width;
274       *height = (*tex_image)->Height;
275       *num_samples = (*tex_image)->NumSamples;
276    }
277 
278    return true;
279 }
280 
281 static void
prepare_target(struct gl_context * ctx,GLuint name,GLenum target,int level,int z,struct gl_texture_image ** texImage,struct gl_renderbuffer ** renderbuffer)282 prepare_target(struct gl_context *ctx, GLuint name, GLenum target,
283                int level, int z,
284                struct gl_texture_image **texImage,
285                struct gl_renderbuffer **renderbuffer)
286 {
287    if (target == GL_RENDERBUFFER) {
288       struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
289 
290       *renderbuffer = rb;
291       *texImage = NULL;
292    } else {
293       struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
294 
295       if (target == GL_TEXTURE_CUBE_MAP) {
296          *texImage = texObj->Image[z][level];
297       }
298       else {
299          *texImage = _mesa_select_tex_image(texObj, target, level);
300       }
301 
302       *renderbuffer = NULL;
303    }
304 }
305 
306 /**
307  * Check that the x,y,z,width,height,region is within the texture image
308  * dimensions.
309  * \return true if bounds OK, false if regions is out of bounds
310  */
311 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,bool is_arb_version)312 check_region_bounds(struct gl_context *ctx,
313                     GLenum target,
314                     const struct gl_texture_image *tex_image,
315                     const struct gl_renderbuffer *renderbuffer,
316                     int x, int y, int z, int width, int height, int depth,
317                     const char *dbg_prefix,
318                     bool is_arb_version)
319 {
320    int surfWidth, surfHeight, surfDepth;
321    const char *suffix = is_arb_version ? "" : "NV";
322 
323    if (width < 0 || height < 0 || depth < 0) {
324       _mesa_error(ctx, GL_INVALID_VALUE,
325                   "glCopyImageSubData%s(%sWidth, %sHeight, or %sDepth is negative)",
326                   suffix, dbg_prefix, dbg_prefix, dbg_prefix);
327       return false;
328    }
329 
330    if (x < 0 || y < 0 || z < 0) {
331       _mesa_error(ctx, GL_INVALID_VALUE,
332                   "glCopyImageSubData%s(%sX, %sY, or %sZ is negative)",
333                   suffix, dbg_prefix, dbg_prefix, dbg_prefix);
334       return false;
335    }
336 
337    /* Check X direction */
338    if (target == GL_RENDERBUFFER) {
339       surfWidth = renderbuffer->Width;
340    }
341    else {
342       surfWidth = tex_image->Width;
343    }
344 
345    if (x + width > surfWidth) {
346       _mesa_error(ctx, GL_INVALID_VALUE,
347                   "glCopyImageSubData%s(%sX or %sWidth exceeds image bounds)",
348                   suffix, dbg_prefix, dbg_prefix);
349       return false;
350    }
351 
352    /* Check Y direction */
353    switch (target) {
354    case GL_RENDERBUFFER:
355       surfHeight = renderbuffer->Height;
356       break;
357    case GL_TEXTURE_1D:
358    case GL_TEXTURE_1D_ARRAY:
359       surfHeight = 1;
360       break;
361    default:
362       surfHeight = tex_image->Height;
363    }
364 
365    if (y + height > surfHeight) {
366       _mesa_error(ctx, GL_INVALID_VALUE,
367                   "glCopyImageSubData%s(%sY or %sHeight exceeds image bounds)",
368                   suffix, dbg_prefix, dbg_prefix);
369       return false;
370    }
371 
372    /* Check Z direction */
373    switch (target) {
374    case GL_RENDERBUFFER:
375    case GL_TEXTURE_1D:
376    case GL_TEXTURE_2D:
377    case GL_TEXTURE_2D_MULTISAMPLE:
378    case GL_TEXTURE_RECTANGLE:
379       surfDepth = 1;
380       break;
381    case GL_TEXTURE_CUBE_MAP:
382       surfDepth = 6;
383       break;
384    case GL_TEXTURE_1D_ARRAY:
385       surfDepth = tex_image->Height;
386       break;
387    default:
388       surfDepth = tex_image->Depth;
389    }
390 
391    if (z < 0 || z + depth > surfDepth) {
392       _mesa_error(ctx, GL_INVALID_VALUE,
393                   "glCopyImageSubData%s(%sZ or %sDepth exceeds image bounds)",
394                   suffix, dbg_prefix, dbg_prefix);
395       return false;
396    }
397 
398    return true;
399 }
400 
401 static bool
compressed_format_compatible(const struct gl_context * ctx,GLenum compressedFormat,GLenum otherFormat)402 compressed_format_compatible(const struct gl_context *ctx,
403                              GLenum compressedFormat, GLenum otherFormat)
404 {
405    enum mesa_block_class compressedClass, otherClass;
406 
407    /* Two view-incompatible compressed formats are never compatible. */
408    if (_mesa_is_compressed_format(ctx, otherFormat)) {
409       return false;
410    }
411 
412    /*
413     * From ARB_copy_image spec:
414     *    Table 4.X.1 (Compatible internal formats for copying between
415     *                 compressed and uncompressed internal formats)
416     *    ---------------------------------------------------------------------
417     *    | Texel / | Uncompressed      |                                     |
418     *    | Block   | internal format   | Compressed internal format          |
419     *    | size    |                   |                                     |
420     *    ---------------------------------------------------------------------
421     *    | 128-bit | RGBA32UI,         | COMPRESSED_RGBA_S3TC_DXT3_EXT,      |
422     *    |         | RGBA32I,          | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
423     *    |         | RGBA32F           | COMPRESSED_RGBA_S3TC_DXT5_EXT,      |
424     *    |         |                   | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
425     *    |         |                   | COMPRESSED_RG_RGTC2,                |
426     *    |         |                   | COMPRESSED_SIGNED_RG_RGTC2,         |
427     *    |         |                   | COMPRESSED_RGBA_BPTC_UNORM,         |
428     *    |         |                   | COMPRESSED_SRGB_ALPHA_BPTC_UNORM,   |
429     *    |         |                   | COMPRESSED_RGB_BPTC_SIGNED_FLOAT,   |
430     *    |         |                   | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT  |
431     *    ---------------------------------------------------------------------
432     *    | 64-bit  | RGBA16F, RG32F,   | COMPRESSED_RGB_S3TC_DXT1_EXT,       |
433     *    |         | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT,      |
434     *    |         | RGBA16I, RG32I,   | COMPRESSED_RGBA_S3TC_DXT1_EXT,      |
435     *    |         | RGBA16,           | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
436     *    |         | RGBA16_SNORM      | COMPRESSED_RED_RGTC1,               |
437     *    |         |                   | COMPRESSED_SIGNED_RED_RGTC1         |
438     *    ---------------------------------------------------------------------
439     */
440 
441    switch (compressedFormat) {
442       case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
443       case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
444       case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
445       case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
446       case GL_COMPRESSED_RG_RGTC2:
447       case GL_COMPRESSED_SIGNED_RG_RGTC2:
448       case GL_COMPRESSED_RGBA_BPTC_UNORM:
449       case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
450       case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
451       case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
452          compressedClass = BLOCK_CLASS_128_BITS;
453          break;
454       case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
455       case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
456       case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
457       case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
458       case GL_COMPRESSED_RED_RGTC1:
459       case GL_COMPRESSED_SIGNED_RED_RGTC1:
460          compressedClass = BLOCK_CLASS_64_BITS;
461          break;
462       case GL_COMPRESSED_RGBA8_ETC2_EAC:
463       case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
464       case GL_COMPRESSED_RG11_EAC:
465       case GL_COMPRESSED_SIGNED_RG11_EAC:
466          if (_mesa_is_gles(ctx))
467             compressedClass = BLOCK_CLASS_128_BITS;
468          else
469             return false;
470          break;
471       case GL_COMPRESSED_RGB8_ETC2:
472       case GL_COMPRESSED_SRGB8_ETC2:
473       case GL_COMPRESSED_R11_EAC:
474       case GL_COMPRESSED_SIGNED_R11_EAC:
475       case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
476       case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
477          if (_mesa_is_gles(ctx))
478             compressedClass = BLOCK_CLASS_64_BITS;
479          else
480             return false;
481          break;
482       default:
483          if (_mesa_is_gles(ctx) && _mesa_is_astc_format(compressedFormat))
484             compressedClass = BLOCK_CLASS_128_BITS;
485          else
486             return false;
487          break;
488    }
489 
490    switch (otherFormat) {
491       case GL_RGBA32UI:
492       case GL_RGBA32I:
493       case GL_RGBA32F:
494          otherClass = BLOCK_CLASS_128_BITS;
495          break;
496       case GL_RGBA16F:
497       case GL_RG32F:
498       case GL_RGBA16UI:
499       case GL_RG32UI:
500       case GL_RGBA16I:
501       case GL_RG32I:
502       case GL_RGBA16:
503       case GL_RGBA16_SNORM:
504          otherClass = BLOCK_CLASS_64_BITS;
505          break;
506       default:
507          return false;
508    }
509 
510    return compressedClass == otherClass;
511 }
512 
513 static bool
copy_format_compatible(const struct gl_context * ctx,GLenum srcFormat,GLenum dstFormat)514 copy_format_compatible(const struct gl_context *ctx,
515                        GLenum srcFormat, GLenum dstFormat)
516 {
517    /*
518     * From ARB_copy_image spec:
519     *    For the purposes of CopyImageSubData, two internal formats
520     *    are considered compatible if any of the following conditions are
521     *    met:
522     *    * the formats are the same,
523     *    * the formats are considered compatible according to the
524     *      compatibility rules used for texture views as defined in
525     *      section 3.9.X. In particular, if both internal formats are listed
526     *      in the same entry of Table 3.X.2, they are considered compatible, or
527     *    * one format is compressed and the other is uncompressed and
528     *      Table 4.X.1 lists the two formats in the same row.
529     */
530 
531    if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) {
532       /* Also checks if formats are equal. */
533       return true;
534    } else if (_mesa_is_compressed_format(ctx, srcFormat)) {
535       return compressed_format_compatible(ctx, srcFormat, dstFormat);
536    } else if (_mesa_is_compressed_format(ctx, dstFormat)) {
537       return compressed_format_compatible(ctx, dstFormat, srcFormat);
538    }
539 
540    return false;
541 }
542 
543 static void
copy_image_subdata(struct gl_context * ctx,struct gl_texture_image * srcTexImage,struct gl_renderbuffer * srcRenderbuffer,int srcX,int srcY,int srcZ,int srcLevel,struct gl_texture_image * dstTexImage,struct gl_renderbuffer * dstRenderbuffer,int dstX,int dstY,int dstZ,int dstLevel,int srcWidth,int srcHeight,int srcDepth)544 copy_image_subdata(struct gl_context *ctx,
545                    struct gl_texture_image *srcTexImage,
546                    struct gl_renderbuffer *srcRenderbuffer,
547                    int srcX, int srcY, int srcZ, int srcLevel,
548                    struct gl_texture_image *dstTexImage,
549                    struct gl_renderbuffer *dstRenderbuffer,
550                    int dstX, int dstY, int dstZ, int dstLevel,
551                    int srcWidth, int srcHeight, int srcDepth)
552 {
553    /* loop over 2D slices/faces/layers */
554    for (int i = 0; i < srcDepth; ++i) {
555       int newSrcZ = srcZ + i;
556       int newDstZ = dstZ + i;
557 
558       if (srcTexImage &&
559           srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
560          /* need to update srcTexImage pointer for the cube face */
561          assert(srcZ + i < MAX_FACES);
562          srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel];
563          assert(srcTexImage);
564          newSrcZ = 0;
565       }
566 
567       if (dstTexImage &&
568           dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
569          /* need to update dstTexImage pointer for the cube face */
570          assert(dstZ + i < MAX_FACES);
571          dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel];
572          assert(dstTexImage);
573          newDstZ = 0;
574       }
575 
576       st_CopyImageSubData(ctx,
577                           srcTexImage, srcRenderbuffer,
578                           srcX, srcY, newSrcZ,
579                           dstTexImage, dstRenderbuffer,
580                           dstX, dstY, newDstZ,
581                           srcWidth, srcHeight);
582    }
583 }
584 
585 void GLAPIENTRY
_mesa_CopyImageSubData_no_error(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)586 _mesa_CopyImageSubData_no_error(GLuint srcName, GLenum srcTarget, GLint srcLevel,
587                                 GLint srcX, GLint srcY, GLint srcZ,
588                                 GLuint dstName, GLenum dstTarget, GLint dstLevel,
589                                 GLint dstX, GLint dstY, GLint dstZ,
590                                 GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
591 {
592    struct gl_texture_image *srcTexImage, *dstTexImage;
593    struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
594 
595    GET_CURRENT_CONTEXT(ctx);
596 
597    prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, &srcTexImage,
598                   &srcRenderbuffer);
599 
600    prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, &dstTexImage,
601                   &dstRenderbuffer);
602 
603    copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ,
604                       srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ,
605                       dstLevel, srcWidth, srcHeight, srcDepth);
606 }
607 
608 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)609 _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,
610                        GLint srcX, GLint srcY, GLint srcZ,
611                        GLuint dstName, GLenum dstTarget, GLint dstLevel,
612                        GLint dstX, GLint dstY, GLint dstZ,
613                        GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
614 {
615    GET_CURRENT_CONTEXT(ctx);
616    struct gl_texture_image *srcTexImage, *dstTexImage;
617    struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
618    mesa_format srcFormat, dstFormat;
619    GLenum srcIntFormat, dstIntFormat;
620    GLuint src_w, src_h, dst_w, dst_h;
621    GLuint src_bw, src_bh, dst_bw, dst_bh;
622    GLuint src_num_samples, dst_num_samples;
623    int dstWidth, dstHeight, dstDepth;
624 
625    if (MESA_VERBOSE & VERBOSE_API)
626       _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
627                                           "%u, %s, %d, %d, %d, %d, "
628                                           "%d, %d, %d)\n",
629                   srcName, _mesa_enum_to_string(srcTarget), srcLevel,
630                   srcX, srcY, srcZ,
631                   dstName, _mesa_enum_to_string(dstTarget), dstLevel,
632                   dstX, dstY, dstZ,
633                   srcWidth, srcHeight, srcDepth);
634 
635    if (!ctx->Extensions.ARB_copy_image) {
636       _mesa_error(ctx, GL_INVALID_OPERATION,
637                   "glCopyImageSubData(extension not available)");
638       return;
639    }
640 
641    if (!prepare_target_err(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth,
642                            &srcTexImage, &srcRenderbuffer, &srcFormat,
643                            &srcIntFormat, &src_w, &src_h, &src_num_samples,
644                            "src",true))
645       return;
646 
647    if (!prepare_target_err(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth,
648                            &dstTexImage, &dstRenderbuffer, &dstFormat,
649                            &dstIntFormat, &dst_w, &dst_h, &dst_num_samples,
650                            "dst",true))
651       return;
652 
653    _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh);
654 
655    /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
656     * spec says:
657     *
658     *    An INVALID_VALUE error is generated if the dimensions of either
659     *    subregion exceeds the boundaries of the corresponding image object,
660     *    or if the image format is compressed and the dimensions of the
661     *    subregion fail to meet the alignment constraints of the format.
662     *
663     * and Section 8.7 (Compressed Texture Images) says:
664     *
665     *    An INVALID_OPERATION error is generated if any of the following
666     *    conditions occurs:
667     *
668     *      * width is not a multiple of four, and width + xoffset is not
669     *        equal to the value of TEXTURE_WIDTH.
670     *      * height is not a multiple of four, and height + yoffset is not
671     *        equal to the value of TEXTURE_HEIGHT.
672     *
673     * so we take that to mean that you can copy the "last" block of a
674     * compressed texture image even if it's smaller than the minimum block
675     * dimensions.
676     */
677    if ((srcX % src_bw != 0) || (srcY % src_bh != 0) ||
678        (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) ||
679        (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) {
680       _mesa_error(ctx, GL_INVALID_VALUE,
681                   "glCopyImageSubData(unaligned src rectangle)");
682       return;
683    }
684 
685    _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh);
686    if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) {
687       _mesa_error(ctx, GL_INVALID_VALUE,
688                   "glCopyImageSubData(unaligned dst rectangle)");
689       return;
690    }
691 
692    /* From the GL_ARB_copy_image spec:
693     *
694     * "The dimensions are always specified in texels, even for compressed
695     * texture formats. But it should be noted that if only one of the
696     * source and destination textures is compressed then the number of
697     * texels touched in the compressed image will be a factor of the
698     * block size larger than in the uncompressed image."
699     *
700     * So, if copying from compressed to uncompressed, the dest region is
701     * shrunk by the src block size factor.  If copying from uncompressed
702     * to compressed, the dest region is grown by the dest block size factor.
703     * Note that we're passed the _source_ width, height, depth and those
704     * dimensions are never changed.
705     */
706    dstWidth = srcWidth * dst_bw / src_bw;
707    dstHeight = srcHeight * dst_bh / src_bh;
708    dstDepth = srcDepth;
709 
710    if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer,
711                             srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth,
712                             "src", true))
713       return;
714 
715    if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer,
716                             dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth,
717                             "dst", true))
718       return;
719 
720    /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
721     * spec says:
722     *
723     *    An INVALID_OPERATION error is generated if either object is a texture
724     *    and the texture is not complete, if the source and destination internal
725     *    formats are not compatible, or if the number of samples do not match.
726     */
727    if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) {
728       _mesa_error(ctx, GL_INVALID_OPERATION,
729                   "glCopyImageSubData(internalFormat mismatch)");
730       return;
731    }
732 
733    if (src_num_samples != dst_num_samples) {
734       _mesa_error(ctx, GL_INVALID_OPERATION,
735                   "glCopyImageSubData(number of samples mismatch)");
736       return;
737    }
738 
739    copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ,
740                       srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ,
741                       dstLevel, srcWidth, srcHeight, srcDepth);
742 }
743 
744 void GLAPIENTRY
_mesa_CopyImageSubDataNV_no_error(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)745 _mesa_CopyImageSubDataNV_no_error(GLuint srcName, GLenum srcTarget, GLint srcLevel,
746                                   GLint srcX, GLint srcY, GLint srcZ,
747                                   GLuint dstName, GLenum dstTarget, GLint dstLevel,
748                                   GLint dstX, GLint dstY, GLint dstZ,
749                                   GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
750 {
751    struct gl_texture_image *srcTexImage, *dstTexImage;
752    struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
753 
754    GET_CURRENT_CONTEXT(ctx);
755 
756    prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, &srcTexImage,
757                   &srcRenderbuffer);
758 
759    prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, &dstTexImage,
760                   &dstRenderbuffer);
761 
762    copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ,
763                       srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ,
764                       dstLevel, srcWidth, srcHeight, srcDepth);
765 }
766 
767 void GLAPIENTRY
_mesa_CopyImageSubDataNV(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)768 _mesa_CopyImageSubDataNV(GLuint srcName, GLenum srcTarget, GLint srcLevel,
769                          GLint srcX, GLint srcY, GLint srcZ,
770                          GLuint dstName, GLenum dstTarget, GLint dstLevel,
771                          GLint dstX, GLint dstY, GLint dstZ,
772                          GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
773 {
774    GET_CURRENT_CONTEXT(ctx);
775    struct gl_texture_image *srcTexImage, *dstTexImage;
776    struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
777    mesa_format srcFormat, dstFormat;
778    GLenum srcIntFormat, dstIntFormat;
779    GLuint src_w, src_h, dst_w, dst_h;
780    GLuint src_bw, src_bh, dst_bw, dst_bh;
781    GLuint src_num_samples, dst_num_samples;
782 
783    if (MESA_VERBOSE & VERBOSE_API)
784       _mesa_debug(ctx, "glCopyImageSubDataNV(%u, %s, %d, %d, %d, %d, "
785                                             "%u, %s, %d, %d, %d, %d, "
786                                             "%d, %d, %d)\n",
787                   srcName, _mesa_enum_to_string(srcTarget), srcLevel,
788                   srcX, srcY, srcZ,
789                   dstName, _mesa_enum_to_string(dstTarget), dstLevel,
790                   dstX, dstY, dstZ,
791                   srcWidth, srcHeight, srcDepth);
792 
793    if (!ctx->Extensions.NV_copy_image) {
794       _mesa_error(ctx, GL_INVALID_OPERATION,
795                   "glCopyImageSubDataNV(extension not available)");
796       return;
797    }
798 
799    if (!prepare_target_err(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth,
800                            &srcTexImage, &srcRenderbuffer, &srcFormat,
801                            &srcIntFormat, &src_w, &src_h, &src_num_samples,
802                            "src", false))
803       return;
804 
805    if (!prepare_target_err(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth,
806                            &dstTexImage, &dstRenderbuffer, &dstFormat,
807                            &dstIntFormat, &dst_w, &dst_h, &dst_num_samples,
808                            "dst", false))
809       return;
810 
811    /*
812     * The NV_copy_image spec says:
813     *
814     *    INVALID_OPERATION is generated if either object is a texture
815     *    and the texture is not consistent, or if the source and destination
816     *    internal formats or number of samples do not match.
817     *
818     * In the absence of any definition of texture consistency the texture
819     * completeness check, which is affected in the prepare_target_err function,
820     * is used instead in keeping with the ARB version.
821     * The check related to the internal format here is different from the ARB
822     * version which adds the ability to copy between images which have
823     * different formats where the formats are compatible for texture views.
824     */
825    if (srcIntFormat != dstIntFormat) {
826       _mesa_error(ctx, GL_INVALID_OPERATION,
827                   "glCopyImageSubDataNV(internalFormat mismatch)");
828       return;
829    }
830 
831    if (src_num_samples != dst_num_samples) {
832       _mesa_error(ctx, GL_INVALID_OPERATION,
833                   "glCopyImageSubDataNV(number of samples mismatch)");
834       return;
835    }
836 
837    /*
838     * The NV_copy_image spec says:
839     *
840     *    INVALID_VALUE is generated if the image format is compressed
841     *    and the dimensions of the subregion fail to meet the alignment
842     *    constraints of the format.
843     *
844     * The check here is identical to the ARB version.
845     */
846    _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh);
847    if ((srcX % src_bw != 0) || (srcY % src_bh != 0) ||
848        (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) ||
849        (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) {
850       _mesa_error(ctx, GL_INVALID_VALUE,
851                   "glCopyImageSubDataNV(unaligned src rectangle)");
852       return;
853    }
854 
855    _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh);
856    if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) {
857       _mesa_error(ctx, GL_INVALID_VALUE,
858                   "glCopyImageSubDataNV(unaligned dst rectangle)");
859       return;
860    }
861 
862    /*
863     * The NV_copy_image spec says:
864     *
865     *    INVALID_VALUE is generated if the dimensions of the either subregion
866     *    exceeds the boundaries of the corresponding image object.
867     *
868     * The check here is similar to the ARB version except for the fact that
869     * block sizes are not considered owing to the fact that copying across
870     * compressed and uncompressed formats is not supported.
871     */
872    if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer,
873                             srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth,
874                             "src", false))
875       return;
876 
877    if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer,
878                             dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth,
879                             "dst", false))
880       return;
881 
882    copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ,
883                       srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ,
884                       dstLevel, srcWidth, srcHeight, srcDepth);
885 }
886