Move compiler.h and imports.h/c from src/mesa/main into src/util
[mesa.git] / src / mesa / main / pbo.c
index 15e0480e9f104555db079e3274a9390973484b27..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"
 
@@ -68,8 +71,8 @@ _mesa_validate_pbo_access(GLuint dimensions,
                           GLenum format, GLenum type, GLsizei clientMemSize,
                           const GLvoid *ptr)
 {
-   const GLvoid *start, *end, *offset;
-   const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
+   /* 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.
@@ -78,29 +81,51 @@ _mesa_validate_pbo_access(GLuint dimensions,
     */
    if (!_mesa_is_bufferobj(pack->BufferObj)) {
       offset = 0;
-      sizeAddr = ((const GLubyte *) 0) + clientMemSize;
+      size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize;
    } else {
-      offset = ptr;
-      sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
+      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 (sizeAddr == 0)
+   if (size == 0)
       /* no buffer! */
       return GL_FALSE;
 
+   /* 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 the offset to the first pixel we'll read/write */
-   start = _mesa_image_address(dimensions, pack, offset, width, height,
-                               format, type, 0, 0, 0);
+   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_address(dimensions, pack, offset, width, height,
-                              format, type, depth-1, height-1, width);
+   end =  _mesa_image_offset(dimensions, pack, width, height,
+                             format, type, depth-1, height-1, width);
 
-   if ((const GLubyte *) start > sizeAddr) {
+   start += offset;
+   end += offset;
+
+   if (start > size) {
       /* This will catch negative values / wrap-around */
       return GL_FALSE;
    }
-   if ((const GLubyte *) end > sizeAddr) {
+   if (end > size) {
       /* Image read/write goes beyond end of buffer */
       return GL_FALSE;
    }
@@ -128,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;
 
@@ -144,47 +171,104 @@ _mesa_map_pbo_source(struct gl_context *ctx,
    return buf;
 }
 
-
 /**
- * Combine PBO-read validation and mapping.
- * If any GL errors are detected, they'll be recorded and NULL returned.
+ * 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
- * \sa _mesa_map_pbo_source
- * A call to this function should have a matching call to
- * _mesa_unmap_pbo_source().
  */
-const GLvoid *
-_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, GLsizei clientMemSize,
-                                 const GLvoid *ptr, const char *where)
+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);
+   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);
+                     "%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;
+      return false;
    }
 
    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
       /* non-PBO access: no further validation to be done */
-      return ptr;
+      return true;
    }
 
-   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;
+      _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;
+}
+
+/**
+ * Perform PBO-read mapping.
+ * If any GL errors are detected, they'll be recorded and NULL returned.
+ * \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().
+ */
+const GLvoid *
+_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,
+                              GLsizei clientMemSize,
+                              const GLvoid *ptr, const char *where)
+{
+   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);
@@ -199,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);
    }
 }
 
@@ -224,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;
 
@@ -251,13 +336,13 @@ _mesa_map_pbo_dest(struct gl_context *ctx,
  */
 GLvoid *
 _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, GLsizei clientMemSize,
-                               GLvoid *ptr, const char *where)
+                            GLuint dimensions,
+                            const struct gl_pixelstore_attrib *unpack,
+                            GLsizei width, GLsizei height, GLsizei depth,
+                            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_validate_pbo_access(dimensions, unpack, width, height, depth,
                                   format, type, clientMemSize, ptr)) {
@@ -277,7 +362,7 @@ _mesa_map_validate_pbo_dest(struct gl_context *ctx,
       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;
@@ -295,9 +380,9 @@ 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);
    }
 }
 
@@ -322,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, INT_MAX, 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;
    }
 
@@ -347,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);
 }
@@ -384,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);
    }
 }
-
-