pbo.c revision 848b8605
1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5848b8605Smrg * Copyright (C) 2009-2011 VMware, Inc. All Rights Reserved. 6848b8605Smrg * 7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 8848b8605Smrg * copy of this software and associated documentation files (the "Software"), 9848b8605Smrg * to deal in the Software without restriction, including without limitation 10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 12848b8605Smrg * Software is furnished to do so, subject to the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice shall be included 15848b8605Smrg * in all copies or substantial portions of the Software. 16848b8605Smrg * 17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 24848b8605Smrg */ 25848b8605Smrg 26848b8605Smrg 27848b8605Smrg/** 28848b8605Smrg * \file pbo.c 29848b8605Smrg * \brief Functions related to Pixel Buffer Objects. 30848b8605Smrg */ 31848b8605Smrg 32848b8605Smrg 33848b8605Smrg 34848b8605Smrg#include "glheader.h" 35848b8605Smrg#include "bufferobj.h" 36848b8605Smrg#include "glformats.h" 37848b8605Smrg#include "image.h" 38848b8605Smrg#include "imports.h" 39848b8605Smrg#include "mtypes.h" 40848b8605Smrg#include "pbo.h" 41848b8605Smrg 42848b8605Smrg 43848b8605Smrg 44848b8605Smrg/** 45848b8605Smrg * When we're about to read pixel data out of a PBO (via glDrawPixels, 46848b8605Smrg * glTexImage, etc) or write data into a PBO (via glReadPixels, 47848b8605Smrg * glGetTexImage, etc) we call this function to check that we're not 48848b8605Smrg * going to read/write out of bounds. 49848b8605Smrg * 50848b8605Smrg * XXX This would also be a convenient time to check that the PBO isn't 51848b8605Smrg * currently mapped. Whoever calls this function should check for that. 52848b8605Smrg * Remember, we can't use a PBO when it's mapped! 53848b8605Smrg * 54848b8605Smrg * If we're not using a PBO, this is a no-op. 55848b8605Smrg * 56848b8605Smrg * \param width width of image to read/write 57848b8605Smrg * \param height height of image to read/write 58848b8605Smrg * \param depth depth of image to read/write 59848b8605Smrg * \param format format of image to read/write 60848b8605Smrg * \param type datatype of image to read/write 61848b8605Smrg * \param clientMemSize the maximum number of bytes to read/write 62848b8605Smrg * \param ptr the user-provided pointer/offset 63848b8605Smrg * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would 64848b8605Smrg * go out of bounds. 65848b8605Smrg */ 66848b8605SmrgGLboolean 67848b8605Smrg_mesa_validate_pbo_access(GLuint dimensions, 68848b8605Smrg const struct gl_pixelstore_attrib *pack, 69848b8605Smrg GLsizei width, GLsizei height, GLsizei depth, 70848b8605Smrg GLenum format, GLenum type, GLsizei clientMemSize, 71848b8605Smrg const GLvoid *ptr) 72848b8605Smrg{ 73848b8605Smrg /* unsigned, to detect overflow/wrap-around */ 74848b8605Smrg uintptr_t start, end, offset, size; 75848b8605Smrg 76848b8605Smrg /* If no PBO is bound, 'ptr' is a pointer to client memory containing 77848b8605Smrg 'clientMemSize' bytes. 78848b8605Smrg If a PBO is bound, 'ptr' is an offset into the bound PBO. 79848b8605Smrg In that case 'clientMemSize' is ignored: we just use the PBO's size. 80848b8605Smrg */ 81848b8605Smrg if (!_mesa_is_bufferobj(pack->BufferObj)) { 82848b8605Smrg offset = 0; 83848b8605Smrg size = clientMemSize; 84848b8605Smrg } else { 85848b8605Smrg offset = (uintptr_t)ptr; 86848b8605Smrg size = pack->BufferObj->Size; 87848b8605Smrg /* The ARB_pixel_buffer_object spec says: 88848b8605Smrg * "INVALID_OPERATION is generated by ColorTable, ColorSubTable, 89848b8605Smrg * ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D, 90848b8605Smrg * TexImage1D, TexImage2D, TexImage3D, TexSubImage1D, 91848b8605Smrg * TexSubImage2D, TexSubImage3D, and DrawPixels if the current 92848b8605Smrg * PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data 93848b8605Smrg * parameter is not evenly divisible into the number of basic machine 94848b8605Smrg * units needed to store in memory a datum indicated by the type 95848b8605Smrg * parameter." 96848b8605Smrg */ 97848b8605Smrg if (type != GL_BITMAP && 98848b8605Smrg (offset % _mesa_sizeof_packed_type(type))) 99848b8605Smrg return GL_FALSE; 100848b8605Smrg } 101848b8605Smrg 102848b8605Smrg if (size == 0) 103848b8605Smrg /* no buffer! */ 104848b8605Smrg return GL_FALSE; 105848b8605Smrg 106848b8605Smrg /* get the offset to the first pixel we'll read/write */ 107848b8605Smrg start = _mesa_image_offset(dimensions, pack, width, height, 108848b8605Smrg format, type, 0, 0, 0); 109848b8605Smrg 110848b8605Smrg /* get the offset to just past the last pixel we'll read/write */ 111848b8605Smrg end = _mesa_image_offset(dimensions, pack, width, height, 112848b8605Smrg format, type, depth-1, height-1, width); 113848b8605Smrg 114848b8605Smrg start += offset; 115848b8605Smrg end += offset; 116848b8605Smrg 117848b8605Smrg if (start > size) { 118848b8605Smrg /* This will catch negative values / wrap-around */ 119848b8605Smrg return GL_FALSE; 120848b8605Smrg } 121848b8605Smrg if (end > size) { 122848b8605Smrg /* Image read/write goes beyond end of buffer */ 123848b8605Smrg return GL_FALSE; 124848b8605Smrg } 125848b8605Smrg 126848b8605Smrg /* OK! */ 127848b8605Smrg return GL_TRUE; 128848b8605Smrg} 129848b8605Smrg 130848b8605Smrg 131848b8605Smrg/** 132848b8605Smrg * For commands that read from a PBO (glDrawPixels, glTexImage, 133848b8605Smrg * glPolygonStipple, etc), if we're reading from a PBO, map it read-only 134848b8605Smrg * and return the pointer into the PBO. If we're not reading from a 135848b8605Smrg * PBO, return \p src as-is. 136848b8605Smrg * If non-null return, must call _mesa_unmap_pbo_source() when done. 137848b8605Smrg * 138848b8605Smrg * \return NULL if error, else pointer to start of data 139848b8605Smrg */ 140848b8605Smrgconst GLvoid * 141848b8605Smrg_mesa_map_pbo_source(struct gl_context *ctx, 142848b8605Smrg const struct gl_pixelstore_attrib *unpack, 143848b8605Smrg const GLvoid *src) 144848b8605Smrg{ 145848b8605Smrg const GLubyte *buf; 146848b8605Smrg 147848b8605Smrg if (_mesa_is_bufferobj(unpack->BufferObj)) { 148848b8605Smrg /* unpack from PBO */ 149848b8605Smrg buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 150848b8605Smrg unpack->BufferObj->Size, 151848b8605Smrg GL_MAP_READ_BIT, 152848b8605Smrg unpack->BufferObj, 153848b8605Smrg MAP_INTERNAL); 154848b8605Smrg if (!buf) 155848b8605Smrg return NULL; 156848b8605Smrg 157848b8605Smrg buf = ADD_POINTERS(buf, src); 158848b8605Smrg } 159848b8605Smrg else { 160848b8605Smrg /* unpack from normal memory */ 161848b8605Smrg buf = src; 162848b8605Smrg } 163848b8605Smrg 164848b8605Smrg return buf; 165848b8605Smrg} 166848b8605Smrg 167848b8605Smrg 168848b8605Smrg/** 169848b8605Smrg * Combine PBO-read validation and mapping. 170848b8605Smrg * If any GL errors are detected, they'll be recorded and NULL returned. 171848b8605Smrg * \sa _mesa_validate_pbo_access 172848b8605Smrg * \sa _mesa_map_pbo_source 173848b8605Smrg * A call to this function should have a matching call to 174848b8605Smrg * _mesa_unmap_pbo_source(). 175848b8605Smrg */ 176848b8605Smrgconst GLvoid * 177848b8605Smrg_mesa_map_validate_pbo_source(struct gl_context *ctx, 178848b8605Smrg GLuint dimensions, 179848b8605Smrg const struct gl_pixelstore_attrib *unpack, 180848b8605Smrg GLsizei width, GLsizei height, GLsizei depth, 181848b8605Smrg GLenum format, GLenum type, 182848b8605Smrg GLsizei clientMemSize, 183848b8605Smrg const GLvoid *ptr, const char *where) 184848b8605Smrg{ 185848b8605Smrg ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 186848b8605Smrg 187848b8605Smrg if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, 188848b8605Smrg format, type, clientMemSize, ptr)) { 189848b8605Smrg if (_mesa_is_bufferobj(unpack->BufferObj)) { 190848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 191848b8605Smrg "%s(out of bounds PBO access)", where); 192848b8605Smrg } else { 193848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 194848b8605Smrg "%s(out of bounds access: bufSize (%d) is too small)", 195848b8605Smrg where, clientMemSize); 196848b8605Smrg } 197848b8605Smrg return NULL; 198848b8605Smrg } 199848b8605Smrg 200848b8605Smrg if (!_mesa_is_bufferobj(unpack->BufferObj)) { 201848b8605Smrg /* non-PBO access: no further validation to be done */ 202848b8605Smrg return ptr; 203848b8605Smrg } 204848b8605Smrg 205848b8605Smrg if (_mesa_check_disallowed_mapping(unpack->BufferObj)) { 206848b8605Smrg /* buffer is already mapped - that's an error */ 207848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); 208848b8605Smrg return NULL; 209848b8605Smrg } 210848b8605Smrg 211848b8605Smrg ptr = _mesa_map_pbo_source(ctx, unpack, ptr); 212848b8605Smrg return ptr; 213848b8605Smrg} 214848b8605Smrg 215848b8605Smrg 216848b8605Smrg/** 217848b8605Smrg * Counterpart to _mesa_map_pbo_source() 218848b8605Smrg */ 219848b8605Smrgvoid 220848b8605Smrg_mesa_unmap_pbo_source(struct gl_context *ctx, 221848b8605Smrg const struct gl_pixelstore_attrib *unpack) 222848b8605Smrg{ 223848b8605Smrg ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ 224848b8605Smrg if (_mesa_is_bufferobj(unpack->BufferObj)) { 225848b8605Smrg ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL); 226848b8605Smrg } 227848b8605Smrg} 228848b8605Smrg 229848b8605Smrg 230848b8605Smrg/** 231848b8605Smrg * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), 232848b8605Smrg * if we're writing to a PBO, map it write-only and return the pointer 233848b8605Smrg * into the PBO. If we're not writing to a PBO, return \p dst as-is. 234848b8605Smrg * If non-null return, must call _mesa_unmap_pbo_dest() when done. 235848b8605Smrg * 236848b8605Smrg * \return NULL if error, else pointer to start of data 237848b8605Smrg */ 238848b8605Smrgvoid * 239848b8605Smrg_mesa_map_pbo_dest(struct gl_context *ctx, 240848b8605Smrg const struct gl_pixelstore_attrib *pack, 241848b8605Smrg GLvoid *dest) 242848b8605Smrg{ 243848b8605Smrg void *buf; 244848b8605Smrg 245848b8605Smrg if (_mesa_is_bufferobj(pack->BufferObj)) { 246848b8605Smrg /* pack into PBO */ 247848b8605Smrg buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 248848b8605Smrg pack->BufferObj->Size, 249848b8605Smrg GL_MAP_WRITE_BIT, 250848b8605Smrg pack->BufferObj, 251848b8605Smrg MAP_INTERNAL); 252848b8605Smrg if (!buf) 253848b8605Smrg return NULL; 254848b8605Smrg 255848b8605Smrg buf = ADD_POINTERS(buf, dest); 256848b8605Smrg } 257848b8605Smrg else { 258848b8605Smrg /* pack to normal memory */ 259848b8605Smrg buf = dest; 260848b8605Smrg } 261848b8605Smrg 262848b8605Smrg return buf; 263848b8605Smrg} 264848b8605Smrg 265848b8605Smrg 266848b8605Smrg/** 267848b8605Smrg * Combine PBO-write validation and mapping. 268848b8605Smrg * If any GL errors are detected, they'll be recorded and NULL returned. 269848b8605Smrg * \sa _mesa_validate_pbo_access 270848b8605Smrg * \sa _mesa_map_pbo_dest 271848b8605Smrg * A call to this function should have a matching call to 272848b8605Smrg * _mesa_unmap_pbo_dest(). 273848b8605Smrg */ 274848b8605SmrgGLvoid * 275848b8605Smrg_mesa_map_validate_pbo_dest(struct gl_context *ctx, 276848b8605Smrg GLuint dimensions, 277848b8605Smrg const struct gl_pixelstore_attrib *unpack, 278848b8605Smrg GLsizei width, GLsizei height, GLsizei depth, 279848b8605Smrg GLenum format, GLenum type, GLsizei clientMemSize, 280848b8605Smrg GLvoid *ptr, const char *where) 281848b8605Smrg{ 282848b8605Smrg ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 283848b8605Smrg 284848b8605Smrg if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, 285848b8605Smrg format, type, clientMemSize, ptr)) { 286848b8605Smrg if (_mesa_is_bufferobj(unpack->BufferObj)) { 287848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 288848b8605Smrg "%s(out of bounds PBO access)", where); 289848b8605Smrg } else { 290848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 291848b8605Smrg "%s(out of bounds access: bufSize (%d) is too small)", 292848b8605Smrg where, clientMemSize); 293848b8605Smrg } 294848b8605Smrg return NULL; 295848b8605Smrg } 296848b8605Smrg 297848b8605Smrg if (!_mesa_is_bufferobj(unpack->BufferObj)) { 298848b8605Smrg /* non-PBO access: no further validation to be done */ 299848b8605Smrg return ptr; 300848b8605Smrg } 301848b8605Smrg 302848b8605Smrg if (_mesa_check_disallowed_mapping(unpack->BufferObj)) { 303848b8605Smrg /* buffer is already mapped - that's an error */ 304848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); 305848b8605Smrg return NULL; 306848b8605Smrg } 307848b8605Smrg 308848b8605Smrg ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); 309848b8605Smrg return ptr; 310848b8605Smrg} 311848b8605Smrg 312848b8605Smrg 313848b8605Smrg/** 314848b8605Smrg * Counterpart to _mesa_map_pbo_dest() 315848b8605Smrg */ 316848b8605Smrgvoid 317848b8605Smrg_mesa_unmap_pbo_dest(struct gl_context *ctx, 318848b8605Smrg const struct gl_pixelstore_attrib *pack) 319848b8605Smrg{ 320848b8605Smrg ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ 321848b8605Smrg if (_mesa_is_bufferobj(pack->BufferObj)) { 322848b8605Smrg ctx->Driver.UnmapBuffer(ctx, pack->BufferObj, MAP_INTERNAL); 323848b8605Smrg } 324848b8605Smrg} 325848b8605Smrg 326848b8605Smrg 327848b8605Smrg/** 328848b8605Smrg * Check if an unpack PBO is active prior to fetching a texture image. 329848b8605Smrg * If so, do bounds checking and map the buffer into main memory. 330848b8605Smrg * Any errors detected will be recorded. 331848b8605Smrg * The caller _must_ call _mesa_unmap_teximage_pbo() too! 332848b8605Smrg */ 333848b8605Smrgconst GLvoid * 334848b8605Smrg_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, 335848b8605Smrg GLsizei width, GLsizei height, GLsizei depth, 336848b8605Smrg GLenum format, GLenum type, const GLvoid *pixels, 337848b8605Smrg const struct gl_pixelstore_attrib *unpack, 338848b8605Smrg const char *funcName) 339848b8605Smrg{ 340848b8605Smrg GLubyte *buf; 341848b8605Smrg 342848b8605Smrg if (!_mesa_is_bufferobj(unpack->BufferObj)) { 343848b8605Smrg /* no PBO */ 344848b8605Smrg return pixels; 345848b8605Smrg } 346848b8605Smrg if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, 347848b8605Smrg format, type, INT_MAX, pixels)) { 348848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)", 349848b8605Smrg funcName, dimensions); 350848b8605Smrg return NULL; 351848b8605Smrg } 352848b8605Smrg 353848b8605Smrg buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, 354848b8605Smrg unpack->BufferObj->Size, 355848b8605Smrg GL_MAP_READ_BIT, 356848b8605Smrg unpack->BufferObj, 357848b8605Smrg MAP_INTERNAL); 358848b8605Smrg if (!buf) { 359848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName, 360848b8605Smrg dimensions); 361848b8605Smrg return NULL; 362848b8605Smrg } 363848b8605Smrg 364848b8605Smrg return ADD_POINTERS(buf, pixels); 365848b8605Smrg} 366848b8605Smrg 367848b8605Smrg 368848b8605Smrg/** 369848b8605Smrg * Check if an unpack PBO is active prior to fetching a compressed texture 370848b8605Smrg * image. 371848b8605Smrg * If so, do bounds checking and map the buffer into main memory. 372848b8605Smrg * Any errors detected will be recorded. 373848b8605Smrg * The caller _must_ call _mesa_unmap_teximage_pbo() too! 374848b8605Smrg */ 375848b8605Smrgconst GLvoid * 376848b8605Smrg_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, 377848b8605Smrg GLuint dimensions, GLsizei imageSize, 378848b8605Smrg const GLvoid *pixels, 379848b8605Smrg const struct gl_pixelstore_attrib *packing, 380848b8605Smrg const char *funcName) 381848b8605Smrg{ 382848b8605Smrg GLubyte *buf; 383848b8605Smrg 384848b8605Smrg if (!_mesa_is_bufferobj(packing->BufferObj)) { 385848b8605Smrg /* not using a PBO - return pointer unchanged */ 386848b8605Smrg return pixels; 387848b8605Smrg } 388848b8605Smrg if ((const GLubyte *) pixels + imageSize > 389848b8605Smrg ((const GLubyte *) 0) + packing->BufferObj->Size) { 390848b8605Smrg /* out of bounds read! */ 391848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)", 392848b8605Smrg funcName, dimensions); 393848b8605Smrg return NULL; 394848b8605Smrg } 395848b8605Smrg 396848b8605Smrg buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0, 397848b8605Smrg packing->BufferObj->Size, 398848b8605Smrg GL_MAP_READ_BIT, 399848b8605Smrg packing->BufferObj, 400848b8605Smrg MAP_INTERNAL); 401848b8605Smrg if (!buf) { 402848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName, 403848b8605Smrg dimensions); 404848b8605Smrg return NULL; 405848b8605Smrg } 406848b8605Smrg 407848b8605Smrg return ADD_POINTERS(buf, pixels); 408848b8605Smrg} 409848b8605Smrg 410848b8605Smrg 411848b8605Smrg/** 412848b8605Smrg * This function must be called after either of the validate_pbo_*_teximage() 413848b8605Smrg * functions. It unmaps the PBO buffer if it was mapped earlier. 414848b8605Smrg */ 415848b8605Smrgvoid 416848b8605Smrg_mesa_unmap_teximage_pbo(struct gl_context *ctx, 417848b8605Smrg const struct gl_pixelstore_attrib *unpack) 418848b8605Smrg{ 419848b8605Smrg if (_mesa_is_bufferobj(unpack->BufferObj)) { 420848b8605Smrg ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL); 421848b8605Smrg } 422848b8605Smrg} 423