2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5 * Copyright (C) 2009-2011 VMware, Inc. All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * \brief Functions related to Pixel Buffer Objects.
34 #include "bufferobj.h"
43 * When we're about to read pixel data out of a PBO (via glDrawPixels,
44 * glTexImage, etc) or write data into a PBO (via glReadPixels,
45 * glGetTexImage, etc) we call this function to check that we're not
46 * going to read out of bounds.
48 * XXX This would also be a convenient time to check that the PBO isn't
49 * currently mapped. Whoever calls this function should check for that.
50 * Remember, we can't use a PBO when it's mapped!
52 * If we're not using a PBO, this is a no-op.
54 * \param width width of image to read/write
55 * \param height height of image to read/write
56 * \param depth depth of image to read/write
57 * \param format format of image to read/write
58 * \param type datatype of image to read/write
59 * \param ptr the user-provided pointer/offset
60 * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
64 _mesa_validate_pbo_access(GLuint dimensions
,
65 const struct gl_pixelstore_attrib
*pack
,
66 GLsizei width
, GLsizei height
, GLsizei depth
,
67 GLenum format
, GLenum type
, const GLvoid
*ptr
)
70 const GLubyte
*sizeAddr
; /* buffer size, cast to a pointer */
72 if (!_mesa_is_bufferobj(pack
->BufferObj
))
73 return GL_TRUE
; /* no PBO, OK */
75 if (pack
->BufferObj
->Size
== 0)
79 /* get address of first pixel we'll read */
80 start
= _mesa_image_address(dimensions
, pack
, ptr
, width
, height
,
81 format
, type
, 0, 0, 0);
83 /* get address just past the last pixel we'll read */
84 end
= _mesa_image_address(dimensions
, pack
, ptr
, width
, height
,
85 format
, type
, depth
-1, height
-1, width
);
88 sizeAddr
= ((const GLubyte
*) 0) + pack
->BufferObj
->Size
;
90 if ((const GLubyte
*) start
> sizeAddr
) {
91 /* This will catch negative values / wrap-around */
94 if ((const GLubyte
*) end
> sizeAddr
) {
95 /* Image read goes beyond end of buffer */
105 * For commands that read from a PBO (glDrawPixels, glTexImage,
106 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
107 * and return the pointer into the PBO. If we're not reading from a
108 * PBO, return \p src as-is.
109 * If non-null return, must call _mesa_unmap_pbo_source() when done.
111 * \return NULL if error, else pointer to start of data
114 _mesa_map_pbo_source(struct gl_context
*ctx
,
115 const struct gl_pixelstore_attrib
*unpack
,
120 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
121 /* unpack from PBO */
122 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
128 buf
= ADD_POINTERS(buf
, src
);
131 /* unpack from normal memory */
140 * Combine PBO-read validation and mapping.
141 * If any GL errors are detected, they'll be recorded and NULL returned.
142 * \sa _mesa_validate_pbo_access
143 * \sa _mesa_map_pbo_source
144 * A call to this function should have a matching call to
145 * _mesa_unmap_pbo_source().
148 _mesa_map_validate_pbo_source(struct gl_context
*ctx
,
150 const struct gl_pixelstore_attrib
*unpack
,
151 GLsizei width
, GLsizei height
, GLsizei depth
,
152 GLenum format
, GLenum type
, const GLvoid
*ptr
,
155 ASSERT(dimensions
== 1 || dimensions
== 2 || dimensions
== 3);
157 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
158 /* non-PBO access: no validation to be done */
162 if (!_mesa_validate_pbo_access(dimensions
, unpack
,
163 width
, height
, depth
, format
, type
, ptr
)) {
164 _mesa_error(ctx
, GL_INVALID_OPERATION
,
165 "%s(out of bounds PBO access)", where
);
169 if (_mesa_bufferobj_mapped(unpack
->BufferObj
)) {
170 /* buffer is already mapped - that's an error */
171 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(PBO is mapped)", where
);
175 ptr
= _mesa_map_pbo_source(ctx
, unpack
, ptr
);
181 * Counterpart to _mesa_map_pbo_source()
184 _mesa_unmap_pbo_source(struct gl_context
*ctx
,
185 const struct gl_pixelstore_attrib
*unpack
)
187 ASSERT(unpack
!= &ctx
->Pack
); /* catch pack/unpack mismatch */
188 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
189 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
196 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
197 * if we're writing to a PBO, map it write-only and return the pointer
198 * into the PBO. If we're not writing to a PBO, return \p dst as-is.
199 * If non-null return, must call _mesa_unmap_pbo_dest() when done.
201 * \return NULL if error, else pointer to start of data
204 _mesa_map_pbo_dest(struct gl_context
*ctx
,
205 const struct gl_pixelstore_attrib
*pack
,
210 if (_mesa_is_bufferobj(pack
->BufferObj
)) {
212 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
218 buf
= ADD_POINTERS(buf
, dest
);
221 /* pack to normal memory */
230 * Combine PBO-write validation and mapping.
231 * If any GL errors are detected, they'll be recorded and NULL returned.
232 * \sa _mesa_validate_pbo_access
233 * \sa _mesa_map_pbo_dest
234 * A call to this function should have a matching call to
235 * _mesa_unmap_pbo_dest().
238 _mesa_map_validate_pbo_dest(struct gl_context
*ctx
,
240 const struct gl_pixelstore_attrib
*unpack
,
241 GLsizei width
, GLsizei height
, GLsizei depth
,
242 GLenum format
, GLenum type
, GLvoid
*ptr
,
245 ASSERT(dimensions
== 1 || dimensions
== 2 || dimensions
== 3);
247 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
248 /* non-PBO access: no validation to be done */
252 if (!_mesa_validate_pbo_access(dimensions
, unpack
,
253 width
, height
, depth
, format
, type
, ptr
)) {
254 _mesa_error(ctx
, GL_INVALID_OPERATION
,
255 "%s(out of bounds PBO access)", where
);
259 if (_mesa_bufferobj_mapped(unpack
->BufferObj
)) {
260 /* buffer is already mapped - that's an error */
261 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(PBO is mapped)", where
);
265 ptr
= _mesa_map_pbo_dest(ctx
, unpack
, ptr
);
271 * Counterpart to _mesa_map_pbo_dest()
274 _mesa_unmap_pbo_dest(struct gl_context
*ctx
,
275 const struct gl_pixelstore_attrib
*pack
)
277 ASSERT(pack
!= &ctx
->Unpack
); /* catch pack/unpack mismatch */
278 if (_mesa_is_bufferobj(pack
->BufferObj
)) {
279 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
, pack
->BufferObj
);
286 * Check if an unpack PBO is active prior to fetching a texture image.
287 * If so, do bounds checking and map the buffer into main memory.
288 * Any errors detected will be recorded.
289 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
292 _mesa_validate_pbo_teximage(struct gl_context
*ctx
, GLuint dimensions
,
293 GLsizei width
, GLsizei height
, GLsizei depth
,
294 GLenum format
, GLenum type
, const GLvoid
*pixels
,
295 const struct gl_pixelstore_attrib
*unpack
,
296 const char *funcName
)
300 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
304 if (!_mesa_validate_pbo_access(dimensions
, unpack
, width
, height
, depth
,
305 format
, type
, pixels
)) {
306 _mesa_error(ctx
, GL_INVALID_OPERATION
, funcName
, "(invalid PBO access)");
310 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
311 GL_READ_ONLY_ARB
, unpack
->BufferObj
);
313 _mesa_error(ctx
, GL_INVALID_OPERATION
, funcName
, "(PBO is mapped)");
317 return ADD_POINTERS(buf
, pixels
);
322 * Check if an unpack PBO is active prior to fetching a compressed texture
324 * If so, do bounds checking and map the buffer into main memory.
325 * Any errors detected will be recorded.
326 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
329 _mesa_validate_pbo_compressed_teximage(struct gl_context
*ctx
,
330 GLsizei imageSize
, const GLvoid
*pixels
,
331 const struct gl_pixelstore_attrib
*packing
,
332 const char *funcName
)
336 if (!_mesa_is_bufferobj(packing
->BufferObj
)) {
337 /* not using a PBO - return pointer unchanged */
340 if ((const GLubyte
*) pixels
+ imageSize
>
341 ((const GLubyte
*) 0) + packing
->BufferObj
->Size
) {
342 /* out of bounds read! */
343 _mesa_error(ctx
, GL_INVALID_OPERATION
, funcName
, "(invalid PBO access)");
347 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
348 GL_READ_ONLY_ARB
, packing
->BufferObj
);
350 _mesa_error(ctx
, GL_INVALID_OPERATION
, funcName
, "(PBO is mapped");
354 return ADD_POINTERS(buf
, pixels
);
359 * This function must be called after either of the validate_pbo_*_teximage()
360 * functions. It unmaps the PBO buffer if it was mapped earlier.
363 _mesa_unmap_teximage_pbo(struct gl_context
*ctx
,
364 const struct gl_pixelstore_attrib
*unpack
)
366 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
367 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,