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 "mtypes.h" 40#include "macros.h" 41#include "pbo.h" 42 43/** 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. 48 * 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! 52 * 53 * If we're not using a PBO, this is a no-op. 54 * 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 63 * go out of bounds. 64 */ 65GLboolean 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, 70 const GLvoid *ptr) 71{ 72 /* unsigned, to detect overflow/wrap-around */ 73 uintptr_t start, end, offset, size; 74 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. 79 */ 80 if (!pack->BufferObj) { 81 offset = 0; 82 size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize; 83 } else { 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 94 * parameter." 95 */ 96 if (type != GL_BITMAP && 97 (offset % _mesa_sizeof_packed_type(type))) 98 return GL_FALSE; 99 } 100 101 if (size == 0) 102 /* no buffer! */ 103 return GL_FALSE; 104 105 /* If the size of the image is zero then no pixels are accessed so we 106 * don't need to check anything else. 107 */ 108 if (width == 0 || height == 0 || depth == 0) 109 return GL_TRUE; 110 111 /* get the offset to the first pixel we'll read/write */ 112 start = _mesa_image_offset(dimensions, pack, width, height, 113 format, type, 0, 0, 0); 114 115 /* get the offset to just past the last pixel we'll read/write */ 116 end = _mesa_image_offset(dimensions, pack, width, height, 117 format, type, depth-1, height-1, width); 118 119 start += offset; 120 end += offset; 121 122 if (start > size) { 123 /* This will catch negative values / wrap-around */ 124 return GL_FALSE; 125 } 126 if (end > size) { 127 /* Image read/write goes beyond end of buffer */ 128 return GL_FALSE; 129 } 130 131 /* OK! */ 132 return GL_TRUE; 133} 134 135 136/** 137 * For commands that read from a PBO (glDrawPixels, glTexImage, 138 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only 139 * and return the pointer into the PBO. If we're not reading from a 140 * PBO, return \p src as-is. 141 * If non-null return, must call _mesa_unmap_pbo_source() when done. 142 * 143 * \return NULL if error, else pointer to start of data 144 */ 145const GLvoid * 146_mesa_map_pbo_source(struct gl_context *ctx, 147 const struct gl_pixelstore_attrib *unpack, 148 const GLvoid *src) 149{ 150 const GLubyte *buf; 151 152 if (unpack->BufferObj) { 153 /* unpack from PBO */ 154 buf = (GLubyte *) _mesa_bufferobj_map_range(ctx, 0, 155 unpack->BufferObj->Size, 156 GL_MAP_READ_BIT, 157 unpack->BufferObj, 158 MAP_INTERNAL); 159 if (!buf) 160 return NULL; 161 162 buf = ADD_POINTERS(buf, src); 163 } 164 else { 165 /* unpack from normal memory */ 166 buf = src; 167 } 168 169 return buf; 170} 171 172/** 173 * Perform PBO validation for read operations with uncompressed textures. 174 * If any GL errors are detected, false is returned, otherwise returns true. 175 * \sa _mesa_validate_pbo_access 176 */ 177bool 178_mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions, 179 const struct gl_pixelstore_attrib *unpack, 180 GLsizei width, GLsizei height, GLsizei depth, 181 GLenum format, GLenum type, 182 GLsizei clientMemSize, 183 const GLvoid *ptr, const char *where) 184{ 185 assert(dimensions == 1 || dimensions == 2 || dimensions == 3); 186 187 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, 188 format, type, clientMemSize, ptr)) { 189 if (unpack->BufferObj) { 190 _mesa_error(ctx, GL_INVALID_OPERATION, 191 "%s(out of bounds PBO access)", 192 where); 193 } else { 194 _mesa_error(ctx, GL_INVALID_OPERATION, 195 "%s(out of bounds access: bufSize (%d) is too small)", 196 where, clientMemSize); 197 } 198 return false; 199 } 200 201 if (!unpack->BufferObj) { 202 /* non-PBO access: no further validation to be done */ 203 return true; 204 } 205 206 if (_mesa_check_disallowed_mapping(unpack->BufferObj)) { 207 /* buffer is already mapped - that's an error */ 208 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", 209 where); 210 return false; 211 } 212 213 return true; 214} 215 216/** 217 * Perform PBO validation for read operations with compressed textures. 218 * If any GL errors are detected, false is returned, otherwise returns true. 219 */ 220bool 221_mesa_validate_pbo_source_compressed(struct gl_context *ctx, GLuint dimensions, 222 const struct gl_pixelstore_attrib *unpack, 223 GLsizei imageSize, const GLvoid *pixels, 224 const char *where) 225{ 226 if (!unpack->BufferObj) { 227 /* not using a PBO */ 228 return true; 229 } 230 231 if ((const GLubyte *) pixels + imageSize > 232 ((const GLubyte *) 0) + unpack->BufferObj->Size) { 233 /* out of bounds read! */ 234 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid PBO access)", 235 where); 236 return false; 237 } 238 239 if (_mesa_check_disallowed_mapping(unpack->BufferObj)) { 240 /* buffer is already mapped - that's an error */ 241 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", 242 where); 243 return false; 244 } 245 246 return true; 247} 248 249/** 250 * Perform PBO-read mapping. 251 * If any GL errors are detected, they'll be recorded and NULL returned. 252 * \sa _mesa_validate_pbo_source 253 * \sa _mesa_map_pbo_source 254 * A call to this function should have a matching call to 255 * _mesa_unmap_pbo_source(). 256 */ 257const GLvoid * 258_mesa_map_validate_pbo_source(struct gl_context *ctx, 259 GLuint dimensions, 260 const struct gl_pixelstore_attrib *unpack, 261 GLsizei width, GLsizei height, GLsizei depth, 262 GLenum format, GLenum type, 263 GLsizei clientMemSize, 264 const GLvoid *ptr, const char *where) 265{ 266 if (!_mesa_validate_pbo_source(ctx, dimensions, unpack, 267 width, height, depth, format, type, 268 clientMemSize, ptr, where)) { 269 return NULL; 270 } 271 272 ptr = _mesa_map_pbo_source(ctx, unpack, ptr); 273 return ptr; 274} 275 276 277/** 278 * Counterpart to _mesa_map_pbo_source() 279 */ 280void 281_mesa_unmap_pbo_source(struct gl_context *ctx, 282 const struct gl_pixelstore_attrib *unpack) 283{ 284 assert(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ 285 if (unpack->BufferObj) { 286 _mesa_bufferobj_unmap(ctx, unpack->BufferObj, MAP_INTERNAL); 287 } 288} 289 290 291/** 292 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), 293 * if we're writing to a PBO, map it write-only and return the pointer 294 * into the PBO. If we're not writing to a PBO, return \p dst as-is. 295 * If non-null return, must call _mesa_unmap_pbo_dest() when done. 296 * 297 * \return NULL if error, else pointer to start of data 298 */ 299void * 300_mesa_map_pbo_dest(struct gl_context *ctx, 301 const struct gl_pixelstore_attrib *pack, 302 GLvoid *dest) 303{ 304 void *buf; 305 306 if (pack->BufferObj) { 307 /* pack into PBO */ 308 buf = (GLubyte *) _mesa_bufferobj_map_range(ctx, 0, 309 pack->BufferObj->Size, 310 GL_MAP_WRITE_BIT, 311 pack->BufferObj, 312 MAP_INTERNAL); 313 if (!buf) 314 return NULL; 315 316 buf = ADD_POINTERS(buf, dest); 317 } 318 else { 319 /* pack to normal memory */ 320 buf = dest; 321 } 322 323 return buf; 324} 325 326 327/** 328 * Combine PBO-write validation and mapping. 329 * If any GL errors are detected, they'll be recorded and NULL returned. 330 * \sa _mesa_validate_pbo_access 331 * \sa _mesa_map_pbo_dest 332 * A call to this function should have a matching call to 333 * _mesa_unmap_pbo_dest(). 334 */ 335GLvoid * 336_mesa_map_validate_pbo_dest(struct gl_context *ctx, 337 GLuint dimensions, 338 const struct gl_pixelstore_attrib *unpack, 339 GLsizei width, GLsizei height, GLsizei depth, 340 GLenum format, GLenum type, GLsizei clientMemSize, 341 GLvoid *ptr, const char *where) 342{ 343 assert(dimensions == 1 || dimensions == 2 || dimensions == 3); 344 345 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, 346 format, type, clientMemSize, ptr)) { 347 if (unpack->BufferObj) { 348 _mesa_error(ctx, GL_INVALID_OPERATION, 349 "%s(out of bounds PBO access)", where); 350 } else { 351 _mesa_error(ctx, GL_INVALID_OPERATION, 352 "%s(out of bounds access: bufSize (%d) is too small)", 353 where, clientMemSize); 354 } 355 return NULL; 356 } 357 358 if (!unpack->BufferObj) { 359 /* non-PBO access: no further validation to be done */ 360 return ptr; 361 } 362 363 if (_mesa_check_disallowed_mapping(unpack->BufferObj)) { 364 /* buffer is already mapped - that's an error */ 365 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); 366 return NULL; 367 } 368 369 ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); 370 return ptr; 371} 372 373 374/** 375 * Counterpart to _mesa_map_pbo_dest() 376 */ 377void 378_mesa_unmap_pbo_dest(struct gl_context *ctx, 379 const struct gl_pixelstore_attrib *pack) 380{ 381 assert(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ 382 if (pack->BufferObj) { 383 _mesa_bufferobj_unmap(ctx, pack->BufferObj, MAP_INTERNAL); 384 } 385} 386 387 388/** 389 * Check if an unpack PBO is active prior to fetching a texture image. 390 * If so, do bounds checking and map the buffer into main memory. 391 * Any errors detected will be recorded. 392 * The caller _must_ call _mesa_unmap_teximage_pbo() too! 393 */ 394const GLvoid * 395_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, 396 GLsizei width, GLsizei height, GLsizei depth, 397 GLenum format, GLenum type, const GLvoid *pixels, 398 const struct gl_pixelstore_attrib *unpack, 399 const char *funcName) 400{ 401 GLubyte *buf; 402 403 if (!unpack->BufferObj) { 404 /* no PBO */ 405 return pixels; 406 } 407 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, 408 format, type, INT_MAX, pixels)) { 409 _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)", 410 funcName, dimensions); 411 return NULL; 412 } 413 414 buf = (GLubyte *) _mesa_bufferobj_map_range(ctx, 0, 415 unpack->BufferObj->Size, 416 GL_MAP_READ_BIT, 417 unpack->BufferObj, 418 MAP_INTERNAL); 419 if (!buf) { 420 _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName, 421 dimensions); 422 return NULL; 423 } 424 425 return ADD_POINTERS(buf, pixels); 426} 427 428 429/** 430 * Check if an unpack PBO is active prior to fetching a compressed texture 431 * image. 432 * If so, do bounds checking and map the buffer into main memory. 433 * Any errors detected will be recorded. 434 * The caller _must_ call _mesa_unmap_teximage_pbo() too! 435 */ 436const GLvoid * 437_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, 438 GLuint dimensions, GLsizei imageSize, 439 const GLvoid *pixels, 440 const struct gl_pixelstore_attrib *packing, 441 const char *funcName) 442{ 443 GLubyte *buf; 444 445 if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, packing, 446 imageSize, pixels, funcName)) { 447 /* error is already set during validation */ 448 return NULL; 449 } 450 451 if (!packing->BufferObj) { 452 /* not using a PBO - return pointer unchanged */ 453 return pixels; 454 } 455 456 buf = (GLubyte*) _mesa_bufferobj_map_range(ctx, 0, 457 packing->BufferObj->Size, 458 GL_MAP_READ_BIT, 459 packing->BufferObj, 460 MAP_INTERNAL); 461 462 /* Validation above already checked that PBO is not mapped, so buffer 463 * should not be null. 464 */ 465 assert(buf); 466 467 return ADD_POINTERS(buf, pixels); 468} 469 470 471/** 472 * This function must be called after either of the validate_pbo_*_teximage() 473 * functions. It unmaps the PBO buffer if it was mapped earlier. 474 */ 475void 476_mesa_unmap_teximage_pbo(struct gl_context *ctx, 477 const struct gl_pixelstore_attrib *unpack) 478{ 479 if (unpack->BufferObj) { 480 _mesa_bufferobj_unmap(ctx, unpack->BufferObj, MAP_INTERNAL); 481 } 482} 483