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
)
49 struct gl_renderbuffer
*rb
;
52 _mesa_error(ctx
, GL_INVALID_VALUE
,
53 "glCopyImageSubData(%sName = %d)", dbg_prefix
, name
);
58 * INVALID_ENUM is generated
59 * * if either <srcTarget> or <dstTarget>
60 * - is not RENDERBUFFER or a valid non-proxy texture target
61 * - is TEXTURE_BUFFER, or
62 * - is one of the cubemap face selectors described in table 3.17,
66 /* Not a texture target, but valid */
68 case GL_TEXTURE_1D_ARRAY
:
71 case GL_TEXTURE_CUBE_MAP
:
72 case GL_TEXTURE_RECTANGLE
:
73 case GL_TEXTURE_2D_ARRAY
:
74 case GL_TEXTURE_CUBE_MAP_ARRAY
:
75 case GL_TEXTURE_2D_MULTISAMPLE
:
76 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
:
77 /* These are all valid */
79 case GL_TEXTURE_EXTERNAL_OES
:
80 /* Only exists in ES */
81 case GL_TEXTURE_BUFFER
:
83 _mesa_error(ctx
, GL_INVALID_ENUM
,
84 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
85 _mesa_lookup_enum_by_nr(*target
));
89 if (*target
== GL_RENDERBUFFER
) {
90 rb
= _mesa_lookup_renderbuffer(ctx
, name
);
92 _mesa_error(ctx
, GL_INVALID_VALUE
,
93 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
98 _mesa_error(ctx
, GL_INVALID_OPERATION
,
99 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
104 _mesa_error(ctx
, GL_INVALID_VALUE
,
105 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
109 if (rb
->NumSamples
> 1)
110 *target
= GL_TEXTURE_2D_MULTISAMPLE
;
112 *target
= GL_TEXTURE_2D
;
115 _mesa_GenTextures(1, tmp_tex
);
117 return false; /* Error already set by GenTextures */
119 _mesa_BindTexture(*target
, *tmp_tex
);
120 *tex_obj
= _mesa_lookup_texture(ctx
, *tmp_tex
);
121 *tex_image
= _mesa_get_tex_image(ctx
, *tex_obj
, *target
, 0);
123 if (!ctx
->Driver
.BindRenderbufferTexImage(ctx
, rb
, *tex_image
)) {
124 _mesa_problem(ctx
, "Failed to create texture from renderbuffer");
128 if (ctx
->Driver
.FinishRenderTexture
&& !rb
->NeedsFinishRenderTexture
) {
129 rb
->NeedsFinishRenderTexture
= true;
130 ctx
->Driver
.FinishRenderTexture(ctx
, rb
);
133 *tex_obj
= _mesa_lookup_texture(ctx
, name
);
135 _mesa_error(ctx
, GL_INVALID_VALUE
,
136 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
140 _mesa_test_texobj_completeness(ctx
, *tex_obj
);
141 if (!(*tex_obj
)->_BaseComplete
||
142 (level
!= 0 && !(*tex_obj
)->_MipmapComplete
)) {
143 _mesa_error(ctx
, GL_INVALID_OPERATION
,
144 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
148 if ((*tex_obj
)->Target
!= *target
) {
149 _mesa_error(ctx
, GL_INVALID_ENUM
,
150 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
151 _mesa_lookup_enum_by_nr(*target
));
155 if (level
< 0 || level
>= MAX_TEXTURE_LEVELS
) {
156 _mesa_error(ctx
, GL_INVALID_VALUE
,
157 "glCopyImageSubData(%sLevel = %d)", dbg_prefix
, level
);
161 *tex_image
= _mesa_select_tex_image(*tex_obj
, *target
, level
);
163 _mesa_error(ctx
, GL_INVALID_VALUE
,
164 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
173 check_region_bounds(struct gl_context
*ctx
, struct gl_texture_image
*tex_image
,
174 int x
, int y
, int z
, int width
, int height
, int depth
,
175 const char *dbg_prefix
)
177 if (width
< 0 || height
< 0 || depth
< 0) {
178 _mesa_error(ctx
, GL_INVALID_VALUE
,
179 "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
180 dbg_prefix
, dbg_prefix
, dbg_prefix
);
184 if (x
< 0 || y
< 0 || z
< 0) {
185 _mesa_error(ctx
, GL_INVALID_VALUE
,
186 "glCopyImageSubData(%sX, %sY, or %sZ is negative)",
187 dbg_prefix
, dbg_prefix
, dbg_prefix
);
191 if (x
+ width
> tex_image
->Width
) {
192 _mesa_error(ctx
, GL_INVALID_VALUE
,
193 "glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
194 dbg_prefix
, dbg_prefix
);
198 switch (tex_image
->TexObject
->Target
) {
200 case GL_TEXTURE_1D_ARRAY
:
201 if (y
!= 0 || height
!= 1) {
202 _mesa_error(ctx
, GL_INVALID_VALUE
,
203 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
204 dbg_prefix
, dbg_prefix
);
209 if (y
+ height
> tex_image
->Height
) {
210 _mesa_error(ctx
, GL_INVALID_VALUE
,
211 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
212 dbg_prefix
, dbg_prefix
);
218 switch (tex_image
->TexObject
->Target
) {
221 case GL_TEXTURE_2D_MULTISAMPLE
:
222 case GL_TEXTURE_RECTANGLE
:
223 if (z
!= 0 || depth
!= 1) {
224 _mesa_error(ctx
, GL_INVALID_VALUE
,
225 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
226 dbg_prefix
, dbg_prefix
);
230 case GL_TEXTURE_CUBE_MAP
:
231 if (z
< 0 || z
+ depth
> 6) {
232 _mesa_error(ctx
, GL_INVALID_VALUE
,
233 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
234 dbg_prefix
, dbg_prefix
);
238 case GL_TEXTURE_1D_ARRAY
:
239 if (z
< 0 || z
+ depth
> tex_image
->Height
) {
240 _mesa_error(ctx
, GL_INVALID_VALUE
,
241 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
242 dbg_prefix
, dbg_prefix
);
246 case GL_TEXTURE_CUBE_MAP_ARRAY
:
247 case GL_TEXTURE_2D_ARRAY
:
248 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
:
250 if (z
< 0 || z
+ depth
> tex_image
->Depth
) {
251 _mesa_error(ctx
, GL_INVALID_VALUE
,
252 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
253 dbg_prefix
, dbg_prefix
);
263 compressed_format_compatible(struct gl_context
*ctx
,
264 GLenum compressedFormat
, GLenum otherFormat
)
266 enum mesa_block_class compressedClass
, otherClass
;
268 /* Two view-incompatible compressed formats are never compatible. */
269 if (_mesa_is_compressed_format(ctx
, otherFormat
)) {
274 * From ARB_copy_image spec:
275 * Table 4.X.1 (Compatible internal formats for copying between
276 * compressed and uncompressed internal formats)
277 * ---------------------------------------------------------------------
278 * | Texel / | Uncompressed | |
279 * | Block | internal format | Compressed internal format |
281 * ---------------------------------------------------------------------
282 * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, |
283 * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
284 * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, |
285 * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
286 * | | | COMPRESSED_RG_RGTC2, |
287 * | | | COMPRESSED_SIGNED_RG_RGTC2, |
288 * | | | COMPRESSED_RGBA_BPTC_UNORM, |
289 * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, |
290 * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, |
291 * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT |
292 * ---------------------------------------------------------------------
293 * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, |
294 * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, |
295 * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, |
296 * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
297 * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, |
298 * | | | COMPRESSED_SIGNED_RED_RGTC1 |
299 * ---------------------------------------------------------------------
302 switch (compressedFormat
) {
303 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
:
304 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
:
305 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
:
306 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
:
307 case GL_COMPRESSED_RG_RGTC2
:
308 case GL_COMPRESSED_SIGNED_RG_RGTC2
:
309 case GL_COMPRESSED_RGBA_BPTC_UNORM
:
310 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM
:
311 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT
:
312 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT
:
313 compressedClass
= BLOCK_CLASS_128_BITS
;
315 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT
:
316 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
:
317 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
:
318 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
:
319 case GL_COMPRESSED_RED_RGTC1
:
320 case GL_COMPRESSED_SIGNED_RED_RGTC1
:
321 compressedClass
= BLOCK_CLASS_64_BITS
;
327 switch (otherFormat
) {
331 otherClass
= BLOCK_CLASS_128_BITS
;
340 case GL_RGBA16_SNORM
:
341 otherClass
= BLOCK_CLASS_64_BITS
;
347 return compressedClass
== otherClass
;
351 copy_format_compatible(struct gl_context
*ctx
,
352 GLenum srcFormat
, GLenum dstFormat
)
355 * From ARB_copy_image spec:
356 * For the purposes of CopyImageSubData, two internal formats
357 * are considered compatible if any of the following conditions are
359 * * the formats are the same,
360 * * the formats are considered compatible according to the
361 * compatibility rules used for texture views as defined in
362 * section 3.9.X. In particular, if both internal formats are listed
363 * in the same entry of Table 3.X.2, they are considered compatible, or
364 * * one format is compressed and the other is uncompressed and
365 * Table 4.X.1 lists the two formats in the same row.
368 if (_mesa_texture_view_compatible_format(ctx
, srcFormat
, dstFormat
)) {
369 /* Also checks if formats are equal. */
371 } else if (_mesa_is_compressed_format(ctx
, srcFormat
)) {
372 return compressed_format_compatible(ctx
, srcFormat
, dstFormat
);
373 } else if (_mesa_is_compressed_format(ctx
, dstFormat
)) {
374 return compressed_format_compatible(ctx
, dstFormat
, srcFormat
);
381 _mesa_CopyImageSubData(GLuint srcName
, GLenum srcTarget
, GLint srcLevel
,
382 GLint srcX
, GLint srcY
, GLint srcZ
,
383 GLuint dstName
, GLenum dstTarget
, GLint dstLevel
,
384 GLint dstX
, GLint dstY
, GLint dstZ
,
385 GLsizei srcWidth
, GLsizei srcHeight
, GLsizei srcDepth
)
387 GET_CURRENT_CONTEXT(ctx
);
388 GLuint tmpTexNames
[2] = { 0, 0 };
389 struct gl_texture_object
*srcTexObj
, *dstTexObj
;
390 struct gl_texture_image
*srcTexImage
, *dstTexImage
;
391 GLuint src_bw
, src_bh
, dst_bw
, dst_bh
;
392 int i
, srcNewZ
, dstNewZ
;
394 if (MESA_VERBOSE
& VERBOSE_API
)
395 _mesa_debug(ctx
, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
396 "%u, %s, %d, %d, %d, %d, "
398 srcName
, _mesa_lookup_enum_by_nr(srcTarget
), srcLevel
,
400 dstName
, _mesa_lookup_enum_by_nr(dstTarget
), dstLevel
,
402 srcWidth
, srcHeight
, srcWidth
);
404 if (!ctx
->Extensions
.ARB_copy_image
) {
405 _mesa_error(ctx
, GL_INVALID_OPERATION
,
406 "glCopyImageSubData(extension not available)");
410 if (!prepare_target(ctx
, srcName
, &srcTarget
, srcLevel
,
411 &srcTexObj
, &srcTexImage
, &tmpTexNames
[0], "src"))
414 if (!prepare_target(ctx
, dstName
, &dstTarget
, dstLevel
,
415 &dstTexObj
, &dstTexImage
, &tmpTexNames
[1], "dst"))
418 _mesa_get_format_block_size(srcTexImage
->TexFormat
, &src_bw
, &src_bh
);
419 if ((srcX
% src_bw
!= 0) || (srcY
% src_bh
!= 0) ||
420 (srcWidth
% src_bw
!= 0) || (srcHeight
% src_bh
!= 0)) {
421 _mesa_error(ctx
, GL_INVALID_VALUE
,
422 "glCopyImageSubData(unaligned src rectangle)");
426 _mesa_get_format_block_size(dstTexImage
->TexFormat
, &dst_bw
, &dst_bh
);
427 if ((dstX
% dst_bw
!= 0) || (dstY
% dst_bh
!= 0)) {
428 _mesa_error(ctx
, GL_INVALID_VALUE
,
429 "glCopyImageSubData(unaligned dst rectangle)");
433 if (!check_region_bounds(ctx
, srcTexImage
, srcX
, srcY
, srcZ
,
434 srcWidth
, srcHeight
, srcDepth
, "src"))
437 if (!check_region_bounds(ctx
, dstTexImage
, dstX
, dstY
, dstZ
,
438 (srcWidth
/ src_bw
) * dst_bw
,
439 (srcHeight
/ src_bh
) * dst_bh
, srcDepth
, "dst"))
442 if (!copy_format_compatible(ctx
, srcTexImage
->InternalFormat
,
443 dstTexImage
->InternalFormat
)) {
444 _mesa_error(ctx
, GL_INVALID_OPERATION
,
445 "glCopyImageSubData(internalFormat mismatch)");
449 for (i
= 0; i
< srcDepth
; ++i
) {
450 if (srcTexObj
->Target
== GL_TEXTURE_CUBE_MAP
) {
451 srcTexImage
= srcTexObj
->Image
[i
+ srcZ
][srcLevel
];
457 if (dstTexObj
->Target
== GL_TEXTURE_CUBE_MAP
) {
458 dstTexImage
= dstTexObj
->Image
[i
+ dstZ
][dstLevel
];
464 ctx
->Driver
.CopyImageSubData(ctx
, srcTexImage
, srcX
, srcY
, srcNewZ
,
465 dstTexImage
, dstX
, dstY
, dstNewZ
,
466 srcWidth
, srcHeight
);
470 _mesa_DeleteTextures(2, tmpTexNames
);