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