pbo.c revision 01e04c3f
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
3401e04c3fSmrg#include "errors.h"
353464ebd5Sriastradh#include "glheader.h"
363464ebd5Sriastradh#include "bufferobj.h"
37af69d88dSmrg#include "glformats.h"
383464ebd5Sriastradh#include "image.h"
393464ebd5Sriastradh#include "imports.h"
403464ebd5Sriastradh#include "mtypes.h"
413464ebd5Sriastradh#include "pbo.h"
423464ebd5Sriastradh
433464ebd5Sriastradh
443464ebd5Sriastradh
453464ebd5Sriastradh/**
463464ebd5Sriastradh * When we're about to read pixel data out of a PBO (via glDrawPixels,
473464ebd5Sriastradh * glTexImage, etc) or write data into a PBO (via glReadPixels,
483464ebd5Sriastradh * glGetTexImage, etc) we call this function to check that we're not
493464ebd5Sriastradh * going to read/write out of bounds.
503464ebd5Sriastradh *
513464ebd5Sriastradh * XXX This would also be a convenient time to check that the PBO isn't
523464ebd5Sriastradh * currently mapped.  Whoever calls this function should check for that.
533464ebd5Sriastradh * Remember, we can't use a PBO when it's mapped!
543464ebd5Sriastradh *
553464ebd5Sriastradh * If we're not using a PBO, this is a no-op.
563464ebd5Sriastradh *
573464ebd5Sriastradh * \param width  width of image to read/write
583464ebd5Sriastradh * \param height  height of image to read/write
593464ebd5Sriastradh * \param depth  depth of image to read/write
603464ebd5Sriastradh * \param format  format of image to read/write
613464ebd5Sriastradh * \param type  datatype of image to read/write
623464ebd5Sriastradh * \param clientMemSize  the maximum number of bytes to read/write
633464ebd5Sriastradh * \param ptr  the user-provided pointer/offset
643464ebd5Sriastradh * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
653464ebd5Sriastradh *         go out of bounds.
663464ebd5Sriastradh */
673464ebd5SriastradhGLboolean
683464ebd5Sriastradh_mesa_validate_pbo_access(GLuint dimensions,
693464ebd5Sriastradh                          const struct gl_pixelstore_attrib *pack,
703464ebd5Sriastradh                          GLsizei width, GLsizei height, GLsizei depth,
713464ebd5Sriastradh                          GLenum format, GLenum type, GLsizei clientMemSize,
723464ebd5Sriastradh                          const GLvoid *ptr)
733464ebd5Sriastradh{
74af69d88dSmrg   /* unsigned, to detect overflow/wrap-around */
75af69d88dSmrg   uintptr_t start, end, offset, size;
763464ebd5Sriastradh
773464ebd5Sriastradh   /* If no PBO is bound, 'ptr' is a pointer to client memory containing
783464ebd5Sriastradh      'clientMemSize' bytes.
793464ebd5Sriastradh      If a PBO is bound, 'ptr' is an offset into the bound PBO.
803464ebd5Sriastradh      In that case 'clientMemSize' is ignored: we just use the PBO's size.
813464ebd5Sriastradh    */
823464ebd5Sriastradh   if (!_mesa_is_bufferobj(pack->BufferObj)) {
833464ebd5Sriastradh      offset = 0;
8401e04c3fSmrg      size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize;
853464ebd5Sriastradh   } else {
86af69d88dSmrg      offset = (uintptr_t)ptr;
87af69d88dSmrg      size = pack->BufferObj->Size;
883464ebd5Sriastradh      /* The ARB_pixel_buffer_object spec says:
893464ebd5Sriastradh       *    "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
903464ebd5Sriastradh       *    ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
913464ebd5Sriastradh       *    TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
923464ebd5Sriastradh       *    TexSubImage2D, TexSubImage3D, and DrawPixels if the current
933464ebd5Sriastradh       *    PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
943464ebd5Sriastradh       *    parameter is not evenly divisible into the number of basic machine
953464ebd5Sriastradh       *    units needed to store in memory a datum indicated by the type
963464ebd5Sriastradh       *    parameter."
973464ebd5Sriastradh       */
983464ebd5Sriastradh      if (type != GL_BITMAP &&
99af69d88dSmrg          (offset % _mesa_sizeof_packed_type(type)))
1003464ebd5Sriastradh         return GL_FALSE;
1013464ebd5Sriastradh   }
1023464ebd5Sriastradh
103af69d88dSmrg   if (size == 0)
1043464ebd5Sriastradh      /* no buffer! */
1053464ebd5Sriastradh      return GL_FALSE;
1063464ebd5Sriastradh
10701e04c3fSmrg   /* If the size of the image is zero then no pixels are accessed so we
10801e04c3fSmrg    * don't need to check anything else.
10901e04c3fSmrg    */
11001e04c3fSmrg   if (width == 0 || height == 0 || depth == 0)
11101e04c3fSmrg      return GL_TRUE;
11201e04c3fSmrg
1133464ebd5Sriastradh   /* get the offset to the first pixel we'll read/write */
114af69d88dSmrg   start = _mesa_image_offset(dimensions, pack, width, height,
115af69d88dSmrg                              format, type, 0, 0, 0);
1163464ebd5Sriastradh
1173464ebd5Sriastradh   /* get the offset to just past the last pixel we'll read/write */
118af69d88dSmrg   end =  _mesa_image_offset(dimensions, pack, width, height,
119af69d88dSmrg                             format, type, depth-1, height-1, width);
1203464ebd5Sriastradh
121af69d88dSmrg   start += offset;
122af69d88dSmrg   end += offset;
123af69d88dSmrg
124af69d88dSmrg   if (start > size) {
1253464ebd5Sriastradh      /* This will catch negative values / wrap-around */
1263464ebd5Sriastradh      return GL_FALSE;
1273464ebd5Sriastradh   }
128af69d88dSmrg   if (end > size) {
1293464ebd5Sriastradh      /* Image read/write goes beyond end of buffer */
1303464ebd5Sriastradh      return GL_FALSE;
1313464ebd5Sriastradh   }
1323464ebd5Sriastradh
1333464ebd5Sriastradh   /* OK! */
1343464ebd5Sriastradh   return GL_TRUE;
1353464ebd5Sriastradh}
1363464ebd5Sriastradh
1373464ebd5Sriastradh
1383464ebd5Sriastradh/**
1393464ebd5Sriastradh * For commands that read from a PBO (glDrawPixels, glTexImage,
1403464ebd5Sriastradh * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
1413464ebd5Sriastradh * and return the pointer into the PBO.  If we're not reading from a
1423464ebd5Sriastradh * PBO, return \p src as-is.
1433464ebd5Sriastradh * If non-null return, must call _mesa_unmap_pbo_source() when done.
1443464ebd5Sriastradh *
1453464ebd5Sriastradh * \return NULL if error, else pointer to start of data
1463464ebd5Sriastradh */
1473464ebd5Sriastradhconst GLvoid *
1483464ebd5Sriastradh_mesa_map_pbo_source(struct gl_context *ctx,
1493464ebd5Sriastradh                     const struct gl_pixelstore_attrib *unpack,
1503464ebd5Sriastradh                     const GLvoid *src)
1513464ebd5Sriastradh{
1523464ebd5Sriastradh   const GLubyte *buf;
1533464ebd5Sriastradh
1543464ebd5Sriastradh   if (_mesa_is_bufferobj(unpack->BufferObj)) {
1553464ebd5Sriastradh      /* unpack from PBO */
156af69d88dSmrg      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
157af69d88dSmrg						   unpack->BufferObj->Size,
158af69d88dSmrg						   GL_MAP_READ_BIT,
159af69d88dSmrg						   unpack->BufferObj,
160af69d88dSmrg                                                   MAP_INTERNAL);
1613464ebd5Sriastradh      if (!buf)
1623464ebd5Sriastradh         return NULL;
1633464ebd5Sriastradh
1643464ebd5Sriastradh      buf = ADD_POINTERS(buf, src);
1653464ebd5Sriastradh   }
1663464ebd5Sriastradh   else {
1673464ebd5Sriastradh      /* unpack from normal memory */
1683464ebd5Sriastradh      buf = src;
1693464ebd5Sriastradh   }
1703464ebd5Sriastradh
1713464ebd5Sriastradh   return buf;
1723464ebd5Sriastradh}
1733464ebd5Sriastradh
1743464ebd5Sriastradh/**
17501e04c3fSmrg * Perform PBO validation for read operations with uncompressed textures.
17601e04c3fSmrg * If any GL errors are detected, false is returned, otherwise returns true.
1773464ebd5Sriastradh * \sa _mesa_validate_pbo_access
1783464ebd5Sriastradh */
17901e04c3fSmrgbool
18001e04c3fSmrg_mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions,
18101e04c3fSmrg                          const struct gl_pixelstore_attrib *unpack,
18201e04c3fSmrg                          GLsizei width, GLsizei height, GLsizei depth,
18301e04c3fSmrg                          GLenum format, GLenum type,
18401e04c3fSmrg                          GLsizei clientMemSize,
18501e04c3fSmrg                          const GLvoid *ptr, const char *where)
1863464ebd5Sriastradh{
18701e04c3fSmrg   assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
1883464ebd5Sriastradh
1893464ebd5Sriastradh   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
1903464ebd5Sriastradh                                  format, type, clientMemSize, ptr)) {
1913464ebd5Sriastradh      if (_mesa_is_bufferobj(unpack->BufferObj)) {
1923464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
19301e04c3fSmrg                     "%s(out of bounds PBO access)",
19401e04c3fSmrg                     where);
1953464ebd5Sriastradh      } else {
1963464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
1973464ebd5Sriastradh                     "%s(out of bounds access: bufSize (%d) is too small)",
1983464ebd5Sriastradh                     where, clientMemSize);
1993464ebd5Sriastradh      }
20001e04c3fSmrg      return false;
2013464ebd5Sriastradh   }
2023464ebd5Sriastradh
2033464ebd5Sriastradh   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
2043464ebd5Sriastradh      /* non-PBO access: no further validation to be done */
20501e04c3fSmrg      return true;
2063464ebd5Sriastradh   }
2073464ebd5Sriastradh
208af69d88dSmrg   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
2093464ebd5Sriastradh      /* buffer is already mapped - that's an error */
21001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
21101e04c3fSmrg                  where);
21201e04c3fSmrg      return false;
21301e04c3fSmrg   }
21401e04c3fSmrg
21501e04c3fSmrg   return true;
21601e04c3fSmrg}
21701e04c3fSmrg
21801e04c3fSmrg/**
21901e04c3fSmrg * Perform PBO validation for read operations with compressed textures.
22001e04c3fSmrg * If any GL errors are detected, false is returned, otherwise returns true.
22101e04c3fSmrg */
22201e04c3fSmrgbool
22301e04c3fSmrg_mesa_validate_pbo_source_compressed(struct gl_context *ctx, GLuint dimensions,
22401e04c3fSmrg                                     const struct gl_pixelstore_attrib *unpack,
22501e04c3fSmrg                                     GLsizei imageSize, const GLvoid *pixels,
22601e04c3fSmrg                                     const char *where)
22701e04c3fSmrg{
22801e04c3fSmrg   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
22901e04c3fSmrg      /* not using a PBO */
23001e04c3fSmrg      return true;
23101e04c3fSmrg   }
23201e04c3fSmrg
23301e04c3fSmrg   if ((const GLubyte *) pixels + imageSize >
23401e04c3fSmrg       ((const GLubyte *) 0) + unpack->BufferObj->Size) {
23501e04c3fSmrg      /* out of bounds read! */
23601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid PBO access)",
23701e04c3fSmrg                  where);
23801e04c3fSmrg      return false;
23901e04c3fSmrg   }
24001e04c3fSmrg
24101e04c3fSmrg   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
24201e04c3fSmrg      /* buffer is already mapped - that's an error */
24301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
24401e04c3fSmrg                  where);
24501e04c3fSmrg      return false;
24601e04c3fSmrg   }
24701e04c3fSmrg
24801e04c3fSmrg   return true;
24901e04c3fSmrg}
25001e04c3fSmrg
25101e04c3fSmrg/**
25201e04c3fSmrg * Perform PBO-read mapping.
25301e04c3fSmrg * If any GL errors are detected, they'll be recorded and NULL returned.
25401e04c3fSmrg * \sa _mesa_validate_pbo_source
25501e04c3fSmrg * \sa _mesa_map_pbo_source
25601e04c3fSmrg * A call to this function should have a matching call to
25701e04c3fSmrg * _mesa_unmap_pbo_source().
25801e04c3fSmrg */
25901e04c3fSmrgconst GLvoid *
26001e04c3fSmrg_mesa_map_validate_pbo_source(struct gl_context *ctx,
26101e04c3fSmrg                              GLuint dimensions,
26201e04c3fSmrg                              const struct gl_pixelstore_attrib *unpack,
26301e04c3fSmrg                              GLsizei width, GLsizei height, GLsizei depth,
26401e04c3fSmrg                              GLenum format, GLenum type,
26501e04c3fSmrg                              GLsizei clientMemSize,
26601e04c3fSmrg                              const GLvoid *ptr, const char *where)
26701e04c3fSmrg{
26801e04c3fSmrg   if (!_mesa_validate_pbo_source(ctx, dimensions, unpack,
26901e04c3fSmrg                                  width, height, depth, format, type,
27001e04c3fSmrg                                  clientMemSize, ptr, where)) {
27101e04c3fSmrg     return NULL;
2723464ebd5Sriastradh   }
2733464ebd5Sriastradh
2743464ebd5Sriastradh   ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
2753464ebd5Sriastradh   return ptr;
2763464ebd5Sriastradh}
2773464ebd5Sriastradh
2783464ebd5Sriastradh
2793464ebd5Sriastradh/**
2803464ebd5Sriastradh * Counterpart to _mesa_map_pbo_source()
2813464ebd5Sriastradh */
2823464ebd5Sriastradhvoid
2833464ebd5Sriastradh_mesa_unmap_pbo_source(struct gl_context *ctx,
2843464ebd5Sriastradh                       const struct gl_pixelstore_attrib *unpack)
2853464ebd5Sriastradh{
28601e04c3fSmrg   assert(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
2873464ebd5Sriastradh   if (_mesa_is_bufferobj(unpack->BufferObj)) {
288af69d88dSmrg      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
2893464ebd5Sriastradh   }
2903464ebd5Sriastradh}
2913464ebd5Sriastradh
2923464ebd5Sriastradh
2933464ebd5Sriastradh/**
2943464ebd5Sriastradh * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
2953464ebd5Sriastradh * if we're writing to a PBO, map it write-only and return the pointer
2963464ebd5Sriastradh * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
2973464ebd5Sriastradh * If non-null return, must call _mesa_unmap_pbo_dest() when done.
2983464ebd5Sriastradh *
2993464ebd5Sriastradh * \return NULL if error, else pointer to start of data
3003464ebd5Sriastradh */
3013464ebd5Sriastradhvoid *
3023464ebd5Sriastradh_mesa_map_pbo_dest(struct gl_context *ctx,
3033464ebd5Sriastradh                   const struct gl_pixelstore_attrib *pack,
3043464ebd5Sriastradh                   GLvoid *dest)
3053464ebd5Sriastradh{
3063464ebd5Sriastradh   void *buf;
3073464ebd5Sriastradh
3083464ebd5Sriastradh   if (_mesa_is_bufferobj(pack->BufferObj)) {
3093464ebd5Sriastradh      /* pack into PBO */
310af69d88dSmrg      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
311af69d88dSmrg						   pack->BufferObj->Size,
312af69d88dSmrg						   GL_MAP_WRITE_BIT,
313af69d88dSmrg						   pack->BufferObj,
314af69d88dSmrg                                                   MAP_INTERNAL);
3153464ebd5Sriastradh      if (!buf)
3163464ebd5Sriastradh         return NULL;
3173464ebd5Sriastradh
3183464ebd5Sriastradh      buf = ADD_POINTERS(buf, dest);
3193464ebd5Sriastradh   }
3203464ebd5Sriastradh   else {
3213464ebd5Sriastradh      /* pack to normal memory */
3223464ebd5Sriastradh      buf = dest;
3233464ebd5Sriastradh   }
3243464ebd5Sriastradh
3253464ebd5Sriastradh   return buf;
3263464ebd5Sriastradh}
3273464ebd5Sriastradh
3283464ebd5Sriastradh
3293464ebd5Sriastradh/**
3303464ebd5Sriastradh * Combine PBO-write validation and mapping.
3313464ebd5Sriastradh * If any GL errors are detected, they'll be recorded and NULL returned.
3323464ebd5Sriastradh * \sa _mesa_validate_pbo_access
3333464ebd5Sriastradh * \sa _mesa_map_pbo_dest
3343464ebd5Sriastradh * A call to this function should have a matching call to
3353464ebd5Sriastradh * _mesa_unmap_pbo_dest().
3363464ebd5Sriastradh */
3373464ebd5SriastradhGLvoid *
3383464ebd5Sriastradh_mesa_map_validate_pbo_dest(struct gl_context *ctx,
339af69d88dSmrg                            GLuint dimensions,
340af69d88dSmrg                            const struct gl_pixelstore_attrib *unpack,
341af69d88dSmrg                            GLsizei width, GLsizei height, GLsizei depth,
342af69d88dSmrg                            GLenum format, GLenum type, GLsizei clientMemSize,
343af69d88dSmrg                            GLvoid *ptr, const char *where)
3443464ebd5Sriastradh{
34501e04c3fSmrg   assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
3463464ebd5Sriastradh
3473464ebd5Sriastradh   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
3483464ebd5Sriastradh                                  format, type, clientMemSize, ptr)) {
3493464ebd5Sriastradh      if (_mesa_is_bufferobj(unpack->BufferObj)) {
3503464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
3513464ebd5Sriastradh                     "%s(out of bounds PBO access)", where);
3523464ebd5Sriastradh      } else {
3533464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
3543464ebd5Sriastradh                     "%s(out of bounds access: bufSize (%d) is too small)",
3553464ebd5Sriastradh                     where, clientMemSize);
3563464ebd5Sriastradh      }
3573464ebd5Sriastradh      return NULL;
3583464ebd5Sriastradh   }
3593464ebd5Sriastradh
3603464ebd5Sriastradh   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
3613464ebd5Sriastradh      /* non-PBO access: no further validation to be done */
3623464ebd5Sriastradh      return ptr;
3633464ebd5Sriastradh   }
3643464ebd5Sriastradh
365af69d88dSmrg   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
3663464ebd5Sriastradh      /* buffer is already mapped - that's an error */
3673464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
3683464ebd5Sriastradh      return NULL;
3693464ebd5Sriastradh   }
3703464ebd5Sriastradh
3713464ebd5Sriastradh   ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
3723464ebd5Sriastradh   return ptr;
3733464ebd5Sriastradh}
3743464ebd5Sriastradh
3753464ebd5Sriastradh
3763464ebd5Sriastradh/**
3773464ebd5Sriastradh * Counterpart to _mesa_map_pbo_dest()
3783464ebd5Sriastradh */
3793464ebd5Sriastradhvoid
3803464ebd5Sriastradh_mesa_unmap_pbo_dest(struct gl_context *ctx,
3813464ebd5Sriastradh                     const struct gl_pixelstore_attrib *pack)
3823464ebd5Sriastradh{
38301e04c3fSmrg   assert(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
3843464ebd5Sriastradh   if (_mesa_is_bufferobj(pack->BufferObj)) {
385af69d88dSmrg      ctx->Driver.UnmapBuffer(ctx, pack->BufferObj, MAP_INTERNAL);
3863464ebd5Sriastradh   }
3873464ebd5Sriastradh}
3883464ebd5Sriastradh
3893464ebd5Sriastradh
3903464ebd5Sriastradh/**
3913464ebd5Sriastradh * Check if an unpack PBO is active prior to fetching a texture image.
3923464ebd5Sriastradh * If so, do bounds checking and map the buffer into main memory.
3933464ebd5Sriastradh * Any errors detected will be recorded.
3943464ebd5Sriastradh * The caller _must_ call _mesa_unmap_teximage_pbo() too!
3953464ebd5Sriastradh */
3963464ebd5Sriastradhconst GLvoid *
3973464ebd5Sriastradh_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
3983464ebd5Sriastradh			    GLsizei width, GLsizei height, GLsizei depth,
3993464ebd5Sriastradh			    GLenum format, GLenum type, const GLvoid *pixels,
4003464ebd5Sriastradh			    const struct gl_pixelstore_attrib *unpack,
4013464ebd5Sriastradh			    const char *funcName)
4023464ebd5Sriastradh{
4033464ebd5Sriastradh   GLubyte *buf;
4043464ebd5Sriastradh
4053464ebd5Sriastradh   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
4063464ebd5Sriastradh      /* no PBO */
4073464ebd5Sriastradh      return pixels;
4083464ebd5Sriastradh   }
4093464ebd5Sriastradh   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
410af69d88dSmrg                                  format, type, INT_MAX, pixels)) {
411af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
412af69d88dSmrg                  funcName, dimensions);
4133464ebd5Sriastradh      return NULL;
4143464ebd5Sriastradh   }
4153464ebd5Sriastradh
416af69d88dSmrg   buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
417af69d88dSmrg                                                unpack->BufferObj->Size,
418af69d88dSmrg						GL_MAP_READ_BIT,
419af69d88dSmrg						unpack->BufferObj,
420af69d88dSmrg                                                MAP_INTERNAL);
4213464ebd5Sriastradh   if (!buf) {
422af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
423af69d88dSmrg                  dimensions);
4243464ebd5Sriastradh      return NULL;
4253464ebd5Sriastradh   }
4263464ebd5Sriastradh
4273464ebd5Sriastradh   return ADD_POINTERS(buf, pixels);
4283464ebd5Sriastradh}
4293464ebd5Sriastradh
4303464ebd5Sriastradh
4313464ebd5Sriastradh/**
4323464ebd5Sriastradh * Check if an unpack PBO is active prior to fetching a compressed texture
4333464ebd5Sriastradh * image.
4343464ebd5Sriastradh * If so, do bounds checking and map the buffer into main memory.
4353464ebd5Sriastradh * Any errors detected will be recorded.
4363464ebd5Sriastradh * The caller _must_ call _mesa_unmap_teximage_pbo() too!
4373464ebd5Sriastradh */
4383464ebd5Sriastradhconst GLvoid *
4393464ebd5Sriastradh_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
440af69d88dSmrg                                 GLuint dimensions, GLsizei imageSize,
441af69d88dSmrg                                 const GLvoid *pixels,
4423464ebd5Sriastradh                                 const struct gl_pixelstore_attrib *packing,
4433464ebd5Sriastradh                                 const char *funcName)
4443464ebd5Sriastradh{
4453464ebd5Sriastradh   GLubyte *buf;
4463464ebd5Sriastradh
44701e04c3fSmrg   if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, packing,
44801e04c3fSmrg                                             imageSize, pixels, funcName)) {
44901e04c3fSmrg     /* error is already set during validation */
45001e04c3fSmrg      return NULL;
45101e04c3fSmrg   }
45201e04c3fSmrg
4533464ebd5Sriastradh   if (!_mesa_is_bufferobj(packing->BufferObj)) {
4543464ebd5Sriastradh      /* not using a PBO - return pointer unchanged */
4553464ebd5Sriastradh      return pixels;
4563464ebd5Sriastradh   }
4573464ebd5Sriastradh
458af69d88dSmrg   buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0,
459af69d88dSmrg					       packing->BufferObj->Size,
460af69d88dSmrg					       GL_MAP_READ_BIT,
461af69d88dSmrg					       packing->BufferObj,
462af69d88dSmrg                                               MAP_INTERNAL);
46301e04c3fSmrg
46401e04c3fSmrg   /* Validation above already checked that PBO is not mapped, so buffer
46501e04c3fSmrg    * should not be null.
46601e04c3fSmrg    */
46701e04c3fSmrg   assert(buf);
4683464ebd5Sriastradh
4693464ebd5Sriastradh   return ADD_POINTERS(buf, pixels);
4703464ebd5Sriastradh}
4713464ebd5Sriastradh
4723464ebd5Sriastradh
4733464ebd5Sriastradh/**
4743464ebd5Sriastradh * This function must be called after either of the validate_pbo_*_teximage()
4753464ebd5Sriastradh * functions.  It unmaps the PBO buffer if it was mapped earlier.
4763464ebd5Sriastradh */
4773464ebd5Sriastradhvoid
4783464ebd5Sriastradh_mesa_unmap_teximage_pbo(struct gl_context *ctx,
4793464ebd5Sriastradh                         const struct gl_pixelstore_attrib *unpack)
4803464ebd5Sriastradh{
4813464ebd5Sriastradh   if (_mesa_is_bufferobj(unpack->BufferObj)) {
482af69d88dSmrg      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
4833464ebd5Sriastradh   }
4843464ebd5Sriastradh}
485