Merge branch 'master' of ../mesa 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 const char *dbg_prefix)
66 {
67 if (name == 0) {
68 _mesa_error(ctx, GL_INVALID_VALUE,
69 "glCopyImageSubData(%sName = %d)", dbg_prefix, name);
70 return false;
71 }
72
73 /*
74 * INVALID_ENUM is generated
75 * * if either <srcTarget> or <dstTarget>
76 * - is not RENDERBUFFER or a valid non-proxy texture target
77 * - is TEXTURE_BUFFER, or
78 * - is one of the cubemap face selectors described in table 3.17,
79 */
80 switch (target) {
81 case GL_RENDERBUFFER:
82 /* Not a texture target, but valid */
83 case GL_TEXTURE_1D:
84 case GL_TEXTURE_1D_ARRAY:
85 case GL_TEXTURE_2D:
86 case GL_TEXTURE_3D:
87 case GL_TEXTURE_CUBE_MAP:
88 case GL_TEXTURE_RECTANGLE:
89 case GL_TEXTURE_2D_ARRAY:
90 case GL_TEXTURE_CUBE_MAP_ARRAY:
91 case GL_TEXTURE_2D_MULTISAMPLE:
92 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
93 /* These are all valid */
94 break;
95 case GL_TEXTURE_EXTERNAL_OES:
96 /* Only exists in ES */
97 case GL_TEXTURE_BUFFER:
98 default:
99 _mesa_error(ctx, GL_INVALID_ENUM,
100 "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
101 _mesa_enum_to_string(target));
102 return false;
103 }
104
105 if (target == GL_RENDERBUFFER) {
106 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
107
108 if (!rb) {
109 _mesa_error(ctx, GL_INVALID_VALUE,
110 "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
111 return false;
112 }
113
114 if (!rb->Name) {
115 _mesa_error(ctx, GL_INVALID_OPERATION,
116 "glCopyImageSubData(%sName incomplete)", dbg_prefix);
117 return false;
118 }
119
120 if (level != 0) {
121 _mesa_error(ctx, GL_INVALID_VALUE,
122 "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
123 return false;
124 }
125
126 *renderbuffer = rb;
127 *format = rb->Format;
128 *internalFormat = rb->InternalFormat;
129 *tex_image = NULL;
130 } else {
131 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
132
133 if (!texObj) {
134 _mesa_error(ctx, GL_INVALID_VALUE,
135 "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
136 return false;
137 }
138
139 _mesa_test_texobj_completeness(ctx, texObj);
140 if (!texObj->_BaseComplete ||
141 (level != 0 && !texObj->_MipmapComplete)) {
142 _mesa_error(ctx, GL_INVALID_OPERATION,
143 "glCopyImageSubData(%sName incomplete)", dbg_prefix);
144 return false;
145 }
146
147 /* Note that target will not be a cube face name */
148 if (texObj->Target != target) {
149 /*
150 * From GL_ARB_copy_image specification:
151 * "INVALID_VALUE is generated if either <srcName> or <dstName> does
152 * not correspond to a valid renderbuffer or texture object according
153 * to the corresponding target parameter."
154 */
155 _mesa_error(ctx, GL_INVALID_VALUE,
156 "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
157 _mesa_enum_to_string(target));
158 return false;
159 }
160
161 if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
162 _mesa_error(ctx, GL_INVALID_VALUE,
163 "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level);
164 return false;
165 }
166
167 if (target == GL_TEXTURE_CUBE_MAP) {
168 int i;
169
170 assert(z < MAX_FACES); /* should have been caught earlier */
171
172 /* make sure all the cube faces are present */
173 for (i = 0; i < depth; i++) {
174 if (!texObj->Image[z+i][level]) {
175 /* missing cube face */
176 _mesa_error(ctx, GL_INVALID_OPERATION,
177 "glCopyImageSubData(missing cube face)");
178 return false;
179 }
180 }
181
182 *tex_image = texObj->Image[z][level];
183 }
184 else {
185 *tex_image = _mesa_select_tex_image(texObj, target, level);
186 }
187
188 if (!*tex_image) {
189 _mesa_error(ctx, GL_INVALID_VALUE,
190 "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
191 return false;
192 }
193
194 *renderbuffer = NULL;
195 *format = (*tex_image)->TexFormat;
196 *internalFormat = (*tex_image)->InternalFormat;
197 }
198
199 return true;
200 }
201
202
203 /**
204 * Check that the x,y,z,width,height,region is within the texture image
205 * dimensions.
206 * \return true if bounds OK, false if regions is out of bounds
207 */
208 static bool
209 check_region_bounds(struct gl_context *ctx,
210 GLenum target,
211 const struct gl_texture_image *tex_image,
212 const struct gl_renderbuffer *renderbuffer,
213 int x, int y, int z, int width, int height, int depth,
214 const char *dbg_prefix)
215 {
216 int surfWidth, surfHeight, surfDepth;
217
218 if (width < 0 || height < 0 || depth < 0) {
219 _mesa_error(ctx, GL_INVALID_VALUE,
220 "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
221 dbg_prefix, dbg_prefix, dbg_prefix);
222 return false;
223 }
224
225 if (x < 0 || y < 0 || z < 0) {
226 _mesa_error(ctx, GL_INVALID_VALUE,
227 "glCopyImageSubData(%sX, %sY, or %sZ is negative)",
228 dbg_prefix, dbg_prefix, dbg_prefix);
229 return false;
230 }
231
232 /* Check X direction */
233 if (target == GL_RENDERBUFFER) {
234 surfWidth = renderbuffer->Width;
235 }
236 else {
237 surfWidth = tex_image->Width;
238 }
239
240 if (x + width > surfWidth) {
241 _mesa_error(ctx, GL_INVALID_VALUE,
242 "glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
243 dbg_prefix, dbg_prefix);
244 return false;
245 }
246
247 /* Check Y direction */
248 switch (target) {
249 case GL_RENDERBUFFER:
250 surfHeight = renderbuffer->Height;
251 break;
252 case GL_TEXTURE_1D:
253 case GL_TEXTURE_1D_ARRAY:
254 surfHeight = 1;
255 break;
256 default:
257 surfHeight = tex_image->Height;
258 }
259
260 if (y + height > surfHeight) {
261 _mesa_error(ctx, GL_INVALID_VALUE,
262 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
263 dbg_prefix, dbg_prefix);
264 return false;
265 }
266
267 /* Check Z direction */
268 switch (target) {
269 case GL_RENDERBUFFER:
270 case GL_TEXTURE_1D:
271 case GL_TEXTURE_2D:
272 case GL_TEXTURE_2D_MULTISAMPLE:
273 case GL_TEXTURE_RECTANGLE:
274 surfDepth = 1;
275 break;
276 case GL_TEXTURE_CUBE_MAP:
277 surfDepth = 6;
278 break;
279 case GL_TEXTURE_1D_ARRAY:
280 surfDepth = tex_image->Height;
281 break;
282 default:
283 surfDepth = tex_image->Depth;
284 }
285
286 if (z < 0 || z + depth > surfDepth) {
287 _mesa_error(ctx, GL_INVALID_VALUE,
288 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
289 dbg_prefix, dbg_prefix);
290 return false;
291 }
292
293 return true;
294 }
295
296 static bool
297 compressed_format_compatible(const struct gl_context *ctx,
298 GLenum compressedFormat, GLenum otherFormat)
299 {
300 enum mesa_block_class compressedClass, otherClass;
301
302 /* Two view-incompatible compressed formats are never compatible. */
303 if (_mesa_is_compressed_format(ctx, otherFormat)) {
304 return false;
305 }
306
307 /*
308 * From ARB_copy_image spec:
309 * Table 4.X.1 (Compatible internal formats for copying between
310 * compressed and uncompressed internal formats)
311 * ---------------------------------------------------------------------
312 * | Texel / | Uncompressed | |
313 * | Block | internal format | Compressed internal format |
314 * | size | | |
315 * ---------------------------------------------------------------------
316 * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, |
317 * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
318 * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, |
319 * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
320 * | | | COMPRESSED_RG_RGTC2, |
321 * | | | COMPRESSED_SIGNED_RG_RGTC2, |
322 * | | | COMPRESSED_RGBA_BPTC_UNORM, |
323 * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, |
324 * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, |
325 * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT |
326 * ---------------------------------------------------------------------
327 * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, |
328 * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, |
329 * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, |
330 * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
331 * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, |
332 * | | | COMPRESSED_SIGNED_RED_RGTC1 |
333 * ---------------------------------------------------------------------
334 */
335
336 switch (compressedFormat) {
337 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
338 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
339 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
340 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
341 case GL_COMPRESSED_RG_RGTC2:
342 case GL_COMPRESSED_SIGNED_RG_RGTC2:
343 case GL_COMPRESSED_RGBA_BPTC_UNORM:
344 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
345 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
346 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
347 compressedClass = BLOCK_CLASS_128_BITS;
348 break;
349 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
350 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
351 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
352 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
353 case GL_COMPRESSED_RED_RGTC1:
354 case GL_COMPRESSED_SIGNED_RED_RGTC1:
355 compressedClass = BLOCK_CLASS_64_BITS;
356 break;
357 default:
358 return false;
359 }
360
361 switch (otherFormat) {
362 case GL_RGBA32UI:
363 case GL_RGBA32I:
364 case GL_RGBA32F:
365 otherClass = BLOCK_CLASS_128_BITS;
366 break;
367 case GL_RGBA16F:
368 case GL_RG32F:
369 case GL_RGBA16UI:
370 case GL_RG32UI:
371 case GL_RGBA16I:
372 case GL_RG32I:
373 case GL_RGBA16:
374 case GL_RGBA16_SNORM:
375 otherClass = BLOCK_CLASS_64_BITS;
376 break;
377 default:
378 return false;
379 }
380
381 return compressedClass == otherClass;
382 }
383
384 static bool
385 copy_format_compatible(const struct gl_context *ctx,
386 GLenum srcFormat, GLenum dstFormat)
387 {
388 /*
389 * From ARB_copy_image spec:
390 * For the purposes of CopyImageSubData, two internal formats
391 * are considered compatible if any of the following conditions are
392 * met:
393 * * the formats are the same,
394 * * the formats are considered compatible according to the
395 * compatibility rules used for texture views as defined in
396 * section 3.9.X. In particular, if both internal formats are listed
397 * in the same entry of Table 3.X.2, they are considered compatible, or
398 * * one format is compressed and the other is uncompressed and
399 * Table 4.X.1 lists the two formats in the same row.
400 */
401
402 if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) {
403 /* Also checks if formats are equal. */
404 return true;
405 } else if (_mesa_is_compressed_format(ctx, srcFormat)) {
406 return compressed_format_compatible(ctx, srcFormat, dstFormat);
407 } else if (_mesa_is_compressed_format(ctx, dstFormat)) {
408 return compressed_format_compatible(ctx, dstFormat, srcFormat);
409 }
410
411 return false;
412 }
413
414 void GLAPIENTRY
415 _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,
416 GLint srcX, GLint srcY, GLint srcZ,
417 GLuint dstName, GLenum dstTarget, GLint dstLevel,
418 GLint dstX, GLint dstY, GLint dstZ,
419 GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
420 {
421 GET_CURRENT_CONTEXT(ctx);
422 struct gl_texture_image *srcTexImage, *dstTexImage;
423 struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer;
424 mesa_format srcFormat, dstFormat;
425 GLenum srcIntFormat, dstIntFormat;
426 GLuint src_bw, src_bh, dst_bw, dst_bh;
427 int dstWidth, dstHeight, dstDepth;
428 int i;
429
430 if (MESA_VERBOSE & VERBOSE_API)
431 _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
432 "%u, %s, %d, %d, %d, %d, "
433 "%d, %d, %d)\n",
434 srcName, _mesa_enum_to_string(srcTarget), srcLevel,
435 srcX, srcY, srcZ,
436 dstName, _mesa_enum_to_string(dstTarget), dstLevel,
437 dstX, dstY, dstZ,
438 srcWidth, srcHeight, srcDepth);
439
440 if (!ctx->Extensions.ARB_copy_image) {
441 _mesa_error(ctx, GL_INVALID_OPERATION,
442 "glCopyImageSubData(extension not available)");
443 return;
444 }
445
446 if (!prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth,
447 &srcTexImage, &srcRenderbuffer, &srcFormat,
448 &srcIntFormat, "src"))
449 return;
450
451 if (!prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth,
452 &dstTexImage, &dstRenderbuffer, &dstFormat,
453 &dstIntFormat, "dst"))
454 return;
455
456 _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh);
457 if ((srcX % src_bw != 0) || (srcY % src_bh != 0) ||
458 (srcWidth % src_bw != 0) || (srcHeight % src_bh != 0)) {
459 _mesa_error(ctx, GL_INVALID_VALUE,
460 "glCopyImageSubData(unaligned src rectangle)");
461 return;
462 }
463
464 _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh);
465 if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) {
466 _mesa_error(ctx, GL_INVALID_VALUE,
467 "glCopyImageSubData(unaligned dst rectangle)");
468 return;
469 }
470
471 /* From the GL_ARB_copy_image spec:
472 *
473 * "The dimensions are always specified in texels, even for compressed
474 * texture formats. But it should be noted that if only one of the
475 * source and destination textures is compressed then the number of
476 * texels touched in the compressed image will be a factor of the
477 * block size larger than in the uncompressed image."
478 *
479 * So, if copying from compressed to uncompressed, the dest region is
480 * shrunk by the src block size factor. If copying from uncompressed
481 * to compressed, the dest region is grown by the dest block size factor.
482 * Note that we're passed the _source_ width, height, depth and those
483 * dimensions are never changed.
484 */
485 dstWidth = srcWidth * dst_bw / src_bw;
486 dstHeight = srcHeight * dst_bh / src_bh;
487 dstDepth = srcDepth;
488
489 if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer,
490 srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth,
491 "src"))
492 return;
493
494 if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer,
495 dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth,
496 "dst"))
497 return;
498
499 if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) {
500 _mesa_error(ctx, GL_INVALID_OPERATION,
501 "glCopyImageSubData(internalFormat mismatch)");
502 return;
503 }
504
505 /* loop over 2D slices/faces/layers */
506 for (i = 0; i < srcDepth; ++i) {
507 int newSrcZ = srcZ + i;
508 int newDstZ = dstZ + i;
509
510 if (srcTexImage &&
511 srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
512 /* need to update srcTexImage pointer for the cube face */
513 assert(srcZ + i < MAX_FACES);
514 srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel];
515 assert(srcTexImage);
516 newSrcZ = 0;
517 }
518
519 if (dstTexImage &&
520 dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) {
521 /* need to update dstTexImage pointer for the cube face */
522 assert(dstZ + i < MAX_FACES);
523 dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel];
524 assert(dstTexImage);
525 newDstZ = 0;
526 }
527
528 ctx->Driver.CopyImageSubData(ctx,
529 srcTexImage, srcRenderbuffer,
530 srcX, srcY, newSrcZ,
531 dstTexImage, dstRenderbuffer,
532 dstX, dstY, newDstZ,
533 srcWidth, srcHeight);
534 }
535 }