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 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. 23 */ 24 25 26 /** 27 * \file pbo.c 28 * \brief Functions related to Pixel Buffer Objects. 29 */ 30 31 32 33 #include "glheader.h" 34 #include "bufferobj.h" 35 #include "glformats.h" 36 #include "image.h" 37 #include "imports.h" 38 #include "mtypes.h" 39 #include "pbo.h" 40 41 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 */ 65 GLboolean 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 (!_mesa_is_bufferobj(pack->BufferObj)) { 81 offset = 0; 82 size = 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 /* 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); 108 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); 112 113 start += offset; 114 end += offset; 115 116 if (start > size) { 117 /* This will catch negative values / wrap-around */ 118 return GL_FALSE; 119 } 120 if (end > size) { 121 /* Image read/write goes beyond end of buffer */ 122 return GL_FALSE; 123 } 124 125 /* OK! */ 126 return GL_TRUE; 127 } 128 129 130 /** 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. 136 * 137 * \return NULL if error, else pointer to start of data 138 */ 139 const GLvoid * 140 _mesa_map_pbo_source(struct gl_context *ctx, 141 const struct gl_pixelstore_attrib *unpack, 142 const GLvoid *src) 143 { 144 const GLubyte *buf; 145 146 if (_mesa_is_bufferobj(unpack->BufferObj)) { 147 /* unpack from PBO */ 148 buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 149 unpack->BufferObj->Size, 150 GL_MAP_READ_BIT, 151 unpack->BufferObj); 152 if (!buf) 153 return NULL; 154 155 buf = ADD_POINTERS(buf, src); 156 } 157 else { 158 /* unpack from normal memory */ 159 buf = src; 160 } 161 162 return buf; 163 } 164 165 166 /** 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(). 173 */ 174 const GLvoid * 175 _mesa_map_validate_pbo_source(struct gl_context *ctx, 176 GLuint dimensions, 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) 182 { 183 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 184 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); 190 } else { 191 _mesa_error(ctx, GL_INVALID_OPERATION, 192 "%s(out of bounds access: bufSize (%d) is too small)", 193 where, clientMemSize); 194 } 195 return NULL; 196 } 197 198 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 199 /* non-PBO access: no further validation to be done */ 200 return ptr; 201 } 202 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); 206 return NULL; 207 } 208 209 ptr = _mesa_map_pbo_source(ctx, unpack, ptr); 210 return ptr; 211 } 212 213 214 /** 215 * Counterpart to _mesa_map_pbo_source() 216 */ 217 void 218 _mesa_unmap_pbo_source(struct gl_context *ctx, 219 const struct gl_pixelstore_attrib *unpack) 220 { 221 ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ 222 if (_mesa_is_bufferobj(unpack->BufferObj)) { 223 ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj); 224 } 225 } 226 227 228 /** 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. 233 * 234 * \return NULL if error, else pointer to start of data 235 */ 236 void * 237 _mesa_map_pbo_dest(struct gl_context *ctx, 238 const struct gl_pixelstore_attrib *pack, 239 GLvoid *dest) 240 { 241 void *buf; 242 243 if (_mesa_is_bufferobj(pack->BufferObj)) { 244 /* pack into PBO */ 245 buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 246 pack->BufferObj->Size, 247 GL_MAP_WRITE_BIT, 248 pack->BufferObj); 249 if (!buf) 250 return NULL; 251 252 buf = ADD_POINTERS(buf, dest); 253 } 254 else { 255 /* pack to normal memory */ 256 buf = dest; 257 } 258 259 return buf; 260 } 261 262 263 /** 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(). 270 */ 271 GLvoid * 272 _mesa_map_validate_pbo_dest(struct gl_context *ctx, 273 GLuint dimensions, 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) 278 { 279 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 280 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); 286 } else { 287 _mesa_error(ctx, GL_INVALID_OPERATION, 288 "%s(out of bounds access: bufSize (%d) is too small)", 289 where, clientMemSize); 290 } 291 return NULL; 292 } 293 294 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 295 /* non-PBO access: no further validation to be done */ 296 return ptr; 297 } 298 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); 302 return NULL; 303 } 304 305 ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); 306 return ptr; 307 } 308 309 310 /** 311 * Counterpart to _mesa_map_pbo_dest() 312 */ 313 void 314 _mesa_unmap_pbo_dest(struct gl_context *ctx, 315 const struct gl_pixelstore_attrib *pack) 316 { 317 ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ 318 if (_mesa_is_bufferobj(pack->BufferObj)) { 319 ctx->Driver.UnmapBuffer(ctx, pack->BufferObj); 320 } 321 } 322 323 324 /** 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! 329 */ 330 const GLvoid * 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) 336 { 337 GLubyte *buf; 338 339 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 340 /* no PBO */ 341 return pixels; 342 } 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)"); 346 return NULL; 347 } 348 349 buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 350 unpack->BufferObj->Size, 351 GL_MAP_READ_BIT, 352 unpack->BufferObj); 353 if (!buf) { 354 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)"); 355 return NULL; 356 } 357 358 return ADD_POINTERS(buf, pixels); 359 } 360 361 362 /** 363 * Check if an unpack PBO is active prior to fetching a compressed texture 364 * image. 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! 368 */ 369 const GLvoid * 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) 374 { 375 GLubyte *buf; 376 377 if (!_mesa_is_bufferobj(packing->BufferObj)) { 378 /* not using a PBO - return pointer unchanged */ 379 return pixels; 380 } 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)"); 385 return NULL; 386 } 387 388 buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0, 389 packing->BufferObj->Size, 390 GL_MAP_READ_BIT, 391 packing->BufferObj); 392 if (!buf) { 393 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped"); 394 return NULL; 395 } 396 397 return ADD_POINTERS(buf, pixels); 398 } 399 400 401 /** 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. 404 */ 405 void 406 _mesa_unmap_teximage_pbo(struct gl_context *ctx, 407 const struct gl_pixelstore_attrib *unpack) 408 { 409 if (_mesa_is_bufferobj(unpack->BufferObj)) { 410 ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj); 411 } 412 } 413