Merge remote-tracking branch 'mesa-public/master' into vulkan
[mesa.git] / src / mesa / main / copyimage.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2014 Intel Corporation. All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Jason Ekstrand <jason.ekstrand@intel.com>
26 */
27
28 #include "glheader.h"
29 #include "errors.h"
30 #include "enums.h"
31 #include "copyimage.h"
32 #include "teximage.h"
33 #include "texobj.h"
34 #include "fbobject.h"
35 #include "textureview.h"
36 #include "glformats.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
59 prepare_target(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 const char *dbg_prefix)
68 {
69 if (name == 0) {
70 _mesa_error(ctx, GL_INVALID_VALUE,
71 "glCopyImageSubData(%sName = %d)", dbg_prefix, name);
72 return false;
73 }
74
75 /*
76 * INVALID_ENUM is generated
77 * * if either <srcTarget> or <dstTarget>
78 * - is not RENDERBUFFER or a valid non-proxy texture target
79 * - is TEXTURE_BUFFER, or
80 * - is one of the cubemap face selectors described in table 3.17,
81 */
82 switch (target) {
83 case GL_RENDERBUFFER:
84 /* Not a texture target, but valid */
85 case GL_TEXTURE_1D:
86 case GL_TEXTURE_1D_ARRAY:
87 case GL_TEXTURE_2D:
88 case GL_TEXTURE_3D:
89 case GL_TEXTURE_CUBE_MAP:
90 case GL_TEXTURE_RECTANGLE:
91 case GL_TEXTURE_2D_ARRAY:
92 case GL_TEXTURE_CUBE_MAP_ARRAY:
93 case GL_TEXTURE_2D_MULTISAMPLE:
94 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
95 /* These are all valid */
96 break;
97 case GL_TEXTURE_EXTERNAL_OES:
98 /* Only exists in ES */
99 case GL_TEXTURE_BUFFER:
100 default:
101 _mesa_error(ctx, GL_INVALID_ENUM,
102 "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
103 _mesa_enum_to_string(target));
104 return false;
105 }
106
107 if (target == GL_RENDERBUFFER) {
108 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
109
110 if (!rb) {
111 _mesa_error(ctx, GL_INVALID_VALUE,
112 "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
113 return false;
114 }
115
116 if (!rb->Name) {
117 _mesa_error(ctx, GL_INVALID_OPERATION,
118 "glCopyImageSubData(%sName incomplete)", dbg_prefix);
119 return false;
120 }
121
122 if (level != 0) {
123 _mesa_error(ctx, GL_INVALID_VALUE,
124 "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
125 return false;
126 }
127
128 *renderbuffer = rb;
129 *format = rb->Format;
130 *internalFormat = rb->InternalFormat;
131 *width = rb->Width;
132 *height = rb->Height;
133 *tex_image = NULL;
134 } else {
135 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
136
137 if (!texObj) {
138 _mesa_error(ctx, GL_INVALID_VALUE,
139 "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
140 return false;
141 }
142
143 _mesa_test_texobj_completeness(ctx, texObj);
144 if (!texObj->_BaseComplete ||
145 (level != 0 && !texObj->_MipmapComplete)) {
146 _mesa_error(ctx, GL_INVALID_OPERATION,
147 "glCopyImageSubData(%sName incomplete)", dbg_prefix);
148 return false;
149 }
150
151 /* Note that target will not be a cube face name */
152 if (texObj->Target != target) {
153 /*
154 * From GL_ARB_copy_image specification:
155 * "INVALID_VALUE is generated if either <srcName> or <dstName> does
156 * not correspond to a valid renderbuffer or texture object according
157 * to the corresponding target parameter."
158 */
159 _mesa_error(ctx, GL_INVALID_VALUE,
160 "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
161 _mesa_enum_to_string(target));
162 return false;
163 }
164
165 if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
166 _mesa_error(ctx, GL_INVALID_VALUE,
167 "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level);
168 return false;
169 }
170
171 if (target == GL_TEXTURE_CUBE_MAP) {
172 int i;
173
174 assert(z < MAX_FACES); /* should have been caught earlier */
175
176 /* make sure all the cube faces are present */
177 for (i = 0; i < depth; i++) {
178 if (!texObj->Image[z+i][level]) {
179 /* missing cube face */
180 _mesa_error(ctx, GL_INVALID_OPERATION,
181 "glCopyImageSubData(missing cube face)");
182 return false;
183 }
184 }
185
186 *tex_image = texObj->Image[z][level];
187 }
188 else {
189 *tex_image = _mesa_select_tex_image(texObj, target, level);
190 }
191
192 if (!*tex_image) {
193 _mesa_error(ctx, GL_INVALID_VALUE,
194 "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
195 return false;
196 }
197
198 *renderbuffer = NULL;
199 *format = (*tex_image)->TexFormat;
200 *internalFormat = (*tex_image)->InternalFormat;
201 *width = (*tex_image)->Width;
202 *height = (*tex_image)->Height;
203 }
204
205 return true;
206 }
207
208
209 /**
210 * Check that the x,y,z,width,height,region is within the texture image
211 * dimensions.
212 * \return true if bounds OK, false if regions is out of bounds
213 */
214 static bool
215 check_region_bounds(struct gl_context *ctx,
216 GLenum target,
217 const struct gl_texture_image *tex_image,
218 const struct gl_renderbuffer *renderbuffer,
219 int x, int y, int z, int width, int height, int depth,
220 const char *dbg_prefix)
221 {
222 int surfWidth, surfHeight, surfDepth;
223
224 if (width < 0 || height < 0 || depth < 0) {
225 _mesa_error(ctx, GL_INVALID_VALUE,
226 "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
227 dbg_prefix, dbg_prefix, dbg_prefix);
228 return false;
229 }
230
231 if (x < 0 || y < 0 || z < 0) {
232 _mesa_error(ctx, GL_INVALID_VALUE,
233 "glCopyImageSubData(%sX, %sY, or %sZ is negative)",
234 dbg_prefix, dbg_prefix, dbg_prefix);
235 return false;
236 }
237
238 /* Check X direction */
239 if (target == GL_RENDERBUFFER) {
240 surfWidth = renderbuffer->Width;
241 }
242 else {
243 surfWidth = tex_image->Width;
244 }
245
246 if (x + width > surfWidth) {
247 _mesa_error(ctx, GL_INVALID_VALUE,
248 "glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
249 dbg_prefix, dbg_prefix);
250 return false;
251 }
252
253 /* Check Y direction */
254 switch (target) {
255 case GL_RENDERBUFFER:
256 surfHeight = renderbuffer->Height;
257 break;
258 case GL_TEXTURE_1D:
259 case GL_TEXTURE_1D_ARRAY:
260 surfHeight = 1;
261 break;
262 default:
263 surfHeight = tex_image->Height;
264 }
265
266 if (y + height > surfHeight) {
267 _mesa_error(ctx, GL_INVALID_VALUE,
268 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
269 dbg_prefix, dbg_prefix);
270 return false;
271 }
272
273 /* Check Z direction */
274 switch (target) {
275 case GL_RENDERBUFFER:
276 case GL_TEXTURE_1D:
277 case GL_TEXTURE_2D:
278 case GL_TEXTURE_2D_MULTISAMPLE:
279 case GL_TEXTURE_RECTANGLE:
280 surfDepth = 1;
281 break;
282 case GL_TEXTURE_CUBE_MAP:
283 surfDepth = 6;
284 break;
285 case GL_TEXTURE_1D_ARRAY:
286 surfDepth = tex_image->Height;
287 break;
288 default:
289 surfDepth = tex_image->Depth;
290 }
291
292 if (z < 0 || z + depth > surfDepth) {
293 _mesa_error(ctx, GL_INVALID_VALUE,
294 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
295 dbg_prefix, dbg_prefix);
296 return false;
297 }
298
299 return true;
300 }
301
302 static bool
303 compressed_format_compatible(const struct gl_context *ctx,
304 GLenum compressedFormat, GLenum otherFormat)
305 {
306 enum mesa_block_class compressedClass, otherClass;
307
308 /* Two view-incompatible compressed formats are never compatible. */
309 if (_mesa_is_compressed_format(ctx, otherFormat)) {
310 return false;
311 }
312
313 /*
314 * From ARB_copy_image spec:
315 * Table 4.X.1 (Compatible internal formats for copying between
316 * compressed and uncompressed internal formats)
317 * ---------------------------------------------------------------------
318 * | Texel / | Uncompressed | |
319 * | Block | internal format | Compressed internal format |
320 * | size | | |
321 * ---------------------------------------------------------------------
322 * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, |
323 * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
324 * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, |
325 * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
326 * | | | COMPRESSED_RG_RGTC2, |
327 * | | | COMPRESSED_SIGNED_RG_RGTC2, |
328 * | | | COMPRESSED_RGBA_BPTC_UNORM, |
329 * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, |
330 * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, |
331 * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT |
332 * ---------------------------------------------------------------------
333 * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, |
334 * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, |
335 * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, |
336 * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
337 * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, |
338 * | | | COMPRESSED_SIGNED_RED_RGTC1 |
339 * ---------------------------------------------------------------------
340 */
341
342 switch (compressedFormat) {
343 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
344 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
345 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
346 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
347 case GL_COMPRESSED_RG_RGTC2:
348 case GL_COMPRESSED_SIGNED_RG_RGTC2:
349 case GL_COMPRESSED_RGBA_BPTC_UNORM:
350 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
351 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
352 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
353 compressedClass = BLOCK_CLASS_128_BITS;
354 break;
355 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
356 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
357 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
358 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
359 case GL_COMPRESSED_RED_RGTC1:
360 case GL_COMPRESSED_SIGNED_RED_RGTC1:
361 compressedClass = BLOCK_CLASS_64_BITS;
362 break;
363 default:
364 return false;
365 }
366
367 switch (otherFormat) {
368 case GL_RGBA32UI:
369 case GL_RGBA32I:
370 case GL_RGBA32F:
371 otherClass = BLOCK_CLASS_128_BITS;
372 break;
373 case GL_RGBA16F:
374 case GL_RG32F:
375 case GL_RGBA16UI:
376 case GL_RG32UI:
377 case GL_RGBA16I:
378 case GL_RG32I:
379 case GL_RGBA16:
380 case GL_RGBA16_SNORM:
381 otherClass = BLOCK_CLASS_64_BITS;
382 break;
383 default:
384 return false;
385 }
386
387 return compressedClass == otherClass;
388 }
389
390 static bool
391 copy_format_compatible(const struct gl_context *ctx,
392 GLenum srcFormat, GLenum dstFormat)
393 {
394 /*
395 * From ARB_copy_image spec:
396 * For the purposes of CopyImageSubData, two internal formats
397 * are considered compatible if any of the following conditions are
398 * met:
399 * * the formats are the same,
400 * * the formats are considered compatible according to the
401 * compatibility rules used for texture views as defined in
402 * section 3.9.X. In particular, if both internal formats are listed
403 * in the same entry of Table 3.X.2, they are considered compatible, or
404 * * one format is compressed and the other is uncompressed and
405 * Table 4.X.1 lists the two formats in the same row.
406 */
407
408 if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) {
409 /* Also checks if formats are equal. */
410 return true;
411 } else if (_mesa_is_compressed_format(ctx, srcFormat)) {
412 return compressed_format_compatible(ctx, srcFormat, dstFormat);
413 } else if (_mesa_is_compressed_format(ctx, dstFormat)) {
414 return compressed_format_compatible(ctx, dstFormat, srcFormat);
415 }
416
417 return false;
418 }
419
420 void GLAPIENTRY
421 _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,
422 GLint srcX, GLint srcY, GLint srcZ,
423 GLuint dstName, GLenum dstTarget, GLint dstLevel,
424 GLint dstX, GLint dstY, GLint dstZ,
425 GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
426 {
427 GET_CURRENT_CONTEXT(ctx);
428 struct gl_texture_image *srcTexImage, *dstTexImage;
429 struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
430 mesa_format srcFormat, dstFormat;
431 GLenum srcIntFormat, dstIntFormat;
432 GLuint src_w, src_h, dst_w, dst_h;
433 GLuint src_bw, src_bh, dst_bw, dst_bh;
434 int dstWidth, dstHeight, dstDepth;
435 int i;
436
437 if (MESA_VERBOSE & VERBOSE_API)
438 _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
439 "%u, %s, %d, %d, %d, %d, "
440 "%d, %d, %d)\n",
441 srcName, _mesa_enum_to_string(srcTarget), srcLevel,
442 srcX, srcY, srcZ,
443 dstName, _mesa_enum_to_string(dstTarget), dstLevel,
444 dstX, dstY, dstZ,
445 srcWidth, srcHeight, srcDepth);
446
447 if (!ctx->Extensions.ARB_copy_image) {
448 _mesa_error(ctx, GL_INVALID_OPERATION,
449 "glCopyImageSubData(extension not available)");
450 return;
451 }
452
453 if (!prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth,
454 &srcTexImage, &srcRenderbuffer, &srcFormat,
455 &srcIntFormat, &src_w, &src_h, "src"))
456 return;
457
458 if (!prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth,
459 &dstTexImage, &dstRenderbuffer, &dstFormat,
460 &dstIntFormat, &dst_w, &dst_h, "dst"))
461 return;
462
463 _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh);
464
465 /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile
466 * spec says:
467 *
468 * An INVALID_VALUE error is generated if the dimensions of either
469 * subregion exceeds the boundaries of the corresponding image object,
470 * or if the image format is compressed and the dimensions of the
471 * subregion fail to meet the alignment constraints of the format.
472 *
473 * and Section 8.7 (Compressed Texture Images) says:
474 *
475 * An INVALID_OPERATION error is generated if any of the following
476 * conditions occurs:
477 *
478 * * width is not a multiple of four, and width + xoffset is not
479 * equal to the value of TEXTURE_WIDTH.
480 * * height is not a multiple of four, and height + yoffset is not
481 * equal to the value of TEXTURE_HEIGHT.
482 *
483 * so we take that to mean that you can copy the "last" block of a
484 * compressed texture image even if it's smaller than the minimum block
485 * dimensions.
486 */
487 if ((srcX % src_bw != 0) || (srcY % src_bh != 0) ||
488 (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) ||
489 (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) {
490 _mesa_error(ctx, GL_INVALID_VALUE,
491 "glCopyImageSubData(unaligned src rectangle)");
492 return;
493 }
494
495 _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh);
496 if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) {
497 _mesa_error(ctx, GL_INVALID_VALUE,
498 "glCopyImageSubData(unaligned dst rectangle)");
499 return;
500 }
501
502 /* From the GL_ARB_copy_image spec:
503 *
504 * "The dimensions are always specified in texels, even for compressed
505 * texture formats. But it should be noted that if only one of the
506 * source and destination textures is compressed then the number of
507 * texels touched in the compressed image will be a factor of the
508 * block size larger than in the uncompressed image."
509 *
510 * So, if copying from compressed to uncompressed, the dest region is
511 * shrunk by the src block size factor. If copying from uncompressed
512 * to compressed, the dest region is grown by the dest block size factor.
513 * Note that we're passed the _source_ width, height, depth and those
514 * dimensions are never changed.
515 */
516 dstWidth = srcWidth * dst_bw / src_bw;
517 dstHeight = srcHeight * dst_bh / src_bh;
518 dstDepth = srcDepth;
519
520 if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer,
521 srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth,
522 "src"))
523 return;
524
525 if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer,
526 dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth,
527 "dst"))
528 return;
529
530 if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) {
531 _mesa_error(ctx, GL_INVALID_OPERATION,
532 "glCopyImageSubData(internalFormat mismatch)");
533 return;
534 }
535
536 /* loop over 2D slices/faces/layers */
537 for (i = 0; i < srcDepth; ++i) {
538 int newSrcZ = srcZ + i;
539 int newDstZ = dstZ + i;
540
541 if (srcTexImage &&
542 srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
543 /* need to update srcTexImage pointer for the cube face */
544 assert(srcZ + i < MAX_FACES);
545 srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel];
546 assert(srcTexImage);
547 newSrcZ = 0;
548 }
549
550 if (dstTexImage &&
551 dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
552 /* need to update dstTexImage pointer for the cube face */
553 assert(dstZ + i < MAX_FACES);
554 dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel];
555 assert(dstTexImage);
556 newDstZ = 0;
557 }
558
559 ctx->Driver.CopyImageSubData(ctx,
560 srcTexImage, srcRenderbuffer,
561 srcX, srcY, newSrcZ,
562 dstTexImage, dstRenderbuffer,
563 dstX, dstY, newDstZ,
564 srcWidth, srcHeight);
565 }
566 }