1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5 * Copyright (C) 2009-2011 VMware, Inc. All Rights Reserved. 6 * 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: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 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. 24 */ 25 26 27/** 28 * \file pbo.c 29 * \brief Functions related to Pixel Buffer Objects. 30 */ 31 32 33 34#include "errors.h" 35#include "glheader.h" 36#include "bufferobj.h" 37#include "glformats.h" 38#include "image.h" 39#include "imports.h" 40#include "mtypes.h" 41#include "pbo.h" 42 43 44 45/** 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. 50 * 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! 54 * 55 * If we're not using a PBO, this is a no-op. 56 * 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 65 * go out of bounds. 66 */ 67GLboolean 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, 72 const GLvoid *ptr) 73{ 74 /* unsigned, to detect overflow/wrap-around */ 75 uintptr_t start, end, offset, size; 76 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. 81 */ 82 if (!_mesa_is_bufferobj(pack->BufferObj)) { 83 offset = 0; 84 size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize; 85 } else { 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 96 * parameter." 97 */ 98 if (type != GL_BITMAP && 99 (offset % _mesa_sizeof_packed_type(type))) 100 return GL_FALSE; 101 } 102 103 if (size == 0) 104 /* no buffer! */ 105 return GL_FALSE; 106 107 /* If the size of the image is zero then no pixels are accessed so we 108 * don't need to check anything else. 109 */ 110 if (width == 0 || height == 0 || depth == 0) 111 return GL_TRUE; 112 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); 116 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); 120 121 start += offset; 122 end += offset; 123 124 if (start > size) { 125 /* This will catch negative values / wrap-around */ 126 return GL_FALSE; 127 } 128 if (end > size) { 129 /* Image read/write goes beyond end of buffer */ 130 return GL_FALSE; 131 } 132 133 /* OK! */ 134 return GL_TRUE; 135} 136 137 138/** 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. 144 * 145 * \return NULL if error, else pointer to start of data 146 */ 147const GLvoid * 148_mesa_map_pbo_source(struct gl_context *ctx, 149 const struct gl_pixelstore_attrib *unpack, 150 const GLvoid *src) 151{ 152 const GLubyte *buf; 153 154 if (_mesa_is_bufferobj(unpack->BufferObj)) { 155 /* unpack from PBO */ 156 buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 157 unpack->BufferObj->Size, 158 GL_MAP_READ_BIT, 159 unpack->BufferObj, 160 MAP_INTERNAL); 161 if (!buf) 162 return NULL; 163 164 buf = ADD_POINTERS(buf, src); 165 } 166 else { 167 /* unpack from normal memory */ 168 buf = src; 169 } 170 171 return buf; 172} 173 174/** 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 178 */ 179bool 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) 186{ 187 assert(dimensions == 1 || dimensions == 2 || dimensions == 3); 188 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)", 194 where); 195 } else { 196 _mesa_error(ctx, GL_INVALID_OPERATION, 197 "%s(out of bounds access: bufSize (%d) is too small)", 198 where, clientMemSize); 199 } 200 return false; 201 } 202 203 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 204 /* non-PBO access: no further validation to be done */ 205 return true; 206 } 207 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)", 211 where); 212 return false; 213 } 214 215 return true; 216} 217 218/** 219 * Perform PBO validation for read operations with compressed textures. 220 * If any GL errors are detected, false is returned, otherwise returns true. 221 */ 222bool 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, 226 const char *where) 227{ 228 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 229 /* not using a PBO */ 230 return true; 231 } 232 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)", 237 where); 238 return false; 239 } 240 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)", 244 where); 245 return false; 246 } 247 248 return true; 249} 250 251/** 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(). 258 */ 259const GLvoid * 260_mesa_map_validate_pbo_source(struct gl_context *ctx, 261 GLuint dimensions, 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) 267{ 268 if (!_mesa_validate_pbo_source(ctx, dimensions, unpack, 269 width, height, depth, format, type, 270 clientMemSize, ptr, where)) { 271 return NULL; 272 } 273 274 ptr = _mesa_map_pbo_source(ctx, unpack, ptr); 275 return ptr; 276} 277 278 279/** 280 * Counterpart to _mesa_map_pbo_source() 281 */ 282void 283_mesa_unmap_pbo_source(struct gl_context *ctx, 284 const struct gl_pixelstore_attrib *unpack) 285{ 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); 289 } 290} 291 292 293/** 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. 298 * 299 * \return NULL if error, else pointer to start of data 300 */ 301void * 302_mesa_map_pbo_dest(struct gl_context *ctx, 303 const struct gl_pixelstore_attrib *pack, 304 GLvoid *dest) 305{ 306 void *buf; 307 308 if (_mesa_is_bufferobj(pack->BufferObj)) { 309 /* pack into PBO */ 310 buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 311 pack->BufferObj->Size, 312 GL_MAP_WRITE_BIT, 313 pack->BufferObj, 314 MAP_INTERNAL); 315 if (!buf) 316 return NULL; 317 318 buf = ADD_POINTERS(buf, dest); 319 } 320 else { 321 /* pack to normal memory */ 322 buf = dest; 323 } 324 325 return buf; 326} 327 328 329/** 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(). 336 */ 337GLvoid * 338_mesa_map_validate_pbo_dest(struct gl_context *ctx, 339 GLuint dimensions, 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) 344{ 345 assert(dimensions == 1 || dimensions == 2 || dimensions == 3); 346 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); 352 } else { 353 _mesa_error(ctx, GL_INVALID_OPERATION, 354 "%s(out of bounds access: bufSize (%d) is too small)", 355 where, clientMemSize); 356 } 357 return NULL; 358 } 359 360 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 361 /* non-PBO access: no further validation to be done */ 362 return ptr; 363 } 364 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); 368 return NULL; 369 } 370 371 ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); 372 return ptr; 373} 374 375 376/** 377 * Counterpart to _mesa_map_pbo_dest() 378 */ 379void 380_mesa_unmap_pbo_dest(struct gl_context *ctx, 381 const struct gl_pixelstore_attrib *pack) 382{ 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); 386 } 387} 388 389 390/** 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! 395 */ 396const GLvoid * 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) 402{ 403 GLubyte *buf; 404 405 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 406 /* no PBO */ 407 return pixels; 408 } 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); 413 return NULL; 414 } 415 416 buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 417 unpack->BufferObj->Size, 418 GL_MAP_READ_BIT, 419 unpack->BufferObj, 420 MAP_INTERNAL); 421 if (!buf) { 422 _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName, 423 dimensions); 424 return NULL; 425 } 426 427 return ADD_POINTERS(buf, pixels); 428} 429 430 431/** 432 * Check if an unpack PBO is active prior to fetching a compressed texture 433 * image. 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! 437 */ 438const GLvoid * 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) 444{ 445 GLubyte *buf; 446 447 if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, packing, 448 imageSize, pixels, funcName)) { 449 /* error is already set during validation */ 450 return NULL; 451 } 452 453 if (!_mesa_is_bufferobj(packing->BufferObj)) { 454 /* not using a PBO - return pointer unchanged */ 455 return pixels; 456 } 457 458 buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0, 459 packing->BufferObj->Size, 460 GL_MAP_READ_BIT, 461 packing->BufferObj, 462 MAP_INTERNAL); 463 464 /* Validation above already checked that PBO is not mapped, so buffer 465 * should not be null. 466 */ 467 assert(buf); 468 469 return ADD_POINTERS(buf, pixels); 470} 471 472 473/** 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. 476 */ 477void 478_mesa_unmap_teximage_pbo(struct gl_context *ctx, 479 const struct gl_pixelstore_attrib *unpack) 480{ 481 if (_mesa_is_bufferobj(unpack->BufferObj)) { 482 ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL); 483 } 484} 485