2 * Mesa 3-D graphics library
4 * Copyright (C) 2015 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>
28 #include "bufferobj.h"
31 #include "glformats.h"
37 #include "shaderapi.h"
45 static struct gl_texture_image
*
46 create_texture_for_pbo(struct gl_context
*ctx
, bool create_pbo
,
47 GLenum pbo_target
, int width
, int height
,
48 GLenum format
, GLenum type
, const void *pixels
,
49 const struct gl_pixelstore_attrib
*packing
,
50 GLuint
*tmp_pbo
, GLuint
*tmp_tex
)
53 GLenum internal_format
;
55 struct gl_buffer_object
*buffer_obj
;
56 struct gl_texture_object
*tex_obj
;
57 struct gl_texture_image
*tex_image
;
60 if (packing
->SwapBytes
||
65 pbo_format
= _mesa_format_from_format_and_type(format
, type
);
66 if (_mesa_format_is_mesa_array_format(pbo_format
))
67 pbo_format
= _mesa_format_from_array_format(pbo_format
);
69 if (!pbo_format
|| !ctx
->TextureFormatSupported
[pbo_format
])
72 /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */
73 pixels
= _mesa_image_address3d(packing
, pixels
,
74 width
, height
, format
, type
, 0, 0, 0);
75 row_stride
= _mesa_image_row_stride(packing
, width
, format
, type
);
77 if (_mesa_is_bufferobj(packing
->BufferObj
)) {
79 buffer_obj
= packing
->BufferObj
;
83 _mesa_GenBuffers(1, tmp_pbo
);
85 /* We are not doing this inside meta_begin/end. However, we know the
86 * client doesn't have the given target bound, so we can go ahead and
87 * squash it. We'll set it back when we're done.
89 _mesa_BindBuffer(pbo_target
, *tmp_pbo
);
91 _mesa_BufferData(pbo_target
, row_stride
* height
, pixels
, GL_STREAM_DRAW
);
93 buffer_obj
= ctx
->Unpack
.BufferObj
;
96 _mesa_BindBuffer(pbo_target
, 0);
99 _mesa_GenTextures(1, tmp_tex
);
100 tex_obj
= _mesa_lookup_texture(ctx
, *tmp_tex
);
101 _mesa_initialize_texture_object(ctx
, tex_obj
, *tmp_tex
, GL_TEXTURE_2D
);
102 /* This must be set after _mesa_initialize_texture_object, not before. */
103 tex_obj
->Immutable
= GL_TRUE
;
104 /* This is required for interactions with ARB_texture_view. */
105 tex_obj
->NumLayers
= 1;
107 internal_format
= _mesa_get_format_base_format(pbo_format
);
109 tex_image
= _mesa_get_tex_image(ctx
, tex_obj
, tex_obj
->Target
, 0);
110 _mesa_init_teximage_fields(ctx
, tex_image
, width
, height
, 1,
111 0, internal_format
, pbo_format
);
113 read_only
= pbo_target
== GL_PIXEL_UNPACK_BUFFER
;
114 if (!ctx
->Driver
.SetTextureStorageForBufferObject(ctx
, tex_obj
,
119 _mesa_DeleteTextures(1, tmp_tex
);
120 _mesa_DeleteBuffers(1, tmp_pbo
);
128 _mesa_meta_pbo_TexSubImage(struct gl_context
*ctx
, GLuint dims
,
129 struct gl_texture_image
*tex_image
,
130 int xoffset
, int yoffset
, int zoffset
,
131 int width
, int height
, int depth
,
132 GLenum format
, GLenum type
, const void *pixels
,
133 bool allocate_storage
, bool create_pbo
,
134 const struct gl_pixelstore_attrib
*packing
)
136 GLuint pbo
= 0, pbo_tex
= 0, fbos
[2] = { 0, 0 };
137 struct gl_texture_image
*pbo_tex_image
;
139 bool success
= false;
142 /* XXX: This should probably be passed in from somewhere */
143 const char *where
= "_mesa_meta_pbo_TexSubImage";
145 if (!_mesa_is_bufferobj(packing
->BufferObj
) && !create_pbo
)
148 if (format
== GL_DEPTH_COMPONENT
||
149 format
== GL_DEPTH_STENCIL
||
150 format
== GL_STENCIL_INDEX
||
151 format
== GL_COLOR_INDEX
)
154 if (ctx
->_ImageTransferState
)
157 if (!_mesa_validate_pbo_access(dims
, packing
, width
, height
, depth
,
158 format
, type
, INT_MAX
, pixels
)) {
159 _mesa_error(ctx
, GL_INVALID_OPERATION
,
160 "%s(out of bounds PBO access)", where
);
164 if (_mesa_check_disallowed_mapping(packing
->BufferObj
)) {
165 /* buffer is mapped - that's an error */
166 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(PBO is mapped)", where
);
170 /* Only accept tightly packed pixels from the user. */
171 if (packing
->ImageHeight
!= 0 && packing
->ImageHeight
!= height
)
174 /* For arrays, use a tall (height * depth) 2D texture. */
175 pbo_tex_image
= create_texture_for_pbo(ctx
, create_pbo
,
176 GL_PIXEL_UNPACK_BUFFER
,
177 width
, height
* depth
,
178 format
, type
, pixels
, packing
,
183 if (allocate_storage
)
184 ctx
->Driver
.AllocTextureImageBuffer(ctx
, tex_image
);
186 /* Only stash the current FBO */
187 _mesa_meta_begin(ctx
, 0);
189 _mesa_GenFramebuffers(2, fbos
);
190 _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER
, fbos
[0]);
191 _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER
, fbos
[1]);
193 if (tex_image
->TexObject
->Target
== GL_TEXTURE_1D_ARRAY
) {
199 _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
201 /* If this passes on the first layer it should pass on the others */
202 status
= _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER
);
203 if (status
!= GL_FRAMEBUFFER_COMPLETE
)
206 _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
208 /* If this passes on the first layer it should pass on the others */
209 status
= _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER
);
210 if (status
!= GL_FRAMEBUFFER_COMPLETE
)
213 _mesa_update_state(ctx
);
215 if (_mesa_meta_BlitFramebuffer(ctx
, ctx
->ReadBuffer
, ctx
->DrawBuffer
,
218 xoffset
+ width
, yoffset
+ height
,
219 GL_COLOR_BUFFER_BIT
, GL_NEAREST
))
222 for (z
= 1; z
< depth
; z
++) {
223 _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
225 _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
226 tex_image
, zoffset
+ z
);
228 _mesa_update_state(ctx
);
230 _mesa_meta_BlitFramebuffer(ctx
, ctx
->ReadBuffer
, ctx
->DrawBuffer
,
231 0, z
* height
, width
, (z
+ 1) * height
,
233 xoffset
+ width
, yoffset
+ height
,
234 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
240 _mesa_DeleteFramebuffers(2, fbos
);
241 _mesa_DeleteTextures(1, &pbo_tex
);
242 _mesa_DeleteBuffers(1, &pbo
);
250 _mesa_meta_pbo_GetTexSubImage(struct gl_context
*ctx
, GLuint dims
,
251 struct gl_texture_image
*tex_image
,
252 int xoffset
, int yoffset
, int zoffset
,
253 int width
, int height
, int depth
,
254 GLenum format
, GLenum type
, const void *pixels
,
255 const struct gl_pixelstore_attrib
*packing
)
257 GLuint pbo
= 0, pbo_tex
= 0, fbos
[2] = { 0, 0 };
258 struct gl_texture_image
*pbo_tex_image
;
260 bool success
= false;
263 /* XXX: This should probably be passed in from somewhere */
264 const char *where
= "_mesa_meta_pbo_GetTexSubImage";
266 if (!_mesa_is_bufferobj(packing
->BufferObj
))
269 if (format
== GL_DEPTH_COMPONENT
||
270 format
== GL_DEPTH_STENCIL
||
271 format
== GL_STENCIL_INDEX
||
272 format
== GL_COLOR_INDEX
)
275 if (ctx
->_ImageTransferState
)
278 if (!_mesa_validate_pbo_access(dims
, packing
, width
, height
, depth
,
279 format
, type
, INT_MAX
, pixels
)) {
280 _mesa_error(ctx
, GL_INVALID_OPERATION
,
281 "%s(out of bounds PBO access)", where
);
285 if (_mesa_check_disallowed_mapping(packing
->BufferObj
)) {
286 /* buffer is mapped - that's an error */
287 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(PBO is mapped)", where
);
291 /* Only accept tightly packed pixels from the user. */
292 if (packing
->ImageHeight
!= 0 && packing
->ImageHeight
!= height
)
295 /* For arrays, use a tall (height * depth) 2D texture. */
296 pbo_tex_image
= create_texture_for_pbo(ctx
, false, GL_PIXEL_PACK_BUFFER
,
297 width
, height
* depth
,
298 format
, type
, pixels
, packing
,
303 /* Only stash the current FBO */
304 _mesa_meta_begin(ctx
, 0);
306 _mesa_GenFramebuffers(2, fbos
);
308 if (tex_image
&& tex_image
->TexObject
->Target
== GL_TEXTURE_1D_ARRAY
) {
314 /* If we were given a texture, bind it to the read framebuffer. If not,
315 * we're doing a ReadPixels and we should just use whatever framebuffer
316 * the client has bound.
319 _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER
, fbos
[0]);
320 _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
322 /* If this passes on the first layer it should pass on the others */
323 status
= _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER
);
324 if (status
!= GL_FRAMEBUFFER_COMPLETE
)
330 _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER
, fbos
[1]);
331 _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
333 /* If this passes on the first layer it should pass on the others */
334 status
= _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER
);
335 if (status
!= GL_FRAMEBUFFER_COMPLETE
)
338 _mesa_update_state(ctx
);
340 if (_mesa_meta_BlitFramebuffer(ctx
, ctx
->ReadBuffer
, ctx
->DrawBuffer
,
342 xoffset
+ width
, yoffset
+ height
,
344 GL_COLOR_BUFFER_BIT
, GL_NEAREST
))
347 for (z
= 1; z
< depth
; z
++) {
348 _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
349 tex_image
, zoffset
+ z
);
350 _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
353 _mesa_update_state(ctx
);
355 _mesa_meta_BlitFramebuffer(ctx
, ctx
->ReadBuffer
, ctx
->DrawBuffer
,
357 xoffset
+ width
, yoffset
+ height
,
358 0, z
* height
, width
, (z
+ 1) * height
,
359 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
365 _mesa_DeleteFramebuffers(2, fbos
);
366 _mesa_DeleteTextures(1, &pbo_tex
);
367 _mesa_DeleteBuffers(1, &pbo
);