Move compiler.h and imports.h/c from src/mesa/main into src/util
[mesa.git] / src / mesa / main / pbo.c
index dc00d423ba9079dde568cc4328d46363d79f9468..6af815759f1c9e516ce70d271b4f5fc8700aa37f 100644 (file)
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
  */
 
 
 
 
 
+#include "errors.h"
 #include "glheader.h"
 #include "bufferobj.h"
+#include "glformats.h"
 #include "image.h"
-#include "imports.h"
+#include "util/imports.h"
 #include "mtypes.h"
 #include "pbo.h"
 
@@ -43,7 +46,7 @@
  * When we're about to read pixel data out of a PBO (via glDrawPixels,
  * glTexImage, etc) or write data into a PBO (via glReadPixels,
  * glGetTexImage, etc) we call this function to check that we're not
- * going to read out of bounds.
+ * going to read/write out of bounds.
  *
  * XXX This would also be a convenient time to check that the PBO isn't
  * currently mapped.  Whoever calls this function should check for that.
  * \param depth  depth of image to read/write
  * \param format  format of image to read/write
  * \param type  datatype of image to read/write
+ * \param clientMemSize  the maximum number of bytes to read/write
  * \param ptr  the user-provided pointer/offset
- * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
+ * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
  *         go out of bounds.
  */
 GLboolean
 _mesa_validate_pbo_access(GLuint dimensions,
                           const struct gl_pixelstore_attrib *pack,
                           GLsizei width, GLsizei height, GLsizei depth,
-                          GLenum format, GLenum type, const GLvoid *ptr)
+                          GLenum format, GLenum type, GLsizei clientMemSize,
+                          const GLvoid *ptr)
 {
-   GLvoid *start, *end;
-   const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
-
-   if (!_mesa_is_bufferobj(pack->BufferObj))
-      return GL_TRUE;  /* no PBO, OK */
+   /* unsigned, to detect overflow/wrap-around */
+   uintptr_t start, end, offset, size;
+
+   /* If no PBO is bound, 'ptr' is a pointer to client memory containing
+      'clientMemSize' bytes.
+      If a PBO is bound, 'ptr' is an offset into the bound PBO.
+      In that case 'clientMemSize' is ignored: we just use the PBO's size.
+    */
+   if (!_mesa_is_bufferobj(pack->BufferObj)) {
+      offset = 0;
+      size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize;
+   } else {
+      offset = (uintptr_t)ptr;
+      size = pack->BufferObj->Size;
+      /* The ARB_pixel_buffer_object spec says:
+       *    "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
+       *    ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
+       *    TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
+       *    TexSubImage2D, TexSubImage3D, and DrawPixels if the current
+       *    PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
+       *    parameter is not evenly divisible into the number of basic machine
+       *    units needed to store in memory a datum indicated by the type
+       *    parameter."
+       */
+      if (type != GL_BITMAP &&
+          (offset % _mesa_sizeof_packed_type(type)))
+         return GL_FALSE;
+   }
 
-   if (pack->BufferObj->Size == 0)
+   if (size == 0)
       /* no buffer! */
       return GL_FALSE;
 
-   /* get address of first pixel we'll read */
-   start = _mesa_image_address(dimensions, pack, ptr, width, height,
-                               format, type, 0, 0, 0);
+   /* If the size of the image is zero then no pixels are accessed so we
+    * don't need to check anything else.
+    */
+   if (width == 0 || height == 0 || depth == 0)
+      return GL_TRUE;
 
-   /* get address just past the last pixel we'll read */
-   end =  _mesa_image_address(dimensions, pack, ptr, width, height,
-                              format, type, depth-1, height-1, width);
+   /* get the offset to the first pixel we'll read/write */
+   start = _mesa_image_offset(dimensions, pack, width, height,
+                              format, type, 0, 0, 0);
 
+   /* get the offset to just past the last pixel we'll read/write */
+   end =  _mesa_image_offset(dimensions, pack, width, height,
+                             format, type, depth-1, height-1, width);
 
-   sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
+   start += offset;
+   end += offset;
 
-   if ((const GLubyte *) start > sizeAddr) {
+   if (start > size) {
       /* This will catch negative values / wrap-around */
       return GL_FALSE;
    }
-   if ((const GLubyte *) end > sizeAddr) {
-      /* Image read goes beyond end of buffer */
+   if (end > size) {
+      /* Image read/write goes beyond end of buffer */
       return GL_FALSE;
    }
 
@@ -119,9 +153,11 @@ _mesa_map_pbo_source(struct gl_context *ctx,
 
    if (_mesa_is_bufferobj(unpack->BufferObj)) {
       /* unpack from PBO */
-      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
-                                              GL_READ_ONLY_ARB,
-                                              unpack->BufferObj);
+      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
+                                                  unpack->BufferObj->Size,
+                                                  GL_MAP_READ_BIT,
+                                                  unpack->BufferObj,
+                                                   MAP_INTERNAL);
       if (!buf)
          return NULL;
 
@@ -135,11 +171,87 @@ _mesa_map_pbo_source(struct gl_context *ctx,
    return buf;
 }
 
+/**
+ * Perform PBO validation for read operations with uncompressed textures.
+ * If any GL errors are detected, false is returned, otherwise returns true.
+ * \sa _mesa_validate_pbo_access
+ */
+bool
+_mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions,
+                          const struct gl_pixelstore_attrib *unpack,
+                          GLsizei width, GLsizei height, GLsizei depth,
+                          GLenum format, GLenum type,
+                          GLsizei clientMemSize,
+                          const GLvoid *ptr, const char *where)
+{
+   assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
+
+   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
+                                  format, type, clientMemSize, ptr)) {
+      if (_mesa_is_bufferobj(unpack->BufferObj)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s(out of bounds PBO access)",
+                     where);
+      } else {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s(out of bounds access: bufSize (%d) is too small)",
+                     where, clientMemSize);
+      }
+      return false;
+   }
+
+   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+      /* non-PBO access: no further validation to be done */
+      return true;
+   }
+
+   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
+      /* buffer is already mapped - that's an error */
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
+                  where);
+      return false;
+   }
+
+   return true;
+}
+
+/**
+ * Perform PBO validation for read operations with compressed textures.
+ * If any GL errors are detected, false is returned, otherwise returns true.
+ */
+bool
+_mesa_validate_pbo_source_compressed(struct gl_context *ctx, GLuint dimensions,
+                                     const struct gl_pixelstore_attrib *unpack,
+                                     GLsizei imageSize, const GLvoid *pixels,
+                                     const char *where)
+{
+   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+      /* not using a PBO */
+      return true;
+   }
+
+   if ((const GLubyte *) pixels + imageSize >
+       ((const GLubyte *) 0) + unpack->BufferObj->Size) {
+      /* out of bounds read! */
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid PBO access)",
+                  where);
+      return false;
+   }
+
+   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
+      /* buffer is already mapped - that's an error */
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
+                  where);
+      return false;
+   }
+
+   return true;
+}
 
 /**
- * Combine PBO-read validation and mapping.
+ * Perform PBO-read mapping.
  * If any GL errors are detected, they'll be recorded and NULL returned.
- * \sa _mesa_validate_pbo_access
+ * \sa _mesa_validate_pbo_source
  * \sa _mesa_map_pbo_source
  * A call to this function should have a matching call to
  * _mesa_unmap_pbo_source().
@@ -149,27 +261,14 @@ _mesa_map_validate_pbo_source(struct gl_context *ctx,
                               GLuint dimensions,
                               const struct gl_pixelstore_attrib *unpack,
                               GLsizei width, GLsizei height, GLsizei depth,
-                              GLenum format, GLenum type, const GLvoid *ptr,
-                              const char *where)
+                              GLenum format, GLenum type,
+                              GLsizei clientMemSize,
+                              const GLvoid *ptr, const char *where)
 {
-   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
-
-   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
-      /* non-PBO access: no validation to be done */
-      return ptr;
-   }
-
-   if (!_mesa_validate_pbo_access(dimensions, unpack,
-                                  width, height, depth, format, type, ptr)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(out of bounds PBO access)", where);
-      return NULL;
-   }
-
-   if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
-      /* buffer is already mapped - that's an error */
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
-      return NULL;
+   if (!_mesa_validate_pbo_source(ctx, dimensions, unpack,
+                                  width, height, depth, format, type,
+                                  clientMemSize, ptr, where)) {
+     return NULL;
    }
 
    ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
