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 the source or destination resource, including:
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
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
)
63 _mesa_error(ctx
, GL_INVALID_VALUE
,
64 "glCopyImageSubData(%sName = %d)", dbg_prefix
, name
);
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,
77 /* Not a texture target, but valid */
79 case GL_TEXTURE_1D_ARRAY
:
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 */
90 case GL_TEXTURE_EXTERNAL_OES
:
91 /* Only exists in ES */
92 case GL_TEXTURE_BUFFER
:
94 _mesa_error(ctx
, GL_INVALID_ENUM
,
95 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
96 _mesa_enum_to_string(*target
));
100 if (*target
== GL_RENDERBUFFER
) {
101 struct gl_renderbuffer
*rb
= _mesa_lookup_renderbuffer(ctx
, name
);
103 _mesa_error(ctx
, GL_INVALID_VALUE
,
104 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
109 _mesa_error(ctx
, GL_INVALID_OPERATION
,
110 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
115 _mesa_error(ctx
, GL_INVALID_VALUE
,
116 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
120 if (rb
->NumSamples
> 1)
121 *target
= GL_TEXTURE_2D_MULTISAMPLE
;
123 *target
= GL_TEXTURE_2D
;
126 _mesa_GenTextures(1, tmp_tex
);
128 return false; /* Error already set by GenTextures */
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);
134 if (!ctx
->Driver
.BindRenderbufferTexImage(ctx
, rb
, *tex_image
)) {
135 _mesa_problem(ctx
, "Failed to create texture from renderbuffer");
139 if (ctx
->Driver
.FinishRenderTexture
&& !rb
->NeedsFinishRenderTexture
) {
140 rb
->NeedsFinishRenderTexture
= true;
141 ctx
->Driver
.FinishRenderTexture(ctx
, rb
);
144 *tex_obj
= _mesa_lookup_texture(ctx
, name
);
146 _mesa_error(ctx
, GL_INVALID_VALUE
,
147 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
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
);
159 if ((*tex_obj
)->Target
!= *target
) {
160 _mesa_error(ctx
, GL_INVALID_ENUM
,
161 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
162 _mesa_enum_to_string(*target
));
166 if (level
< 0 || level
>= MAX_TEXTURE_LEVELS
) {
167 _mesa_error(ctx
, GL_INVALID_VALUE
,
168 "glCopyImageSubData(%sLevel = %d)", dbg_prefix
, level
);
172 *tex_image
= _mesa_select_tex_image(*tex_obj
, *target
, level
);
174 _mesa_error(ctx
, GL_INVALID_VALUE
,
175 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
185 * Check that the x,y,z,width,height,region is within the texture image
187 * \return true if bounds OK, false if regions is out of bounds
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
)
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
);
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
);
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
);
217 /* Check Y direction */
218 switch (tex_image
->TexObject
->Target
) {
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
);
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
);
238 /* Check Z direction */
239 switch (tex_image
->TexObject
->Target
) {
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
);
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
);
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
);
267 case GL_TEXTURE_CUBE_MAP_ARRAY
:
268 case GL_TEXTURE_2D_ARRAY
:
269 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
:
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
);
284 compressed_format_compatible(const struct gl_context
*ctx
,
285 GLenum compressedFormat
, GLenum otherFormat
)
287 enum mesa_block_class compressedClass
, otherClass
;
289 /* Two view-incompatible compressed formats are never compatible. */
290 if (_mesa_is_compressed_format(ctx
, otherFormat
)) {
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 |
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 * ---------------------------------------------------------------------
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
;
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
;
348 switch (otherFormat
) {
352 otherClass
= BLOCK_CLASS_128_BITS
;
361 case GL_RGBA16_SNORM
:
362 otherClass
= BLOCK_CLASS_64_BITS
;
368 return compressedClass
== otherClass
;
372 copy_format_compatible(const struct gl_context
*ctx
,
373 GLenum srcFormat
, GLenum dstFormat
)
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
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.
389 if (_mesa_texture_view_compatible_format(ctx
, srcFormat
, dstFormat
)) {
390 /* Also checks if formats are equal. */
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
);
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
)
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
;
415 if (MESA_VERBOSE
& VERBOSE_API
)
416 _mesa_debug(ctx
, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
417 "%u, %s, %d, %d, %d, %d, "
419 srcName
, _mesa_enum_to_string(srcTarget
), srcLevel
,
421 dstName
, _mesa_enum_to_string(dstTarget
), dstLevel
,
423 srcWidth
, srcHeight
, srcWidth
);
425 if (!ctx
->Extensions
.ARB_copy_image
) {
426 _mesa_error(ctx
, GL_INVALID_OPERATION
,
427 "glCopyImageSubData(extension not available)");
431 if (!prepare_target(ctx
, srcName
, &srcTarget
, srcLevel
,
432 &srcTexObj
, &srcTexImage
, &tmpTexNames
[0], "src"))
435 if (!prepare_target(ctx
, dstName
, &dstTarget
, dstLevel
,
436 &dstTexObj
, &dstTexImage
, &tmpTexNames
[1], "dst"))
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)");
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)");
454 if (!check_region_bounds(ctx
, srcTexImage
, srcX
, srcY
, srcZ
,
455 srcWidth
, srcHeight
, srcDepth
, "src"))
458 if (!check_region_bounds(ctx
, dstTexImage
, dstX
, dstY
, dstZ
,
459 (srcWidth
/ src_bw
) * dst_bw
,
460 (srcHeight
/ src_bh
) * dst_bh
, srcDepth
, "dst"))
463 if (!copy_format_compatible(ctx
, srcTexImage
->InternalFormat
,
464 dstTexImage
->InternalFormat
)) {
465 _mesa_error(ctx
, GL_INVALID_OPERATION
,
466 "glCopyImageSubData(internalFormat mismatch)");
470 for (i
= 0; i
< srcDepth
; ++i
) {
471 int srcNewZ
, dstNewZ
;
473 if (srcTexObj
->Target
== GL_TEXTURE_CUBE_MAP
) {
474 srcTexImage
= srcTexObj
->Image
[i
+ srcZ
][srcLevel
];
480 if (dstTexObj
->Target
== GL_TEXTURE_CUBE_MAP
) {
481 dstTexImage
= dstTexObj
->Image
[i
+ dstZ
][dstLevel
];
487 ctx
->Driver
.CopyImageSubData(ctx
, srcTexImage
, srcX
, srcY
, srcNewZ
,
488 dstTexImage
, dstX
, dstY
, dstNewZ
,
489 srcWidth
, srcHeight
);
493 _mesa_DeleteTextures(2, tmpTexNames
);