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