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"
38 prepare_target(struct gl_context
*ctx
, GLuint name
, GLenum
*target
, int level
,
39 struct gl_texture_object
**tex_obj
,
40 struct gl_texture_image
**tex_image
, GLuint
*tmp_tex
,
41 const char *dbg_prefix
)
43 struct gl_renderbuffer
*rb
;
46 _mesa_error(ctx
, GL_INVALID_VALUE
,
47 "glCopyImageSubData(%sName = %d)", dbg_prefix
, name
);
52 * INVALID_ENUM is generated
53 * * if either <srcTarget> or <dstTarget>
54 * - is not RENDERBUFFER or a valid non-proxy texture target
55 * - is TEXTURE_BUFFER, or
56 * - is one of the cubemap face selectors described in table 3.17,
60 /* Not a texture target, but valid */
62 case GL_TEXTURE_1D_ARRAY
:
65 case GL_TEXTURE_CUBE_MAP
:
66 case GL_TEXTURE_RECTANGLE
:
67 case GL_TEXTURE_2D_ARRAY
:
68 case GL_TEXTURE_CUBE_MAP_ARRAY
:
69 case GL_TEXTURE_2D_MULTISAMPLE
:
70 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
:
71 /* These are all valid */
73 case GL_TEXTURE_EXTERNAL_OES
:
74 /* Only exists in ES */
75 case GL_TEXTURE_BUFFER
:
77 _mesa_error(ctx
, GL_INVALID_ENUM
,
78 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
79 _mesa_lookup_enum_by_nr(*target
));
83 if (*target
== GL_RENDERBUFFER
) {
84 rb
= _mesa_lookup_renderbuffer(ctx
, name
);
86 _mesa_error(ctx
, GL_INVALID_VALUE
,
87 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
92 _mesa_error(ctx
, GL_INVALID_OPERATION
,
93 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
98 _mesa_error(ctx
, GL_INVALID_VALUE
,
99 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
103 if (rb
->NumSamples
> 1)
104 *target
= GL_TEXTURE_2D_MULTISAMPLE
;
106 *target
= GL_TEXTURE_2D
;
109 _mesa_GenTextures(1, tmp_tex
);
111 return false; /* Error already set by GenTextures */
113 _mesa_BindTexture(*target
, *tmp_tex
);
114 *tex_obj
= _mesa_lookup_texture(ctx
, *tmp_tex
);
115 *tex_image
= _mesa_get_tex_image(ctx
, *tex_obj
, *target
, 0);
117 if (!ctx
->Driver
.BindRenderbufferTexImage(ctx
, rb
, *tex_image
)) {
118 _mesa_problem(ctx
, "Failed to create texture from renderbuffer");
122 if (ctx
->Driver
.FinishRenderTexture
&& !rb
->NeedsFinishRenderTexture
) {
123 rb
->NeedsFinishRenderTexture
= true;
124 ctx
->Driver
.FinishRenderTexture(ctx
, rb
);
127 *tex_obj
= _mesa_lookup_texture(ctx
, name
);
129 _mesa_error(ctx
, GL_INVALID_VALUE
,
130 "glCopyImageSubData(%sName = %u)", dbg_prefix
, name
);
134 _mesa_test_texobj_completeness(ctx
, *tex_obj
);
135 if (!(*tex_obj
)->_BaseComplete
||
136 (level
!= 0 && !(*tex_obj
)->_MipmapComplete
)) {
137 _mesa_error(ctx
, GL_INVALID_OPERATION
,
138 "glCopyImageSubData(%sName incomplete)", dbg_prefix
);
142 if ((*tex_obj
)->Target
!= *target
) {
143 _mesa_error(ctx
, GL_INVALID_ENUM
,
144 "glCopyImageSubData(%sTarget = %s)", dbg_prefix
,
145 _mesa_lookup_enum_by_nr(*target
));
149 if (level
< 0 || level
>= MAX_TEXTURE_LEVELS
) {
150 _mesa_error(ctx
, GL_INVALID_VALUE
,
151 "glCopyImageSubData(%sLevel = %d)", dbg_prefix
, level
);
155 *tex_image
= _mesa_select_tex_image(ctx
, *tex_obj
, *target
, level
);
157 _mesa_error(ctx
, GL_INVALID_VALUE
,
158 "glCopyImageSubData(%sLevel = %u)", dbg_prefix
, level
);
167 check_region_bounds(struct gl_context
*ctx
, struct gl_texture_image
*tex_image
,
168 int x
, int y
, int z
, int width
, int height
, int depth
,
169 const char *dbg_prefix
)
171 if (width
< 0 || height
< 0 || depth
< 0) {
172 _mesa_error(ctx
, GL_INVALID_VALUE
,
173 "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
174 dbg_prefix
, dbg_prefix
, dbg_prefix
);
178 if (x
< 0 || y
< 0 || z
< 0) {
179 _mesa_error(ctx
, GL_INVALID_VALUE
,
180 "glCopyImageSubData(%sX, %sY, or %sZ is negative)",
181 dbg_prefix
, dbg_prefix
, dbg_prefix
);
185 if (x
+ width
> tex_image
->Width
) {
186 _mesa_error(ctx
, GL_INVALID_VALUE
,
187 "glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
188 dbg_prefix
, dbg_prefix
);
192 switch (tex_image
->TexObject
->Target
) {
194 case GL_TEXTURE_1D_ARRAY
:
195 if (y
!= 0 || height
!= 1) {
196 _mesa_error(ctx
, GL_INVALID_VALUE
,
197 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
198 dbg_prefix
, dbg_prefix
);
203 if (y
+ height
> tex_image
->Height
) {
204 _mesa_error(ctx
, GL_INVALID_VALUE
,
205 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
206 dbg_prefix
, dbg_prefix
);
212 switch (tex_image
->TexObject
->Target
) {
215 case GL_TEXTURE_2D_MULTISAMPLE
:
216 case GL_TEXTURE_RECTANGLE
:
217 if (z
!= 0 || depth
!= 1) {
218 _mesa_error(ctx
, GL_INVALID_VALUE
,
219 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
220 dbg_prefix
, dbg_prefix
);
224 case GL_TEXTURE_CUBE_MAP
:
225 if (z
< 0 || z
+ depth
> 6) {
226 _mesa_error(ctx
, GL_INVALID_VALUE
,
227 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
228 dbg_prefix
, dbg_prefix
);
232 case GL_TEXTURE_1D_ARRAY
:
233 if (z
< 0 || z
+ depth
> tex_image
->Height
) {
234 _mesa_error(ctx
, GL_INVALID_VALUE
,
235 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
236 dbg_prefix
, dbg_prefix
);
240 case GL_TEXTURE_CUBE_MAP_ARRAY
:
241 case GL_TEXTURE_2D_ARRAY
:
242 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY
:
244 if (z
< 0 || z
+ depth
> tex_image
->Depth
) {
245 _mesa_error(ctx
, GL_INVALID_VALUE
,
246 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
247 dbg_prefix
, dbg_prefix
);
257 _mesa_CopyImageSubData(GLuint srcName
, GLenum srcTarget
, GLint srcLevel
,
258 GLint srcX
, GLint srcY
, GLint srcZ
,
259 GLuint dstName
, GLenum dstTarget
, GLint dstLevel
,
260 GLint dstX
, GLint dstY
, GLint dstZ
,
261 GLsizei srcWidth
, GLsizei srcHeight
, GLsizei srcDepth
)
263 GET_CURRENT_CONTEXT(ctx
);
264 GLuint tmpTexNames
[2] = { 0, 0 };
265 struct gl_texture_object
*srcTexObj
, *dstTexObj
;
266 struct gl_texture_image
*srcTexImage
, *dstTexImage
;
267 GLuint src_bw
, src_bh
, dst_bw
, dst_bh
;
268 int i
, srcNewZ
, dstNewZ
, Bpt
;
270 if (MESA_VERBOSE
& VERBOSE_API
)
271 _mesa_debug(ctx
, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
272 "%u, %s, %d, %d, %d, %d, "
274 srcName
, _mesa_lookup_enum_by_nr(srcTarget
), srcLevel
,
276 dstName
, _mesa_lookup_enum_by_nr(dstTarget
), dstLevel
,
278 srcWidth
, srcHeight
, srcWidth
);
280 if (!ctx
->Extensions
.ARB_copy_image
) {
281 _mesa_error(ctx
, GL_INVALID_OPERATION
,
282 "glCopyImageSubData(extension not available)");
286 if (!prepare_target(ctx
, srcName
, &srcTarget
, srcLevel
,
287 &srcTexObj
, &srcTexImage
, &tmpTexNames
[0], "src"))
290 if (!prepare_target(ctx
, dstName
, &dstTarget
, dstLevel
,
291 &dstTexObj
, &dstTexImage
, &tmpTexNames
[1], "dst"))
294 _mesa_get_format_block_size(srcTexImage
->TexFormat
, &src_bw
, &src_bh
);
295 if ((srcX
% src_bw
!= 0) || (srcY
% src_bh
!= 0) ||
296 (srcWidth
% src_bw
!= 0) || (srcHeight
% src_bh
!= 0)) {
297 _mesa_error(ctx
, GL_INVALID_VALUE
,
298 "glCopyImageSubData(unaligned src rectangle)");
302 _mesa_get_format_block_size(dstTexImage
->TexFormat
, &dst_bw
, &dst_bh
);
303 if ((dstX
% dst_bw
!= 0) || (dstY
% dst_bh
!= 0)) {
304 _mesa_error(ctx
, GL_INVALID_VALUE
,
305 "glCopyImageSubData(unaligned dst rectangle)");
309 /* Very simple sanity check. This is sufficient if one of the textures
311 Bpt
= _mesa_get_format_bytes(srcTexImage
->TexFormat
);
312 if (_mesa_get_format_bytes(dstTexImage
->TexFormat
) != Bpt
) {
313 _mesa_error(ctx
, GL_INVALID_VALUE
,
314 "glCopyImageSubData(internalFormat mismatch)");
318 if (!check_region_bounds(ctx
, srcTexImage
, srcX
, srcY
, srcZ
,
319 srcWidth
, srcHeight
, srcDepth
, "src"))
322 if (!check_region_bounds(ctx
, dstTexImage
, dstX
, dstY
, dstZ
,
323 (srcWidth
/ src_bw
) * dst_bw
,
324 (srcHeight
/ src_bh
) * dst_bh
, srcDepth
, "dst"))
327 if (_mesa_is_format_compressed(srcTexImage
->TexFormat
)) {
328 /* XXX: Technically, we should probaby do some more specific checking
329 * here. However, this should be sufficient for all compressed
330 * formats that mesa supports since it is a direct memory copy.
332 } else if (_mesa_is_format_compressed(dstTexImage
->TexFormat
)) {
333 } else if (_mesa_texture_view_compatible_format(ctx
,
334 srcTexImage
->InternalFormat
,
335 dstTexImage
->InternalFormat
)) {
337 return; /* Error logged by _mesa_texture_view_compatible_format */
340 for (i
= 0; i
< srcDepth
; ++i
) {
341 if (srcTexObj
->Target
== GL_TEXTURE_CUBE_MAP
) {
342 srcTexImage
= srcTexObj
->Image
[i
+ srcZ
][srcLevel
];
348 if (dstTexObj
->Target
== GL_TEXTURE_CUBE_MAP
) {
349 dstTexImage
= dstTexObj
->Image
[i
+ dstZ
][dstLevel
];
355 ctx
->Driver
.CopyImageSubData(ctx
, srcTexImage
, srcX
, srcY
, srcNewZ
,
356 dstTexImage
, dstX
, dstY
, dstNewZ
,
357 srcWidth
, srcHeight
);
361 _mesa_DeleteTextures(2, tmpTexNames
);