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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
29 * \brief Functions related to Pixel Buffer Objects.
36 #include "bufferobj.h"
37 #include "glformats.h"
46 * When we're about to read pixel data out of a PBO (via glDrawPixels,
47 * glTexImage, etc) or write data into a PBO (via glReadPixels,
48 * glGetTexImage, etc) we call this function to check that we're not
49 * going to read/write out of bounds.
51 * XXX This would also be a convenient time to check that the PBO isn't
52 * currently mapped. Whoever calls this function should check for that.
53 * Remember, we can't use a PBO when it's mapped!
55 * If we're not using a PBO, this is a no-op.
57 * \param width width of image to read/write
58 * \param height height of image to read/write
59 * \param depth depth of image to read/write
60 * \param format format of image to read/write
61 * \param type datatype of image to read/write
62 * \param clientMemSize the maximum number of bytes to read/write
63 * \param ptr the user-provided pointer/offset
64 * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
68 _mesa_validate_pbo_access(GLuint dimensions
,
69 const struct gl_pixelstore_attrib
*pack
,
70 GLsizei width
, GLsizei height
, GLsizei depth
,
71 GLenum format
, GLenum type
, GLsizei clientMemSize
,
74 /* unsigned, to detect overflow/wrap-around */
75 uintptr_t start
, end
, offset
, size
;
77 /* If no PBO is bound, 'ptr' is a pointer to client memory containing
78 'clientMemSize' bytes.
79 If a PBO is bound, 'ptr' is an offset into the bound PBO.
80 In that case 'clientMemSize' is ignored: we just use the PBO's size.
82 if (!_mesa_is_bufferobj(pack
->BufferObj
)) {
84 size
= (clientMemSize
== INT_MAX
) ? UINTPTR_MAX
: clientMemSize
;
86 offset
= (uintptr_t)ptr
;
87 size
= pack
->BufferObj
->Size
;
88 /* The ARB_pixel_buffer_object spec says:
89 * "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
90 * ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
91 * TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
92 * TexSubImage2D, TexSubImage3D, and DrawPixels if the current
93 * PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
94 * parameter is not evenly divisible into the number of basic machine
95 * units needed to store in memory a datum indicated by the type
98 if (type
!= GL_BITMAP
&&
99 (offset
% _mesa_sizeof_packed_type(type
)))
107 /* If the size of the image is zero then no pixels are accessed so we
108 * don't need to check anything else.
110 if (width
== 0 || height
== 0 || depth
== 0)
113 /* get the offset to the first pixel we'll read/write */
114 start
= _mesa_image_offset(dimensions
, pack
, width
, height
,
115 format
, type
, 0, 0, 0);
117 /* get the offset to just past the last pixel we'll read/write */
118 end
= _mesa_image_offset(dimensions
, pack
, width
, height
,
119 format
, type
, depth
-1, height
-1, width
);
125 /* This will catch negative values / wrap-around */
129 /* Image read/write goes beyond end of buffer */
139 * For commands that read from a PBO (glDrawPixels, glTexImage,
140 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
141 * and return the pointer into the PBO. If we're not reading from a
142 * PBO, return \p src as-is.
143 * If non-null return, must call _mesa_unmap_pbo_source() when done.
145 * \return NULL if error, else pointer to start of data
148 _mesa_map_pbo_source(struct gl_context
*ctx
,
149 const struct gl_pixelstore_attrib
*unpack
,
154 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
155 /* unpack from PBO */
156 buf
= (GLubyte
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
157 unpack
->BufferObj
->Size
,
164 buf
= ADD_POINTERS(buf
, src
);
167 /* unpack from normal memory */
175 * Perform PBO validation for read operations with uncompressed textures.
176 * If any GL errors are detected, false is returned, otherwise returns true.
177 * \sa _mesa_validate_pbo_access
180 _mesa_validate_pbo_source(struct gl_context
*ctx
, GLuint dimensions
,
181 const struct gl_pixelstore_attrib
*unpack
,
182 GLsizei width
, GLsizei height
, GLsizei depth
,
183 GLenum format
, GLenum type
,
184 GLsizei clientMemSize
,
185 const GLvoid
*ptr
, const char *where
)
187 assert(dimensions
== 1 || dimensions
== 2 || dimensions
== 3);
189 if (!_mesa_validate_pbo_access(dimensions
, unpack
, width
, height
, depth
,
190 format
, type
, clientMemSize
, ptr
)) {
191 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
192 _mesa_error(ctx
, GL_INVALID_OPERATION
,
193 "%s(out of bounds PBO access)",
196 _mesa_error(ctx
, GL_INVALID_OPERATION
,
197 "%s(out of bounds access: bufSize (%d) is too small)",
198 where
, clientMemSize
);
203 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
204 /* non-PBO access: no further validation to be done */
208 if (_mesa_check_disallowed_mapping(unpack
->BufferObj
)) {
209 /* buffer is already mapped - that's an error */
210 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(PBO is mapped)",
219 * Perform PBO validation for read operations with compressed textures.
220 * If any GL errors are detected, false is returned, otherwise returns true.
223 _mesa_validate_pbo_source_compressed(struct gl_context
*ctx
, GLuint dimensions
,
224 const struct gl_pixelstore_attrib
*unpack
,
225 GLsizei imageSize
, const GLvoid
*pixels
,
228 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
229 /* not using a PBO */
233 if ((const GLubyte
*) pixels
+ imageSize
>
234 ((const GLubyte
*) 0) + unpack
->BufferObj
->Size
) {
235 /* out of bounds read! */
236 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(invalid PBO access)",
241 if (_mesa_check_disallowed_mapping(unpack
->BufferObj
)) {
242 /* buffer is already mapped - that's an error */
243 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(PBO is mapped)",
252 * Perform PBO-read mapping.
253 * If any GL errors are detected, they'll be recorded and NULL returned.
254 * \sa _mesa_validate_pbo_source
255 * \sa _mesa_map_pbo_source
256 * A call to this function should have a matching call to
257 * _mesa_unmap_pbo_source().
260 _mesa_map_validate_pbo_source(struct gl_context
*ctx
,
262 const struct gl_pixelstore_attrib
*unpack
,
263 GLsizei width
, GLsizei height
, GLsizei depth
,
264 GLenum format
, GLenum type
,
265 GLsizei clientMemSize
,
266 const GLvoid
*ptr
, const char *where
)
268 if (!_mesa_validate_pbo_source(ctx
, dimensions
, unpack
,
269 width
, height
, depth
, format
, type
,
270 clientMemSize
, ptr
, where
)) {
274 ptr
= _mesa_map_pbo_source(ctx
, unpack
, ptr
);
280 * Counterpart to _mesa_map_pbo_source()
283 _mesa_unmap_pbo_source(struct gl_context
*ctx
,
284 const struct gl_pixelstore_attrib
*unpack
)
286 assert(unpack
!= &ctx
->Pack
); /* catch pack/unpack mismatch */
287 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
288 ctx
->Driver
.UnmapBuffer(ctx
, unpack
->BufferObj
, MAP_INTERNAL
);
294 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
295 * if we're writing to a PBO, map it write-only and return the pointer
296 * into the PBO. If we're not writing to a PBO, return \p dst as-is.
297 * If non-null return, must call _mesa_unmap_pbo_dest() when done.
299 * \return NULL if error, else pointer to start of data
302 _mesa_map_pbo_dest(struct gl_context
*ctx
,
303 const struct gl_pixelstore_attrib
*pack
,
308 if (_mesa_is_bufferobj(pack
->BufferObj
)) {
310 buf
= (GLubyte
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
311 pack
->BufferObj
->Size
,
318 buf
= ADD_POINTERS(buf
, dest
);
321 /* pack to normal memory */
330 * Combine PBO-write validation and mapping.
331 * If any GL errors are detected, they'll be recorded and NULL returned.
332 * \sa _mesa_validate_pbo_access
333 * \sa _mesa_map_pbo_dest
334 * A call to this function should have a matching call to
335 * _mesa_unmap_pbo_dest().
338 _mesa_map_validate_pbo_dest(struct gl_context
*ctx
,
340 const struct gl_pixelstore_attrib
*unpack
,
341 GLsizei width
, GLsizei height
, GLsizei depth
,
342 GLenum format
, GLenum type
, GLsizei clientMemSize
,
343 GLvoid
*ptr
, const char *where
)
345 assert(dimensions
== 1 || dimensions
== 2 || dimensions
== 3);
347 if (!_mesa_validate_pbo_access(dimensions
, unpack
, width
, height
, depth
,
348 format
, type
, clientMemSize
, ptr
)) {
349 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
350 _mesa_error(ctx
, GL_INVALID_OPERATION
,
351 "%s(out of bounds PBO access)", where
);
353 _mesa_error(ctx
, GL_INVALID_OPERATION
,
354 "%s(out of bounds access: bufSize (%d) is too small)",
355 where
, clientMemSize
);
360 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
361 /* non-PBO access: no further validation to be done */
365 if (_mesa_check_disallowed_mapping(unpack
->BufferObj
)) {
366 /* buffer is already mapped - that's an error */
367 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(PBO is mapped)", where
);
371 ptr
= _mesa_map_pbo_dest(ctx
, unpack
, ptr
);
377 * Counterpart to _mesa_map_pbo_dest()
380 _mesa_unmap_pbo_dest(struct gl_context
*ctx
,
381 const struct gl_pixelstore_attrib
*pack
)
383 assert(pack
!= &ctx
->Unpack
); /* catch pack/unpack mismatch */
384 if (_mesa_is_bufferobj(pack
->BufferObj
)) {
385 ctx
->Driver
.UnmapBuffer(ctx
, pack
->BufferObj
, MAP_INTERNAL
);
391 * Check if an unpack PBO is active prior to fetching a texture image.
392 * If so, do bounds checking and map the buffer into main memory.
393 * Any errors detected will be recorded.
394 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
397 _mesa_validate_pbo_teximage(struct gl_context
*ctx
, GLuint dimensions
,
398 GLsizei width
, GLsizei height
, GLsizei depth
,
399 GLenum format
, GLenum type
, const GLvoid
*pixels
,
400 const struct gl_pixelstore_attrib
*unpack
,
401 const char *funcName
)
405 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
409 if (!_mesa_validate_pbo_access(dimensions
, unpack
, width
, height
, depth
,
410 format
, type
, INT_MAX
, pixels
)) {
411 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s%uD(invalid PBO access)",
412 funcName
, dimensions
);
416 buf
= (GLubyte
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
417 unpack
->BufferObj
->Size
,
422 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s%uD(PBO is mapped)", funcName
,
427 return ADD_POINTERS(buf
, pixels
);
432 * Check if an unpack PBO is active prior to fetching a compressed texture
434 * If so, do bounds checking and map the buffer into main memory.
435 * Any errors detected will be recorded.
436 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
439 _mesa_validate_pbo_compressed_teximage(struct gl_context
*ctx
,
440 GLuint dimensions
, GLsizei imageSize
,
441 const GLvoid
*pixels
,
442 const struct gl_pixelstore_attrib
*packing
,
443 const char *funcName
)
447 if (!_mesa_validate_pbo_source_compressed(ctx
, dimensions
, packing
,
448 imageSize
, pixels
, funcName
)) {
449 /* error is already set during validation */
453 if (!_mesa_is_bufferobj(packing
->BufferObj
)) {
454 /* not using a PBO - return pointer unchanged */
458 buf
= (GLubyte
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
459 packing
->BufferObj
->Size
,
464 /* Validation above already checked that PBO is not mapped, so buffer
465 * should not be null.
469 return ADD_POINTERS(buf
, pixels
);
474 * This function must be called after either of the validate_pbo_*_teximage()
475 * functions. It unmaps the PBO buffer if it was mapped earlier.
478 _mesa_unmap_teximage_pbo(struct gl_context
*ctx
,
479 const struct gl_pixelstore_attrib
*unpack
)
481 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
482 ctx
->Driver
.UnmapBuffer(ctx
, unpack
->BufferObj
, MAP_INTERNAL
);