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/write 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 clientMemSize the maximum number of bytes to read/write
60 * \param ptr the user-provided pointer/offset
61 * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
65 _mesa_validate_pbo_access(GLuint dimensions,
66 const struct gl_pixelstore_attrib *pack,
67 GLsizei width, GLsizei height, GLsizei depth,
68 GLenum format, GLenum type, GLsizei clientMemSize,
71 const GLvoid *start, *end, *offset;
72 const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
74 /* If no PBO is bound, 'ptr' is a pointer to client memory containing
75 'clientMemSize' bytes.
76 If a PBO is bound, 'ptr' is an offset into the bound PBO.
77 In that case 'clientMemSize' is ignored: we just use the PBO's size.
79 if (!_mesa_is_bufferobj(pack->BufferObj)) {
81 sizeAddr = ((const GLubyte *) 0) + clientMemSize;
84 sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
85 /* The ARB_pixel_buffer_object spec says:
86 * "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
87 * ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
88 * TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
89 * TexSubImage2D, TexSubImage3D, and DrawPixels if the current
90 * PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
91 * parameter is not evenly divisible into the number of basic machine
92 * units needed to store in memory a datum indicated by the type
95 if (type != GL_BITMAP &&
96 ((GLintptr)offset % _mesa_sizeof_packed_type(type)))
104 /* get the offset to the first pixel we'll read/write */
105 start = _mesa_image_address(dimensions, pack, offset, width, height,
106 format, type, 0, 0, 0);
108 /* get the offset to just past the last pixel we'll read/write */
109 end = _mesa_image_address(dimensions, pack, offset, width, height,
110 format, type, depth-1, height-1, width);
112 if ((const GLubyte *) start > sizeAddr) {
113 /* This will catch negative values / wrap-around */
116 if ((const GLubyte *) end > sizeAddr) {
117 /* Image read/write goes beyond end of buffer */
127 * For commands that read from a PBO (glDrawPixels, glTexImage,
128 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
129 * and return the pointer into the PBO. If we're not reading from a
130 * PBO, return \p src as-is.
131 * If non-null return, must call _mesa_unmap_pbo_source() when done.
133 * \return NULL if error, else pointer to start of data
136 _mesa_map_pbo_source(struct gl_context *ctx,
137 const struct gl_pixelstore_attrib *unpack,
142 if (_mesa_is_bufferobj(unpack->BufferObj)) {
143 /* unpack from PBO */
144 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
150 buf = ADD_POINTERS(buf, src);
153 /* unpack from normal memory */
162 * Combine PBO-read validation and mapping.
163 * If any GL errors are detected, they'll be recorded and NULL returned.
164 * \sa _mesa_validate_pbo_access
165 * \sa _mesa_map_pbo_source
166 * A call to this function should have a matching call to
167 * _mesa_unmap_pbo_source().
170 _mesa_map_validate_pbo_source(struct gl_context *ctx,
172 const struct gl_pixelstore_attrib *unpack,
173 GLsizei width, GLsizei height, GLsizei depth,
174 GLenum format, GLenum type, GLsizei clientMemSize,
175 const GLvoid *ptr, const char *where)
177 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
179 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
180 format, type, clientMemSize, ptr)) {
181 if (_mesa_is_bufferobj(unpack->BufferObj)) {
182 _mesa_error(ctx, GL_INVALID_OPERATION,
183 "%s(out of bounds PBO access)", where);
185 _mesa_error(ctx, GL_INVALID_OPERATION,
186 "%s(out of bounds access: bufSize (%d) is too small)",
187 where, clientMemSize);
192 if (!_mesa_is_bufferobj(unpack->BufferObj)) {
193 /* non-PBO access: no further validation to be done */
197 if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
198 /* buffer is already mapped - that's an error */
199 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
203 ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
209 * Counterpart to _mesa_map_pbo_source()
212 _mesa_unmap_pbo_source(struct gl_context *ctx,
213 const struct gl_pixelstore_attrib *unpack)
215 ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
216 if (_mesa_is_bufferobj(unpack->BufferObj)) {
217 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
224 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
225 * if we're writing to a PBO, map it write-only and return the pointer
226 * into the PBO. If we're not writing to a PBO, return \p dst as-is.
227 * If non-null return, must call _mesa_unmap_pbo_dest() when done.
229 * \return NULL if error, else pointer to start of data
232 _mesa_map_pbo_dest(struct gl_context *ctx,
233 const struct gl_pixelstore_attrib *pack,
238 if (_mesa_is_bufferobj(pack->BufferObj)) {
240 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
246 buf = ADD_POINTERS(buf, dest);
249 /* pack to normal memory */
258 * Combine PBO-write validation and mapping.
259 * If any GL errors are detected, they'll be recorded and NULL returned.
260 * \sa _mesa_validate_pbo_access
261 * \sa _mesa_map_pbo_dest
262 * A call to this function should have a matching call to
263 * _mesa_unmap_pbo_dest().
266 _mesa_map_validate_pbo_dest(struct gl_context *ctx,
268 const struct gl_pixelstore_attrib *unpack,
269 GLsizei width, GLsizei height, GLsizei depth,
270 GLenum format, GLenum type, GLsizei clientMemSize,
271 GLvoid *ptr, const char *where)
273 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
275 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
276 format, type, clientMemSize, ptr)) {
277 if (_mesa_is_bufferobj(unpack->BufferObj)) {
278 _mesa_error(ctx, GL_INVALID_OPERATION,
279 "%s(out of bounds PBO access)", where);
281 _mesa_error(ctx, GL_INVALID_OPERATION,
282 "%s(out of bounds access: bufSize (%d) is too small)",
283 where, clientMemSize);
288 if (!_mesa_is_bufferobj(unpack->BufferObj)) {
289 /* non-PBO access: no further validation to be done */
293 if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
294 /* buffer is already mapped - that's an error */
295 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
299 ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
305 * Counterpart to _mesa_map_pbo_dest()
308 _mesa_unmap_pbo_dest(struct gl_context *ctx,
309 const struct gl_pixelstore_attrib *pack)
311 ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
312 if (_mesa_is_bufferobj(pack->BufferObj)) {
313 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
319 * Check if an unpack PBO is active prior to fetching a texture image.
320 * If so, do bounds checking and map the buffer into main memory.
321 * Any errors detected will be recorded.
322 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
325 _mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
326 GLsizei width, GLsizei height, GLsizei depth,
327 GLenum format, GLenum type, const GLvoid *pixels,
328 const struct gl_pixelstore_attrib *unpack,
329 const char *funcName)
333 if (!_mesa_is_bufferobj(unpack->BufferObj)) {
337 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
338 format, type, INT_MAX, pixels)) {
339 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
343 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
344 GL_READ_ONLY_ARB, unpack->BufferObj);
346 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)");
350 return ADD_POINTERS(buf, pixels);
355 * Check if an unpack PBO is active prior to fetching a compressed texture
357 * If so, do bounds checking and map the buffer into main memory.
358 * Any errors detected will be recorded.
359 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
362 _mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
363 GLsizei imageSize, const GLvoid *pixels,
364 const struct gl_pixelstore_attrib *packing,
365 const char *funcName)
369 if (!_mesa_is_bufferobj(packing->BufferObj)) {
370 /* not using a PBO - return pointer unchanged */
373 if ((const GLubyte *) pixels + imageSize >
374 ((const GLubyte *) 0) + packing->BufferObj->Size) {
375 /* out of bounds read! */
376 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
380 buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
381 GL_READ_ONLY_ARB, packing->BufferObj);
383 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped");
387 return ADD_POINTERS(buf, pixels);
392 * This function must be called after either of the validate_pbo_*_teximage()
393 * functions. It unmaps the PBO buffer if it was mapped earlier.
396 _mesa_unmap_teximage_pbo(struct gl_context *ctx,
397 const struct gl_pixelstore_attrib *unpack)
399 if (_mesa_is_bufferobj(unpack->BufferObj)) {
400 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,