pbo.c revision 3464ebd5
13464ebd5Sriastradh/* 23464ebd5Sriastradh * Mesa 3-D graphics library 33464ebd5Sriastradh * 43464ebd5Sriastradh * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 53464ebd5Sriastradh * Copyright (C) 2009-2011 VMware, Inc. All Rights Reserved. 63464ebd5Sriastradh * 73464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 83464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"), 93464ebd5Sriastradh * to deal in the Software without restriction, including without limitation 103464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 113464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the 123464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions: 133464ebd5Sriastradh * 143464ebd5Sriastradh * The above copyright notice and this permission notice shall be included 153464ebd5Sriastradh * in all copies or substantial portions of the Software. 163464ebd5Sriastradh * 173464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 183464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 193464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 203464ebd5Sriastradh * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 213464ebd5Sriastradh * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 223464ebd5Sriastradh * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 233464ebd5Sriastradh */ 243464ebd5Sriastradh 253464ebd5Sriastradh 263464ebd5Sriastradh/** 273464ebd5Sriastradh * \file pbo.c 283464ebd5Sriastradh * \brief Functions related to Pixel Buffer Objects. 293464ebd5Sriastradh */ 303464ebd5Sriastradh 313464ebd5Sriastradh 323464ebd5Sriastradh 333464ebd5Sriastradh#include "glheader.h" 343464ebd5Sriastradh#include "bufferobj.h" 353464ebd5Sriastradh#include "image.h" 363464ebd5Sriastradh#include "imports.h" 373464ebd5Sriastradh#include "mtypes.h" 383464ebd5Sriastradh#include "pbo.h" 393464ebd5Sriastradh 403464ebd5Sriastradh 413464ebd5Sriastradh 423464ebd5Sriastradh/** 433464ebd5Sriastradh * When we're about to read pixel data out of a PBO (via glDrawPixels, 443464ebd5Sriastradh * glTexImage, etc) or write data into a PBO (via glReadPixels, 453464ebd5Sriastradh * glGetTexImage, etc) we call this function to check that we're not 463464ebd5Sriastradh * going to read/write out of bounds. 473464ebd5Sriastradh * 483464ebd5Sriastradh * XXX This would also be a convenient time to check that the PBO isn't 493464ebd5Sriastradh * currently mapped. Whoever calls this function should check for that. 503464ebd5Sriastradh * Remember, we can't use a PBO when it's mapped! 513464ebd5Sriastradh * 523464ebd5Sriastradh * If we're not using a PBO, this is a no-op. 533464ebd5Sriastradh * 543464ebd5Sriastradh * \param width width of image to read/write 553464ebd5Sriastradh * \param height height of image to read/write 563464ebd5Sriastradh * \param depth depth of image to read/write 573464ebd5Sriastradh * \param format format of image to read/write 583464ebd5Sriastradh * \param type datatype of image to read/write 593464ebd5Sriastradh * \param clientMemSize the maximum number of bytes to read/write 603464ebd5Sriastradh * \param ptr the user-provided pointer/offset 613464ebd5Sriastradh * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would 623464ebd5Sriastradh * go out of bounds. 633464ebd5Sriastradh */ 643464ebd5SriastradhGLboolean 653464ebd5Sriastradh_mesa_validate_pbo_access(GLuint dimensions, 663464ebd5Sriastradh const struct gl_pixelstore_attrib *pack, 673464ebd5Sriastradh GLsizei width, GLsizei height, GLsizei depth, 683464ebd5Sriastradh GLenum format, GLenum type, GLsizei clientMemSize, 693464ebd5Sriastradh const GLvoid *ptr) 703464ebd5Sriastradh{ 713464ebd5Sriastradh const GLvoid *start, *end, *offset; 723464ebd5Sriastradh const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ 733464ebd5Sriastradh 743464ebd5Sriastradh /* If no PBO is bound, 'ptr' is a pointer to client memory containing 753464ebd5Sriastradh 'clientMemSize' bytes. 763464ebd5Sriastradh If a PBO is bound, 'ptr' is an offset into the bound PBO. 773464ebd5Sriastradh In that case 'clientMemSize' is ignored: we just use the PBO's size. 783464ebd5Sriastradh */ 793464ebd5Sriastradh if (!_mesa_is_bufferobj(pack->BufferObj)) { 803464ebd5Sriastradh offset = 0; 813464ebd5Sriastradh sizeAddr = ((const GLubyte *) 0) + clientMemSize; 823464ebd5Sriastradh } else { 833464ebd5Sriastradh offset = ptr; 843464ebd5Sriastradh sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; 853464ebd5Sriastradh /* The ARB_pixel_buffer_object spec says: 863464ebd5Sriastradh * "INVALID_OPERATION is generated by ColorTable, ColorSubTable, 873464ebd5Sriastradh * ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D, 883464ebd5Sriastradh * TexImage1D, TexImage2D, TexImage3D, TexSubImage1D, 893464ebd5Sriastradh * TexSubImage2D, TexSubImage3D, and DrawPixels if the current 903464ebd5Sriastradh * PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data 913464ebd5Sriastradh * parameter is not evenly divisible into the number of basic machine 923464ebd5Sriastradh * units needed to store in memory a datum indicated by the type 933464ebd5Sriastradh * parameter." 943464ebd5Sriastradh */ 953464ebd5Sriastradh if (type != GL_BITMAP && 963464ebd5Sriastradh ((GLintptr)offset % _mesa_sizeof_packed_type(type))) 973464ebd5Sriastradh return GL_FALSE; 983464ebd5Sriastradh } 993464ebd5Sriastradh 1003464ebd5Sriastradh if (sizeAddr == 0) 1013464ebd5Sriastradh /* no buffer! */ 1023464ebd5Sriastradh return GL_FALSE; 1033464ebd5Sriastradh 1043464ebd5Sriastradh /* get the offset to the first pixel we'll read/write */ 1053464ebd5Sriastradh start = _mesa_image_address(dimensions, pack, offset, width, height, 1063464ebd5Sriastradh format, type, 0, 0, 0); 1073464ebd5Sriastradh 1083464ebd5Sriastradh /* get the offset to just past the last pixel we'll read/write */ 1093464ebd5Sriastradh end = _mesa_image_address(dimensions, pack, offset, width, height, 1103464ebd5Sriastradh format, type, depth-1, height-1, width); 1113464ebd5Sriastradh 1123464ebd5Sriastradh if ((const GLubyte *) start > sizeAddr) { 1133464ebd5Sriastradh /* This will catch negative values / wrap-around */ 1143464ebd5Sriastradh return GL_FALSE; 1153464ebd5Sriastradh } 1163464ebd5Sriastradh if ((const GLubyte *) end > sizeAddr) { 1173464ebd5Sriastradh /* Image read/write goes beyond end of buffer */ 1183464ebd5Sriastradh return GL_FALSE; 1193464ebd5Sriastradh } 1203464ebd5Sriastradh 1213464ebd5Sriastradh /* OK! */ 1223464ebd5Sriastradh return GL_TRUE; 1233464ebd5Sriastradh} 1243464ebd5Sriastradh 1253464ebd5Sriastradh 1263464ebd5Sriastradh/** 1273464ebd5Sriastradh * For commands that read from a PBO (glDrawPixels, glTexImage, 1283464ebd5Sriastradh * glPolygonStipple, etc), if we're reading from a PBO, map it read-only 1293464ebd5Sriastradh * and return the pointer into the PBO. If we're not reading from a 1303464ebd5Sriastradh * PBO, return \p src as-is. 1313464ebd5Sriastradh * If non-null return, must call _mesa_unmap_pbo_source() when done. 1323464ebd5Sriastradh * 1333464ebd5Sriastradh * \return NULL if error, else pointer to start of data 1343464ebd5Sriastradh */ 1353464ebd5Sriastradhconst GLvoid * 1363464ebd5Sriastradh_mesa_map_pbo_source(struct gl_context *ctx, 1373464ebd5Sriastradh const struct gl_pixelstore_attrib *unpack, 1383464ebd5Sriastradh const GLvoid *src) 1393464ebd5Sriastradh{ 1403464ebd5Sriastradh const GLubyte *buf; 1413464ebd5Sriastradh 1423464ebd5Sriastradh if (_mesa_is_bufferobj(unpack->BufferObj)) { 1433464ebd5Sriastradh /* unpack from PBO */ 1443464ebd5Sriastradh buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 1453464ebd5Sriastradh GL_READ_ONLY_ARB, 1463464ebd5Sriastradh unpack->BufferObj); 1473464ebd5Sriastradh if (!buf) 1483464ebd5Sriastradh return NULL; 1493464ebd5Sriastradh 1503464ebd5Sriastradh buf = ADD_POINTERS(buf, src); 1513464ebd5Sriastradh } 1523464ebd5Sriastradh else { 1533464ebd5Sriastradh /* unpack from normal memory */ 1543464ebd5Sriastradh buf = src; 1553464ebd5Sriastradh } 1563464ebd5Sriastradh 1573464ebd5Sriastradh return buf; 1583464ebd5Sriastradh} 1593464ebd5Sriastradh 1603464ebd5Sriastradh 1613464ebd5Sriastradh/** 1623464ebd5Sriastradh * Combine PBO-read validation and mapping. 1633464ebd5Sriastradh * If any GL errors are detected, they'll be recorded and NULL returned. 1643464ebd5Sriastradh * \sa _mesa_validate_pbo_access 1653464ebd5Sriastradh * \sa _mesa_map_pbo_source 1663464ebd5Sriastradh * A call to this function should have a matching call to 1673464ebd5Sriastradh * _mesa_unmap_pbo_source(). 1683464ebd5Sriastradh */ 1693464ebd5Sriastradhconst GLvoid * 1703464ebd5Sriastradh_mesa_map_validate_pbo_source(struct gl_context *ctx, 1713464ebd5Sriastradh GLuint dimensions, 1723464ebd5Sriastradh const struct gl_pixelstore_attrib *unpack, 1733464ebd5Sriastradh GLsizei width, GLsizei height, GLsizei depth, 1743464ebd5Sriastradh GLenum format, GLenum type, GLsizei clientMemSize, 1753464ebd5Sriastradh const GLvoid *ptr, const char *where) 1763464ebd5Sriastradh{ 1773464ebd5Sriastradh ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 1783464ebd5Sriastradh 1793464ebd5Sriastradh if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, 1803464ebd5Sriastradh format, type, clientMemSize, ptr)) { 1813464ebd5Sriastradh if (_mesa_is_bufferobj(unpack->BufferObj)) { 1823464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 1833464ebd5Sriastradh "%s(out of bounds PBO access)", where); 1843464ebd5Sriastradh } else { 1853464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 1863464ebd5Sriastradh "%s(out of bounds access: bufSize (%d) is too small)", 1873464ebd5Sriastradh where, clientMemSize); 1883464ebd5Sriastradh } 1893464ebd5Sriastradh return NULL; 1903464ebd5Sriastradh } 1913464ebd5Sriastradh 1923464ebd5Sriastradh if (!_mesa_is_bufferobj(unpack->BufferObj)) { 1933464ebd5Sriastradh /* non-PBO access: no further validation to be done */ 1943464ebd5Sriastradh return ptr; 1953464ebd5Sriastradh } 1963464ebd5Sriastradh 1973464ebd5Sriastradh if (_mesa_bufferobj_mapped(unpack->BufferObj)) { 1983464ebd5Sriastradh /* buffer is already mapped - that's an error */ 1993464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); 2003464ebd5Sriastradh return NULL; 2013464ebd5Sriastradh } 2023464ebd5Sriastradh 2033464ebd5Sriastradh ptr = _mesa_map_pbo_source(ctx, unpack, ptr); 2043464ebd5Sriastradh return ptr; 2053464ebd5Sriastradh} 2063464ebd5Sriastradh 2073464ebd5Sriastradh 2083464ebd5Sriastradh/** 2093464ebd5Sriastradh * Counterpart to _mesa_map_pbo_source() 2103464ebd5Sriastradh */ 2113464ebd5Sriastradhvoid 2123464ebd5Sriastradh_mesa_unmap_pbo_source(struct gl_context *ctx, 2133464ebd5Sriastradh const struct gl_pixelstore_attrib *unpack) 2143464ebd5Sriastradh{ 2153464ebd5Sriastradh ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ 2163464ebd5Sriastradh if (_mesa_is_bufferobj(unpack->BufferObj)) { 2173464ebd5Sriastradh ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 2183464ebd5Sriastradh unpack->BufferObj); 2193464ebd5Sriastradh } 2203464ebd5Sriastradh} 2213464ebd5Sriastradh 2223464ebd5Sriastradh 2233464ebd5Sriastradh/** 2243464ebd5Sriastradh * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), 2253464ebd5Sriastradh * if we're writing to a PBO, map it write-only and return the pointer 2263464ebd5Sriastradh * into the PBO. If we're not writing to a PBO, return \p dst as-is. 2273464ebd5Sriastradh * If non-null return, must call _mesa_unmap_pbo_dest() when done. 2283464ebd5Sriastradh * 2293464ebd5Sriastradh * \return NULL if error, else pointer to start of data 2303464ebd5Sriastradh */ 2313464ebd5Sriastradhvoid * 2323464ebd5Sriastradh_mesa_map_pbo_dest(struct gl_context *ctx, 2333464ebd5Sriastradh const struct gl_pixelstore_attrib *pack, 2343464ebd5Sriastradh GLvoid *dest) 2353464ebd5Sriastradh{ 2363464ebd5Sriastradh void *buf; 2373464ebd5Sriastradh 2383464ebd5Sriastradh if (_mesa_is_bufferobj(pack->BufferObj)) { 2393464ebd5Sriastradh /* pack into PBO */ 2403464ebd5Sriastradh buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, 2413464ebd5Sriastradh GL_WRITE_ONLY_ARB, 2423464ebd5Sriastradh pack->BufferObj); 2433464ebd5Sriastradh if (!buf) 2443464ebd5Sriastradh return NULL; 2453464ebd5Sriastradh 2463464ebd5Sriastradh buf = ADD_POINTERS(buf, dest); 2473464ebd5Sriastradh } 2483464ebd5Sriastradh else { 2493464ebd5Sriastradh /* pack to normal memory */ 2503464ebd5Sriastradh buf = dest; 2513464ebd5Sriastradh } 2523464ebd5Sriastradh 2533464ebd5Sriastradh return buf; 2543464ebd5Sriastradh} 2553464ebd5Sriastradh 2563464ebd5Sriastradh 2573464ebd5Sriastradh/** 2583464ebd5Sriastradh * Combine PBO-write validation and mapping. 2593464ebd5Sriastradh * If any GL errors are detected, they'll be recorded and NULL returned. 2603464ebd5Sriastradh * \sa _mesa_validate_pbo_access 2613464ebd5Sriastradh * \sa _mesa_map_pbo_dest 2623464ebd5Sriastradh * A call to this function should have a matching call to 2633464ebd5Sriastradh * _mesa_unmap_pbo_dest(). 2643464ebd5Sriastradh */ 2653464ebd5SriastradhGLvoid * 2663464ebd5Sriastradh_mesa_map_validate_pbo_dest(struct gl_context *ctx, 2673464ebd5Sriastradh GLuint dimensions, 2683464ebd5Sriastradh const struct gl_pixelstore_attrib *unpack, 2693464ebd5Sriastradh GLsizei width, GLsizei height, GLsizei depth, 2703464ebd5Sriastradh GLenum format, GLenum type, GLsizei clientMemSize, 2713464ebd5Sriastradh GLvoid *ptr, const char *where) 2723464ebd5Sriastradh{ 2733464ebd5Sriastradh ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 2743464ebd5Sriastradh 2753464ebd5Sriastradh if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, 2763464ebd5Sriastradh format, type, clientMemSize, ptr)) { 2773464ebd5Sriastradh if (_mesa_is_bufferobj(unpack->BufferObj)) { 2783464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 2793464ebd5Sriastradh "%s(out of bounds PBO access)", where); 2803464ebd5Sriastradh } else { 2813464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 2823464ebd5Sriastradh "%s(out of bounds access: bufSize (%d) is too small)", 2833464ebd5Sriastradh where, clientMemSize); 2843464ebd5Sriastradh } 2853464ebd5Sriastradh return NULL; 2863464ebd5Sriastradh } 2873464ebd5Sriastradh 2883464ebd5Sriastradh if (!_mesa_is_bufferobj(unpack->BufferObj)) { 2893464ebd5Sriastradh /* non-PBO access: no further validation to be done */ 2903464ebd5Sriastradh return ptr; 2913464ebd5Sriastradh } 2923464ebd5Sriastradh 2933464ebd5Sriastradh if (_mesa_bufferobj_mapped(unpack->BufferObj)) { 2943464ebd5Sriastradh /* buffer is already mapped - that's an error */ 2953464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); 2963464ebd5Sriastradh return NULL; 2973464ebd5Sriastradh } 2983464ebd5Sriastradh 2993464ebd5Sriastradh ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); 3003464ebd5Sriastradh return ptr; 3013464ebd5Sriastradh} 3023464ebd5Sriastradh 3033464ebd5Sriastradh 3043464ebd5Sriastradh/** 3053464ebd5Sriastradh * Counterpart to _mesa_map_pbo_dest() 3063464ebd5Sriastradh */ 3073464ebd5Sriastradhvoid 3083464ebd5Sriastradh_mesa_unmap_pbo_dest(struct gl_context *ctx, 3093464ebd5Sriastradh const struct gl_pixelstore_attrib *pack) 3103464ebd5Sriastradh{ 3113464ebd5Sriastradh ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ 3123464ebd5Sriastradh if (_mesa_is_bufferobj(pack->BufferObj)) { 3133464ebd5Sriastradh ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); 3143464ebd5Sriastradh } 3153464ebd5Sriastradh} 3163464ebd5Sriastradh 3173464ebd5Sriastradh 3183464ebd5Sriastradh/** 3193464ebd5Sriastradh * Check if an unpack PBO is active prior to fetching a texture image. 3203464ebd5Sriastradh * If so, do bounds checking and map the buffer into main memory. 3213464ebd5Sriastradh * Any errors detected will be recorded. 3223464ebd5Sriastradh * The caller _must_ call _mesa_unmap_teximage_pbo() too! 3233464ebd5Sriastradh */ 3243464ebd5Sriastradhconst GLvoid * 3253464ebd5Sriastradh_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, 3263464ebd5Sriastradh GLsizei width, GLsizei height, GLsizei depth, 3273464ebd5Sriastradh GLenum format, GLenum type, const GLvoid *pixels, 3283464ebd5Sriastradh const struct gl_pixelstore_attrib *unpack, 3293464ebd5Sriastradh const char *funcName) 3303464ebd5Sriastradh{ 3313464ebd5Sriastradh GLubyte *buf; 3323464ebd5Sriastradh 3333464ebd5Sriastradh if (!_mesa_is_bufferobj(unpack->BufferObj)) { 3343464ebd5Sriastradh /* no PBO */ 3353464ebd5Sriastradh return pixels; 3363464ebd5Sriastradh } 3373464ebd5Sriastradh if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, 3383464ebd5Sriastradh format, type, INT_MAX, pixels)) { 3393464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); 3403464ebd5Sriastradh return NULL; 3413464ebd5Sriastradh } 3423464ebd5Sriastradh 3433464ebd5Sriastradh buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 3443464ebd5Sriastradh GL_READ_ONLY_ARB, unpack->BufferObj); 3453464ebd5Sriastradh if (!buf) { 3463464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)"); 3473464ebd5Sriastradh return NULL; 3483464ebd5Sriastradh } 3493464ebd5Sriastradh 3503464ebd5Sriastradh return ADD_POINTERS(buf, pixels); 3513464ebd5Sriastradh} 3523464ebd5Sriastradh 3533464ebd5Sriastradh 3543464ebd5Sriastradh/** 3553464ebd5Sriastradh * Check if an unpack PBO is active prior to fetching a compressed texture 3563464ebd5Sriastradh * image. 3573464ebd5Sriastradh * If so, do bounds checking and map the buffer into main memory. 3583464ebd5Sriastradh * Any errors detected will be recorded. 3593464ebd5Sriastradh * The caller _must_ call _mesa_unmap_teximage_pbo() too! 3603464ebd5Sriastradh */ 3613464ebd5Sriastradhconst GLvoid * 3623464ebd5Sriastradh_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, 3633464ebd5Sriastradh GLsizei imageSize, const GLvoid *pixels, 3643464ebd5Sriastradh const struct gl_pixelstore_attrib *packing, 3653464ebd5Sriastradh const char *funcName) 3663464ebd5Sriastradh{ 3673464ebd5Sriastradh GLubyte *buf; 3683464ebd5Sriastradh 3693464ebd5Sriastradh if (!_mesa_is_bufferobj(packing->BufferObj)) { 3703464ebd5Sriastradh /* not using a PBO - return pointer unchanged */ 3713464ebd5Sriastradh return pixels; 3723464ebd5Sriastradh } 3733464ebd5Sriastradh if ((const GLubyte *) pixels + imageSize > 3743464ebd5Sriastradh ((const GLubyte *) 0) + packing->BufferObj->Size) { 3753464ebd5Sriastradh /* out of bounds read! */ 3763464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); 3773464ebd5Sriastradh return NULL; 3783464ebd5Sriastradh } 3793464ebd5Sriastradh 3803464ebd5Sriastradh buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 3813464ebd5Sriastradh GL_READ_ONLY_ARB, packing->BufferObj); 3823464ebd5Sriastradh if (!buf) { 3833464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped"); 3843464ebd5Sriastradh return NULL; 3853464ebd5Sriastradh } 3863464ebd5Sriastradh 3873464ebd5Sriastradh return ADD_POINTERS(buf, pixels); 3883464ebd5Sriastradh} 3893464ebd5Sriastradh 3903464ebd5Sriastradh 3913464ebd5Sriastradh/** 3923464ebd5Sriastradh * This function must be called after either of the validate_pbo_*_teximage() 3933464ebd5Sriastradh * functions. It unmaps the PBO buffer if it was mapped earlier. 3943464ebd5Sriastradh */ 3953464ebd5Sriastradhvoid 3963464ebd5Sriastradh_mesa_unmap_teximage_pbo(struct gl_context *ctx, 3973464ebd5Sriastradh const struct gl_pixelstore_attrib *unpack) 3983464ebd5Sriastradh{ 3993464ebd5Sriastradh if (_mesa_is_bufferobj(unpack->BufferObj)) { 4003464ebd5Sriastradh ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 4013464ebd5Sriastradh unpack->BufferObj); 4023464ebd5Sriastradh } 4033464ebd5Sriastradh} 4043464ebd5Sriastradh 4053464ebd5Sriastradh 406