2 * Mesa 3-D graphics library
4 * Copyright (C) 2014 Intel Corporation. All Rights Reserved.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
25 * Jason Ekstrand <jason.ekstrand@intel.com>
31 #include "copyimage.h"
35 #include "textureview.h"
36 #include "glformats.h"
38 enum mesa_block_class
{
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
)
50 _mesa_error(ctx
, GL_INVALID_VALUE
,
51 "glCopyImageSubData(%sName = %d)", dbg_prefix
, name
);
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,
64 /* Not a texture target, but valid */
66 case GL_TEXTURE_1D_ARRAY
:
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 */
77 case GL_TEXTURE_EXTERNAL_OES
:
78 /* Only exists in ES */
79 case GL_TEXTURE_BUFFER
:
81 _mesa_error(ctx
, GL_INVALID_ENUM
,
82 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
83 _mesa_lookup_enum_by_nr(*target
));
87 if (*target
== GL_RENDERBUFFER
) {
88 struct gl_renderbuffer
*rb
= _mesa_lookup_renderbuffer(ctx
, name
);
90 _mesa_error(ctx
, GL_INVALID_VALUE
,
91 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
96 _mesa_error(ctx
, GL_INVALID_OPERATION
,
97 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
102 _mesa_error(ctx
, GL_INVALID_VALUE
,
103 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
107 if (rb
->NumSamples
> 1)
108 *target
= GL_TEXTURE_2D_MULTISAMPLE
;
110 *target
= GL_TEXTURE_2D
;
113 _mesa_GenTextures(1, tmp_tex
);
115 return false; /* Error already set by GenTextures */
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);
121 if (!ctx
->Driver
.BindRenderbufferTexImage(ctx
, rb
, *tex_image
)) {
122 _mesa_problem(ctx
, "Failed to create texture from renderbuffer");
126 if (ctx
->Driver
.FinishRenderTexture
&& !rb
->NeedsFinishRenderTexture
) {
127 rb
->NeedsFinishRenderTexture
= true;
128 ctx
->Driver
.FinishRenderTexture(ctx
, rb
);
131 *tex_obj
= _mesa_lookup_texture(ctx
, name
);
133 _mesa_error(ctx
, GL_INVALID_VALUE
,
134 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
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
);
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
));
153 if (level
< 0 || level
>= MAX_TEXTURE_LEVELS
) {
154 _mesa_error(ctx
, GL_INVALID_VALUE
,
155 "glCopyImageSubData(%sLevel = %d)", dbg_prefix
, level
);
159 *tex_image
= _mesa_select_tex_image(*tex_obj
, *target
, level
);
161 _mesa_error(ctx
, GL_INVALID_VALUE
,
162 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
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
)
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
);
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
);
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
);
197 switch (tex_image
->TexObject
->Target
) {
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
);
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
);
217 switch (tex_image
->TexObject
->Target
) {
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
);
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
);
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
);
245 case GL_TEXTURE_CUBE_MAP_ARRAY
:
246 case GL_TEXTURE_2D_ARRAY
:
247 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
:
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
);
262 compressed_format_compatible(const struct gl_context
*ctx
,
263 GLenum compressedFormat
, GLenum otherFormat
)
265 enum mesa_block_class compressedClass
, otherClass
;
267 /* Two view-incompatible compressed formats are never compatible. */
268 if (_mesa_is_compressed_format(ctx
, otherFormat
)) {
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 |
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 * ---------------------------------------------------------------------
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
;
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
;
326 switch (otherFormat
) {
330 otherClass
= BLOCK_CLASS_128_BITS
;
339 case GL_RGBA16_SNORM
:
340 otherClass
= BLOCK_CLASS_64_BITS
;
346 return compressedClass
== otherClass
;
350 copy_format_compatible(const struct gl_context
*ctx
,
351 GLenum srcFormat
, GLenum dstFormat
)
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
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.
367 if (_mesa_texture_view_compatible_format(ctx
, srcFormat
, dstFormat
)) {
368 /* Also checks if formats are equal. */
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
);
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
)
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
;
393 if (MESA_VERBOSE
& VERBOSE_API
)
394 _mesa_debug(ctx
, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
395 "%u, %s, %d, %d, %d, %d, "
397 srcName
, _mesa_lookup_enum_by_nr(srcTarget
), srcLevel
,
399 dstName
, _mesa_lookup_enum_by_nr(dstTarget
), dstLevel
,
401 srcWidth
, srcHeight
, srcWidth
);
403 if (!ctx
->Extensions
.ARB_copy_image
) {
404 _mesa_error(ctx
, GL_INVALID_OPERATION
,
405 "glCopyImageSubData(extension not available)");
409 if (!prepare_target(ctx
, srcName
, &srcTarget
, srcLevel
,
410 &srcTexObj
, &srcTexImage
, &tmpTexNames
[0], "src"))
413 if (!prepare_target(ctx
, dstName
, &dstTarget
, dstLevel
,
414 &dstTexObj
, &dstTexImage
, &tmpTexNames
[1], "dst"))
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)");
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)");
432 if (!check_region_bounds(ctx
, srcTexImage
, srcX
, srcY
, srcZ
,
433 srcWidth
, srcHeight
, srcDepth
, "src"))
436 if (!check_region_bounds(ctx
, dstTexImage
, dstX
, dstY
, dstZ
,
437 (srcWidth
/ src_bw
) * dst_bw
,
438 (srcHeight
/ src_bh
) * dst_bh
, srcDepth
, "dst"))
441 if (!copy_format_compatible(ctx
, srcTexImage
->InternalFormat
,
442 dstTexImage
->InternalFormat
)) {
443 _mesa_error(ctx
, GL_INVALID_OPERATION
,
444 "glCopyImageSubData(internalFormat mismatch)");
448 for (i
= 0; i
< srcDepth
; ++i
) {
449 int srcNewZ
, dstNewZ
;
451 if (srcTexObj
->Target
== GL_TEXTURE_CUBE_MAP
) {
452 srcTexImage
= srcTexObj
->Image
[i
+ srcZ
][srcLevel
];
458 if (dstTexObj
->Target
== GL_TEXTURE_CUBE_MAP
) {
459 dstTexImage
= dstTexObj
->Image
[i
+ dstZ
][dstLevel
];
465 ctx
->Driver
.CopyImageSubData(ctx
, srcTexImage
, srcX
, srcY
, srcNewZ
,
466 dstTexImage
, dstX
, dstY
, dstNewZ
,
467 srcWidth
, srcHeight
);
471 _mesa_DeleteTextures(2, tmpTexNames
);