pbo.c revision af69d88d
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
20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
243464ebd5Sriastradh */
253464ebd5Sriastradh
263464ebd5Sriastradh
273464ebd5Sriastradh/**
283464ebd5Sriastradh * \file pbo.c
293464ebd5Sriastradh * \brief Functions related to Pixel Buffer Objects.
303464ebd5Sriastradh */
313464ebd5Sriastradh
323464ebd5Sriastradh
333464ebd5Sriastradh
343464ebd5Sriastradh#include "glheader.h"
353464ebd5Sriastradh#include "bufferobj.h"
36af69d88dSmrg#include "glformats.h"
373464ebd5Sriastradh#include "image.h"
383464ebd5Sriastradh#include "imports.h"
393464ebd5Sriastradh#include "mtypes.h"
403464ebd5Sriastradh#include "pbo.h"
413464ebd5Sriastradh
423464ebd5Sriastradh
433464ebd5Sriastradh
443464ebd5Sriastradh/**
453464ebd5Sriastradh * When we're about to read pixel data out of a PBO (via glDrawPixels,
463464ebd5Sriastradh * glTexImage, etc) or write data into a PBO (via glReadPixels,
473464ebd5Sriastradh * glGetTexImage, etc) we call this function to check that we're not
483464ebd5Sriastradh * going to read/write out of bounds.
493464ebd5Sriastradh *
503464ebd5Sriastradh * XXX This would also be a convenient time to check that the PBO isn't
513464ebd5Sriastradh * currently mapped.  Whoever calls this function should check for that.
523464ebd5Sriastradh * Remember, we can't use a PBO when it's mapped!
533464ebd5Sriastradh *
543464ebd5Sriastradh * If we're not using a PBO, this is a no-op.
553464ebd5Sriastradh *
563464ebd5Sriastradh * \param width  width of image to read/write
573464ebd5Sriastradh * \param height  height of image to read/write
583464ebd5Sriastradh * \param depth  depth of image to read/write
593464ebd5Sriastradh * \param format  format of image to read/write
603464ebd5Sriastradh * \param type  datatype of image to read/write
613464ebd5Sriastradh * \param clientMemSize  the maximum number of bytes to read/write
623464ebd5Sriastradh * \param ptr  the user-provided pointer/offset
633464ebd5Sriastradh * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
643464ebd5Sriastradh *         go out of bounds.
653464ebd5Sriastradh */
663464ebd5SriastradhGLboolean
673464ebd5Sriastradh_mesa_validate_pbo_access(GLuint dimensions,
683464ebd5Sriastradh                          const struct gl_pixelstore_attrib *pack,
693464ebd5Sriastradh                          GLsizei width, GLsizei height, GLsizei depth,
703464ebd5Sriastradh                          GLenum format, GLenum type, GLsizei clientMemSize,
713464ebd5Sriastradh                          const GLvoid *ptr)
723464ebd5Sriastradh{
73af69d88dSmrg   /* unsigned, to detect overflow/wrap-around */
74af69d88dSmrg   uintptr_t start, end, offset, size;
753464ebd5Sriastradh
763464ebd5Sriastradh   /* If no PBO is bound, 'ptr' is a pointer to client memory containing
773464ebd5Sriastradh      'clientMemSize' bytes.
783464ebd5Sriastradh      If a PBO is bound, 'ptr' is an offset into the bound PBO.
793464ebd5Sriastradh      In that case 'clientMemSize' is ignored: we just use the PBO's size.
803464ebd5Sriastradh    */
813464ebd5Sriastradh   if (!_mesa_is_bufferobj(pack->BufferObj)) {
823464ebd5Sriastradh      offset = 0;
83af69d88dSmrg      size = clientMemSize;
843464ebd5Sriastradh   } else {
85af69d88dSmrg      offset = (uintptr_t)ptr;
86af69d88dSmrg      size = pack->BufferObj->Size;
873464ebd5Sriastradh      /* The ARB_pixel_buffer_object spec says:
883464ebd5Sriastradh       *    "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
893464ebd5Sriastradh       *    ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
903464ebd5Sriastradh       *    TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
913464ebd5Sriastradh       *    TexSubImage2D, TexSubImage3D, and DrawPixels if the current
923464ebd5Sriastradh       *    PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
933464ebd5Sriastradh       *    parameter is not evenly divisible into the number of basic machine
943464ebd5Sriastradh       *    units needed to store in memory a datum indicated by the type
953464ebd5Sriastradh       *    parameter."
963464ebd5Sriastradh       */
973464ebd5Sriastradh      if (type != GL_BITMAP &&
98af69d88dSmrg          (offset % _mesa_sizeof_packed_type(type)))
993464ebd5Sriastradh         return GL_FALSE;
1003464ebd5Sriastradh   }
1013464ebd5Sriastradh
102af69d88dSmrg   if (size == 0)
1033464ebd5Sriastradh      /* no buffer! */
1043464ebd5Sriastradh      return GL_FALSE;
1053464ebd5Sriastradh
1063464ebd5Sriastradh   /* get the offset to the first pixel we'll read/write */
107af69d88dSmrg   start = _mesa_image_offset(dimensions, pack, width, height,
108af69d88dSmrg                              format, type, 0, 0, 0);
1093464ebd5Sriastradh
1103464ebd5Sriastradh   /* get the offset to just past the last pixel we'll read/write */
111af69d88dSmrg   end =  _mesa_image_offset(dimensions, pack, width, height,
112af69d88dSmrg                             format, type, depth-1, height-1, width);
1133464ebd5Sriastradh
114af69d88dSmrg   start += offset;
115af69d88dSmrg   end += offset;
116af69d88dSmrg
117af69d88dSmrg   if (start > size) {
1183464ebd5Sriastradh      /* This will catch negative values / wrap-around */
1193464ebd5Sriastradh      return GL_FALSE;
1203464ebd5Sriastradh   }
121af69d88dSmrg   if (end > size) {
1223464ebd5Sriastradh      /* Image read/write goes beyond end of buffer */
1233464ebd5Sriastradh      return GL_FALSE;
1243464ebd5Sriastradh   }
1253464ebd5Sriastradh
1263464ebd5Sriastradh   /* OK! */
1273464ebd5Sriastradh   return GL_TRUE;
1283464ebd5Sriastradh}
1293464ebd5Sriastradh
1303464ebd5Sriastradh
1313464ebd5Sriastradh/**
1323464ebd5Sriastradh * For commands that read from a PBO (glDrawPixels, glTexImage,
1333464ebd5Sriastradh * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
1343464ebd5Sriastradh * and return the pointer into the PBO.  If we're not reading from a
1353464ebd5Sriastradh * PBO, return \p src as-is.
1363464ebd5Sriastradh * If non-null return, must call _mesa_unmap_pbo_source() when done.
1373464ebd5Sriastradh *
1383464ebd5Sriastradh * \return NULL if error, else pointer to start of data
1393464ebd5Sriastradh */
1403464ebd5Sriastradhconst GLvoid *
1413464ebd5Sriastradh_mesa_map_pbo_source(struct gl_context *ctx,
1423464ebd5Sriastradh                     const struct gl_pixelstore_attrib *unpack,
1433464ebd5Sriastradh                     const GLvoid *src)
1443464ebd5Sriastradh{
1453464ebd5Sriastradh   const GLubyte *buf;
1463464ebd5Sriastradh
1473464ebd5Sriastradh   if (_mesa_is_bufferobj(unpack->BufferObj)) {
1483464ebd5Sriastradh      /* unpack from PBO */
149af69d88dSmrg      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
150af69d88dSmrg						   unpack->BufferObj->Size,
151af69d88dSmrg						   GL_MAP_READ_BIT,
152af69d88dSmrg						   unpack->BufferObj,
153af69d88dSmrg                                                   MAP_INTERNAL);
1543464ebd5Sriastradh      if (!buf)
1553464ebd5Sriastradh         return NULL;
1563464ebd5Sriastradh
1573464ebd5Sriastradh      buf = ADD_POINTERS(buf, src);
1583464ebd5Sriastradh   }
1593464ebd5Sriastradh   else {
1603464ebd5Sriastradh      /* unpack from normal memory */
1613464ebd5Sriastradh      buf = src;
1623464ebd5Sriastradh   }
1633464ebd5Sriastradh
1643464ebd5Sriastradh   return buf;
1653464ebd5Sriastradh}
1663464ebd5Sriastradh
1673464ebd5Sriastradh
1683464ebd5Sriastradh/**
1693464ebd5Sriastradh * Combine PBO-read validation and mapping.
1703464ebd5Sriastradh * If any GL errors are detected, they'll be recorded and NULL returned.
1713464ebd5Sriastradh * \sa _mesa_validate_pbo_access
1723464ebd5Sriastradh * \sa _mesa_map_pbo_source
1733464ebd5Sriastradh * A call to this function should have a matching call to
1743464ebd5Sriastradh * _mesa_unmap_pbo_source().
1753464ebd5Sriastradh */
1763464ebd5Sriastradhconst GLvoid *
1773464ebd5Sriastradh_mesa_map_validate_pbo_source(struct gl_context *ctx,
178af69d88dSmrg                              GLuint dimensions,
179af69d88dSmrg                              const struct gl_pixelstore_attrib *unpack,
180af69d88dSmrg                              GLsizei width, GLsizei height, GLsizei depth,
181af69d88dSmrg                              GLenum format, GLenum type,
182af69d88dSmrg                              GLsizei clientMemSize,
183af69d88dSmrg                              const GLvoid *ptr, const char *where)
1843464ebd5Sriastradh{
1853464ebd5Sriastradh   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
1863464ebd5Sriastradh
1873464ebd5Sriastradh   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
1883464ebd5Sriastradh                                  format, type, clientMemSize, ptr)) {
1893464ebd5Sriastradh      if (_mesa_is_bufferobj(unpack->BufferObj)) {
1903464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
1913464ebd5Sriastradh                     "%s(out of bounds PBO access)", where);
1923464ebd5Sriastradh      } else {
1933464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
1943464ebd5Sriastradh                     "%s(out of bounds access: bufSize (%d) is too small)",
1953464ebd5Sriastradh                     where, clientMemSize);
1963464ebd5Sriastradh      }
1973464ebd5Sriastradh      return NULL;
1983464ebd5Sriastradh   }
1993464ebd5Sriastradh
2003464ebd5Sriastradh   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
2013464ebd5Sriastradh      /* non-PBO access: no further validation to be done */
2023464ebd5Sriastradh      return ptr;
2033464ebd5Sriastradh   }
2043464ebd5Sriastradh
205af69d88dSmrg   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
2063464ebd5Sriastradh      /* buffer is already mapped - that's an error */
2073464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
2083464ebd5Sriastradh      return NULL;
2093464ebd5Sriastradh   }
2103464ebd5Sriastradh
2113464ebd5Sriastradh   ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
2123464ebd5Sriastradh   return ptr;
2133464ebd5Sriastradh}
2143464ebd5Sriastradh
2153464ebd5Sriastradh
2163464ebd5Sriastradh/**
2173464ebd5Sriastradh * Counterpart to _mesa_map_pbo_source()
2183464ebd5Sriastradh */
2193464ebd5Sriastradhvoid
2203464ebd5Sriastradh_mesa_unmap_pbo_source(struct gl_context *ctx,
2213464ebd5Sriastradh                       const struct gl_pixelstore_attrib *unpack)
2223464ebd5Sriastradh{
2233464ebd5Sriastradh   ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
2243464ebd5Sriastradh   if (_mesa_is_bufferobj(unpack->BufferObj)) {
225af69d88dSmrg      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
2263464ebd5Sriastradh   }
2273464ebd5Sriastradh}
2283464ebd5Sriastradh
2293464ebd5Sriastradh
2303464ebd5Sriastradh/**
2313464ebd5Sriastradh * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
2323464ebd5Sriastradh * if we're writing to a PBO, map it write-only and return the pointer
2333464ebd5Sriastradh * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
2343464ebd5Sriastradh * If non-null return, must call _mesa_unmap_pbo_dest() when done.
2353464ebd5Sriastradh *
2363464ebd5Sriastradh * \return NULL if error, else pointer to start of data
2373464ebd5Sriastradh */
2383464ebd5Sriastradhvoid *
2393464ebd5Sriastradh_mesa_map_pbo_dest(struct gl_context *ctx,
2403464ebd5Sriastradh                   const struct gl_pixelstore_attrib *pack,
2413464ebd5Sriastradh                   GLvoid *dest)
2423464ebd5Sriastradh{
2433464ebd5Sriastradh   void *buf;
2443464ebd5Sriastradh
2453464ebd5Sriastradh   if (_mesa_is_bufferobj(pack->BufferObj)) {
2463464ebd5Sriastradh      /* pack into PBO */
247af69d88dSmrg      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
248af69d88dSmrg						   pack->BufferObj->Size,
249af69d88dSmrg						   GL_MAP_WRITE_BIT,
250af69d88dSmrg						   pack->BufferObj,
251af69d88dSmrg                                                   MAP_INTERNAL);
2523464ebd5Sriastradh      if (!buf)
2533464ebd5Sriastradh         return NULL;
2543464ebd5Sriastradh
2553464ebd5Sriastradh      buf = ADD_POINTERS(buf, dest);
2563464ebd5Sriastradh   }
2573464ebd5Sriastradh   else {
2583464ebd5Sriastradh      /* pack to normal memory */
2593464ebd5Sriastradh      buf = dest;
2603464ebd5Sriastradh   }
2613464ebd5Sriastradh
2623464ebd5Sriastradh   return buf;
2633464ebd5Sriastradh}
2643464ebd5Sriastradh
2653464ebd5Sriastradh
2663464ebd5Sriastradh/**
2673464ebd5Sriastradh * Combine PBO-write validation and mapping.
2683464ebd5Sriastradh * If any GL errors are detected, they'll be recorded and NULL returned.
2693464ebd5Sriastradh * \sa _mesa_validate_pbo_access
2703464ebd5Sriastradh * \sa _mesa_map_pbo_dest
2713464ebd5Sriastradh * A call to this function should have a matching call to
2723464ebd5Sriastradh * _mesa_unmap_pbo_dest().
2733464ebd5Sriastradh */
2743464ebd5SriastradhGLvoid *
2753464ebd5Sriastradh_mesa_map_validate_pbo_dest(struct gl_context *ctx,
276af69d88dSmrg                            GLuint dimensions,
277af69d88dSmrg                            const struct gl_pixelstore_attrib *unpack,
278af69d88dSmrg                            GLsizei width, GLsizei height, GLsizei depth,
279af69d88dSmrg                            GLenum format, GLenum type, GLsizei clientMemSize,
280af69d88dSmrg                            GLvoid *ptr, const char *where)
2813464ebd5Sriastradh{
2823464ebd5Sriastradh   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
2833464ebd5Sriastradh
2843464ebd5Sriastradh   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
2853464ebd5Sriastradh                                  format, type, clientMemSize, ptr)) {
2863464ebd5Sriastradh      if (_mesa_is_bufferobj(unpack->BufferObj)) {
2873464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
2883464ebd5Sriastradh                     "%s(out of bounds PBO access)", where);
2893464ebd5Sriastradh      } else {
2903464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
2913464ebd5Sriastradh                     "%s(out of bounds access: bufSize (%d) is too small)",
2923464ebd5Sriastradh                     where, clientMemSize);
2933464ebd5Sriastradh      }
2943464ebd5Sriastradh      return NULL;
2953464ebd5Sriastradh   }
2963464ebd5Sriastradh
2973464ebd5Sriastradh   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
2983464ebd5Sriastradh      /* non-PBO access: no further validation to be done */
2993464ebd5Sriastradh      return ptr;
3003464ebd5Sriastradh   }
3013464ebd5Sriastradh
302af69d88dSmrg   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
3033464ebd5Sriastradh      /* buffer is already mapped - that's an error */
3043464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
3053464ebd5Sriastradh      return NULL;
3063464ebd5Sriastradh   }
3073464ebd5Sriastradh
3083464ebd5Sriastradh   ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
3093464ebd5Sriastradh   return ptr;
3103464ebd5Sriastradh}
3113464ebd5Sriastradh
3123464ebd5Sriastradh
3133464ebd5Sriastradh/**
3143464ebd5Sriastradh * Counterpart to _mesa_map_pbo_dest()
3153464ebd5Sriastradh */
3163464ebd5Sriastradhvoid
3173464ebd5Sriastradh_mesa_unmap_pbo_dest(struct gl_context *ctx,
3183464ebd5Sriastradh                     const struct gl_pixelstore_attrib *pack)
3193464ebd5Sriastradh{
3203464ebd5Sriastradh   ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
3213464ebd5Sriastradh   if (_mesa_is_bufferobj(pack->BufferObj)) {
322af69d88dSmrg      ctx->Driver.UnmapBuffer(ctx, pack->BufferObj, MAP_INTERNAL);
3233464ebd5Sriastradh   }
3243464ebd5Sriastradh}
3253464ebd5Sriastradh
3263464ebd5Sriastradh
3273464ebd5Sriastradh/**
3283464ebd5Sriastradh * Check if an unpack PBO is active prior to fetching a texture image.
3293464ebd5Sriastradh * If so, do bounds checking and map the buffer into main memory.
3303464ebd5Sriastradh * Any errors detected will be recorded.
3313464ebd5Sriastradh * The caller _must_ call _mesa_unmap_teximage_pbo() too!
3323464ebd5Sriastradh */
3333464ebd5Sriastradhconst GLvoid *
3343464ebd5Sriastradh_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
3353464ebd5Sriastradh			    GLsizei width, GLsizei height, GLsizei depth,
3363464ebd5Sriastradh			    GLenum format, GLenum type, const GLvoid *pixels,
3373464ebd5Sriastradh			    const struct gl_pixelstore_attrib *unpack,
3383464ebd5Sriastradh			    const char *funcName)
3393464ebd5Sriastradh{
3403464ebd5Sriastradh   GLubyte *buf;
3413464ebd5Sriastradh
3423464ebd5Sriastradh   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
3433464ebd5Sriastradh      /* no PBO */
3443464ebd5Sriastradh      return pixels;
3453464ebd5Sriastradh   }
3463464ebd5Sriastradh   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
347af69d88dSmrg                                  format, type, INT_MAX, pixels)) {
348af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
349af69d88dSmrg                  funcName, dimensions);
3503464ebd5Sriastradh      return NULL;
3513464ebd5Sriastradh   }
3523464ebd5Sriastradh
353af69d88dSmrg   buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
354af69d88dSmrg                                                unpack->BufferObj->Size,
355af69d88dSmrg						GL_MAP_READ_BIT,
356af69d88dSmrg						unpack->BufferObj,
357af69d88dSmrg                                                MAP_INTERNAL);
3583464ebd5Sriastradh   if (!buf) {
359af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
360af69d88dSmrg                  dimensions);
3613464ebd5Sriastradh      return NULL;
3623464ebd5Sriastradh   }
3633464ebd5Sriastradh
3643464ebd5Sriastradh   return ADD_POINTERS(buf, pixels);
3653464ebd5Sriastradh}
3663464ebd5Sriastradh
3673464ebd5Sriastradh
3683464ebd5Sriastradh/**
3693464ebd5Sriastradh * Check if an unpack PBO is active prior to fetching a compressed texture
3703464ebd5Sriastradh * image.
3713464ebd5Sriastradh * If so, do bounds checking and map the buffer into main memory.
3723464ebd5Sriastradh * Any errors detected will be recorded.
3733464ebd5Sriastradh * The caller _must_ call _mesa_unmap_teximage_pbo() too!
3743464ebd5Sriastradh */
3753464ebd5Sriastradhconst GLvoid *
3763464ebd5Sriastradh_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
377af69d88dSmrg                                 GLuint dimensions, GLsizei imageSize,
378af69d88dSmrg                                 const GLvoid *pixels,
3793464ebd5Sriastradh                                 const struct gl_pixelstore_attrib *packing,
3803464ebd5Sriastradh                                 const char *funcName)
3813464ebd5Sriastradh{
3823464ebd5Sriastradh   GLubyte *buf;
3833464ebd5Sriastradh
3843464ebd5Sriastradh   if (!_mesa_is_bufferobj(packing->BufferObj)) {
3853464ebd5Sriastradh      /* not using a PBO - return pointer unchanged */
3863464ebd5Sriastradh      return pixels;
3873464ebd5Sriastradh   }
3883464ebd5Sriastradh   if ((const GLubyte *) pixels + imageSize >
3893464ebd5Sriastradh       ((const GLubyte *) 0) + packing->BufferObj->Size) {
3903464ebd5Sriastradh      /* out of bounds read! */
391af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
392af69d88dSmrg                  funcName, dimensions);
3933464ebd5Sriastradh      return NULL;
3943464ebd5Sriastradh   }
3953464ebd5Sriastradh
396af69d88dSmrg   buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0,
397af69d88dSmrg					       packing->BufferObj->Size,
398af69d88dSmrg					       GL_MAP_READ_BIT,
399af69d88dSmrg					       packing->BufferObj,
400af69d88dSmrg                                               MAP_INTERNAL);
4013464ebd5Sriastradh   if (!buf) {
402af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
403af69d88dSmrg                  dimensions);
4043464ebd5Sriastradh      return NULL;
4053464ebd5Sriastradh   }
4063464ebd5Sriastradh
4073464ebd5Sriastradh   return ADD_POINTERS(buf, pixels);
4083464ebd5Sriastradh}
4093464ebd5Sriastradh
4103464ebd5Sriastradh
4113464ebd5Sriastradh/**
4123464ebd5Sriastradh * This function must be called after either of the validate_pbo_*_teximage()
4133464ebd5Sriastradh * functions.  It unmaps the PBO buffer if it was mapped earlier.
4143464ebd5Sriastradh */
4153464ebd5Sriastradhvoid
4163464ebd5Sriastradh_mesa_unmap_teximage_pbo(struct gl_context *ctx,
4173464ebd5Sriastradh                         const struct gl_pixelstore_attrib *unpack)
4183464ebd5Sriastradh{
4193464ebd5Sriastradh   if (_mesa_is_bufferobj(unpack->BufferObj)) {
420af69d88dSmrg      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
4213464ebd5Sriastradh   }
4223464ebd5Sriastradh}
423