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