@@ -184,10 +283,9 @@ void
 _mesa_unmap_pbo_source(struct gl_context *ctx,
                        const struct gl_pixelstore_attrib *unpack)
 {
-   ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
+   assert(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
    if (_mesa_is_bufferobj(unpack->BufferObj)) {
-      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
-                              unpack->BufferObj);
+      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
    }
 }
 
@@ -209,9 +307,11 @@ _mesa_map_pbo_dest(struct gl_context *ctx,
 
    if (_mesa_is_bufferobj(pack->BufferObj)) {
       /* pack into PBO */
-      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
-                                              GL_WRITE_ONLY_ARB,
-                                              pack->BufferObj);
+      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
+                                                  pack->BufferObj->Size,
+                                                  GL_MAP_WRITE_BIT,
+                                                  pack->BufferObj,
+                                                   MAP_INTERNAL);
       if (!buf)
          return NULL;
 
@@ -239,24 +339,30 @@ _mesa_map_validate_pbo_dest(struct gl_context *ctx,
                             GLuint dimensions,
                             const struct gl_pixelstore_attrib *unpack,
                             GLsizei width, GLsizei height, GLsizei depth,
-                            GLenum format, GLenum type, GLvoid *ptr,
-                            const char *where)
+                            GLenum format, GLenum type, GLsizei clientMemSize,
+                            GLvoid *ptr, const char *where)
 {
-   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
+   assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
 
-   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
-      /* non-PBO access: no validation to be done */
-      return ptr;
+   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
+                                  format, type, clientMemSize, ptr)) {
+      if (_mesa_is_bufferobj(unpack->BufferObj)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s(out of bounds PBO access)", where);
+      } else {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s(out of bounds access: bufSize (%d) is too small)",
+                     where, clientMemSize);
+      }
+      return NULL;
    }
 
