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"
35 #include "glformats.h"
44 * When we're about to read pixel data out of a PBO (via glDrawPixels,
45 * glTexImage, etc) or write data into a PBO (via glReadPixels,
46 * glGetTexImage, etc) we call this function to check that we're not
47 * going to read/write out of bounds.
49 * XXX This would also be a convenient time to check that the PBO isn't
50 * currently mapped. Whoever calls this function should check for that.
51 * Remember, we can't use a PBO when it's mapped!
53 * If we're not using a PBO, this is a no-op.
55 * \param width width of image to read/write
56 * \param height height of image to read/write
57 * \param depth depth of image to read/write
58 * \param format format of image to read/write
59 * \param type datatype of image to read/write
60 * \param clientMemSize the maximum number of bytes to read/write
61 * \param ptr the user-provided pointer/offset
62 * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
66 _mesa_validate_pbo_access(GLuint dimensions
,
67 const struct gl_pixelstore_attrib
*pack
,
68 GLsizei width
, GLsizei height
, GLsizei depth
,
69 GLenum format
, GLenum type
, GLsizei clientMemSize
,
72 /* unsigned, to detect overflow/wrap-around */
73 uintptr_t start
, end
, offset
, size
;
75 /* If no PBO is bound, 'ptr' is a pointer to client memory containing
76 'clientMemSize' bytes.
77 If a PBO is bound, 'ptr' is an offset into the bound PBO.
78 In that case 'clientMemSize' is ignored: we just use the PBO's size.
80 if (!_mesa_is_bufferobj(pack
->BufferObj
)) {
84 offset
= (uintptr_t)ptr
;
85 size
= pack
->BufferObj
->Size
;
86 /* The ARB_pixel_buffer_object spec says:
87 * "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
88 * ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
89 * TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
90 * TexSubImage2D, TexSubImage3D, and DrawPixels if the current
91 * PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
92 * parameter is not evenly divisible into the number of basic machine
93 * units needed to store in memory a datum indicated by the type
96 if (type
!= GL_BITMAP
&&
97 (offset
% _mesa_sizeof_packed_type(type
)))
105 /* get the offset to the first pixel we'll read/write */
106 start
= _mesa_image_offset(dimensions
, pack
, width
, height
,
107 format
, type
, 0, 0, 0);
109 /* get the offset to just past the last pixel we'll read/write */
110 end
= _mesa_image_offset(dimensions
, pack
, width
, height
,
111 format
, type
, depth
-1, height
-1, width
);
117 /* This will catch negative values / wrap-around */
121 /* Image read/write goes beyond end of buffer */
131 * For commands that read from a PBO (glDrawPixels, glTexImage,
132 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
133 * and return the pointer into the PBO. If we're not reading from a
134 * PBO, return \p src as-is.
135 * If non-null return, must call _mesa_unmap_pbo_source() when done.
137 * \return NULL if error, else pointer to start of data
140 _mesa_map_pbo_source(struct gl_context
*ctx
,
141 const struct gl_pixelstore_attrib
*unpack
,
146 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
147 /* unpack from PBO */
148 buf
= (GLubyte
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
149 unpack
->BufferObj
->Size
,
155 buf
= ADD_POINTERS(buf
, src
);
158 /* unpack from normal memory */
167 * Combine PBO-read validation and mapping.
168 * If any GL errors are detected, they'll be recorded and NULL returned.
169 * \sa _mesa_validate_pbo_access
170 * \sa _mesa_map_pbo_source
171 * A call to this function should have a matching call to
172 * _mesa_unmap_pbo_source().
175 _mesa_map_validate_pbo_source(struct gl_context
*ctx
,
177 const struct gl_pixelstore_attrib
*unpack
,
178 GLsizei width
, GLsizei height
, GLsizei depth
,
179 GLenum format
, GLenum type
,
180 GLsizei clientMemSize
,
181 const GLvoid
*ptr
, const char *where
)
183 ASSERT(dimensions
== 1 || dimensions
== 2 || dimensions
== 3);
185 if (!_mesa_validate_pbo_access(dimensions
, unpack
, width
, height
, depth
,
186 format
, type
, clientMemSize
, ptr
)) {
187 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
188 _mesa_error(ctx
, GL_INVALID_OPERATION
,
189 "%s(out of bounds PBO access)", where
);
191 _mesa_error(ctx
, GL_INVALID_OPERATION
,
192 "%s(out of bounds access: bufSize (%d) is too small)",
193 where
, clientMemSize
);
198 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
199 /* non-PBO access: no further validation to be done */
203 if (_mesa_bufferobj_mapped(unpack
->BufferObj
)) {
204 /* buffer is already mapped - that's an error */
205 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(PBO is mapped)", where
);
209 ptr
= _mesa_map_pbo_source(ctx
, unpack
, ptr
);
215 * Counterpart to _mesa_map_pbo_source()
218 _mesa_unmap_pbo_source(struct gl_context
*ctx
,
219 const struct gl_pixelstore_attrib
*unpack
)
221 ASSERT(unpack
!= &ctx
->Pack
); /* catch pack/unpack mismatch */
222 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
223 ctx
->Driver
.UnmapBuffer(ctx
, unpack
->BufferObj
);
229 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
230 * if we're writing to a PBO, map it write-only and return the pointer
231 * into the PBO. If we're not writing to a PBO, return \p dst as-is.
232 * If non-null return, must call _mesa_unmap_pbo_dest() when done.
234 * \return NULL if error, else pointer to start of data
237 _mesa_map_pbo_dest(struct gl_context
*ctx
,
238 const struct gl_pixelstore_attrib
*pack
,
243 if (_mesa_is_bufferobj(pack
->BufferObj
)) {
245 buf
= (GLubyte
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
246 pack
->BufferObj
->Size
,
252 buf
= ADD_POINTERS(buf
, dest
);
255 /* pack to normal memory */
264 * Combine PBO-write validation and mapping.
265 * If any GL errors are detected, they'll be recorded and NULL returned.
266 * \sa _mesa_validate_pbo_access
267 * \sa _mesa_map_pbo_dest
268 * A call to this function should have a matching call to
269 * _mesa_unmap_pbo_dest().
272 _mesa_map_validate_pbo_dest(struct gl_context
*ctx
,
274 const struct gl_pixelstore_attrib
*unpack
,
275 GLsizei width
, GLsizei height
, GLsizei depth
,
276 GLenum format
, GLenum type
, GLsizei clientMemSize
,
277 GLvoid
*ptr
, const char *where
)
279 ASSERT(dimensions
== 1 || dimensions
== 2 || dimensions
== 3);
281 if (!_mesa_validate_pbo_access(dimensions
, unpack
, width
, height
, depth
,
282 format
, type
, clientMemSize
, ptr
)) {
283 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
284 _mesa_error(ctx
, GL_INVALID_OPERATION
,
285 "%s(out of bounds PBO access)", where
);
287 _mesa_error(ctx
, GL_INVALID_OPERATION
,
288 "%s(out of bounds access: bufSize (%d) is too small)",
289 where
, clientMemSize
);
294 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
295 /* non-PBO access: no further validation to be done */
299 if (_mesa_bufferobj_mapped(unpack
->BufferObj
)) {
300 /* buffer is already mapped - that's an error */
301 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s(PBO is mapped)", where
);
305 ptr
= _mesa_map_pbo_dest(ctx
, unpack
, ptr
);
311 * Counterpart to _mesa_map_pbo_dest()
314 _mesa_unmap_pbo_dest(struct gl_context
*ctx
,
315 const struct gl_pixelstore_attrib
*pack
)
317 ASSERT(pack
!= &ctx
->Unpack
); /* catch pack/unpack mismatch */
318 if (_mesa_is_bufferobj(pack
->BufferObj
)) {
319 ctx
->Driver
.UnmapBuffer(ctx
, pack
->BufferObj
);
325 * Check if an unpack PBO is active prior to fetching a texture image.
326 * If so, do bounds checking and map the buffer into main memory.
327 * Any errors detected will be recorded.
328 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
331 _mesa_validate_pbo_teximage(struct gl_context
*ctx
, GLuint dimensions
,
332 GLsizei width
, GLsizei height
, GLsizei depth
,
333 GLenum format
, GLenum type
, const GLvoid
*pixels
,
334 const struct gl_pixelstore_attrib
*unpack
,
335 const char *funcName
)
339 if (!_mesa_is_bufferobj(unpack
->BufferObj
)) {
343 if (!_mesa_validate_pbo_access(dimensions
, unpack
, width
, height
, depth
,
344 format
, type
, INT_MAX
, pixels
)) {
345 _mesa_error(ctx
, GL_INVALID_OPERATION
, funcName
, "(invalid PBO access)");
349 buf
= (GLubyte
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
350 unpack
->BufferObj
->Size
,
354 _mesa_error(ctx
, GL_INVALID_OPERATION
, funcName
, "(PBO is mapped)");
358 return ADD_POINTERS(buf
, pixels
);
363 * Check if an unpack PBO is active prior to fetching a compressed texture
365 * If so, do bounds checking and map the buffer into main memory.
366 * Any errors detected will be recorded.
367 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
370 _mesa_validate_pbo_compressed_teximage(struct gl_context
*ctx
,
371 GLsizei imageSize
, const GLvoid
*pixels
,
372 const struct gl_pixelstore_attrib
*packing
,
373 const char *funcName
)
377 if (!_mesa_is_bufferobj(packing
->BufferObj
)) {
378 /* not using a PBO - return pointer unchanged */
381 if ((const GLubyte
*) pixels
+ imageSize
>
382 ((const GLubyte
*) 0) + packing
->BufferObj
->Size
) {
383 /* out of bounds read! */
384 _mesa_error(ctx
, GL_INVALID_OPERATION
, funcName
, "(invalid PBO access)");
388 buf
= (GLubyte
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
389 packing
->BufferObj
->Size
,
393 _mesa_error(ctx
, GL_INVALID_OPERATION
, funcName
, "(PBO is mapped");
397 return ADD_POINTERS(buf
, pixels
);
402 * This function must be called after either of the validate_pbo_*_teximage()
403 * functions. It unmaps the PBO buffer if it was mapped earlier.
406 _mesa_unmap_teximage_pbo(struct gl_context
*ctx
,
407 const struct gl_pixelstore_attrib
*unpack
)
409 if (_mesa_is_bufferobj(unpack
->BufferObj
)) {
410 ctx
->Driver
.UnmapBuffer(ctx
, unpack
->BufferObj
);