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