-   if (!_mesa_validate_pbo_access(dimensions, unpack,
-                                  width, height, depth, format, type, ptr)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(out of bounds PBO access)", where);
-      return NULL;
+   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+      /* non-PBO access: no further validation to be done */
+      return ptr;
    }
 
-   if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
+   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
       /* buffer is already mapped - that's an error */
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
       return NULL;
@@ -274,14 +380,13 @@ void
 _mesa_unmap_pbo_dest(struct gl_context *ctx,
                      const struct gl_pixelstore_attrib *pack)
 {
-   ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
+   assert(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
    if (_mesa_is_bufferobj(pack->BufferObj)) {
-      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
+      ctx->Driver.UnmapBuffer(ctx, pack->BufferObj, MAP_INTERNAL);
    }
 }
 
 
-
 /**
  * Check if an unpack PBO is active prior to fetching a texture image.
  * If so, do bounds checking and map the buffer into main memory.
@@ -302,15 +407,20 @@ _mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
       return pixels;
    }
    if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
-                                  format, type, pixels)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
+                                  format, type, INT_MAX, pixels)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
+                  funcName, dimensions);
       return NULL;
    }
 
-   buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
-                                          GL_READ_ONLY_ARB, unpack->BufferObj);
+   buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
+                                                unpack->BufferObj->Size,
+                                               GL_MAP_READ_BIT,
+                                               unpack->BufferObj,
+                                                MAP_INTERNAL);
    if (!buf) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)");
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
+                  dimensions);
       return NULL;
    }
 
@@ -327,29 +437,34 @@ _mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
  */
 const GLvoid *
 _mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
-                                 GLsizei imageSize, const GLvoid *pixels,
+                                 GLuint dimensions, GLsizei imageSize,
+                                 const GLvoid *pixels,
                                  const struct gl_pixelstore_attrib *packing,
                                  const char *funcName)
 {
    GLubyte *buf;
 
+   if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, packing,
+                                             imageSize, pixels, funcName)) {
+     /* error is already set during validation */
+      return NULL;
+   }
+
    if (!_mesa_is_bufferobj(packing->BufferObj)) {
       /* not using a PBO - return pointer unchanged */
       return pixels;
    }
-   if ((const GLubyte *) pixels + imageSize >
-       ((const GLubyte *) 0) + packing->BufferObj->Size) {
-      /* out of bounds read! */
-      _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
-      return NULL;
-   }
 
-   buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
-                                         GL_READ_ONLY_ARB, packing->BufferObj);
-   if (!buf) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped");
-      return NULL;
-   }
+   buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0,
+                                              packing->BufferObj->Size,
+                                              GL_MAP_READ_BIT,
+                                              packing->BufferObj,
+                                               MAP_INTERNAL);
+
+   /* Validation above already checked that PBO is not mapped, so buffer
+    * should not be null.
+    */
+   assert(buf);
 
    return ADD_POINTERS(buf, pixels);
 }
@@ -364,9 +479,6 @@ _mesa_unmap_teximage_pbo(struct gl_context *ctx,
                          const struct gl_pixelstore_attrib *unpack)
 {
    if (_mesa_is_bufferobj(unpack->BufferObj)) {
-      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
-                              unpack->BufferObj);
+      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
    }
 }
-
-