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