intel: use driReadDrawable in do_copy_texsubimage()
[mesa.git] / src / mesa / main / bufferobj.c
index f96185a4b5d98e26e30eb06d5527fd537a8a8446..189b5e165585ef37bbd1d5c507319daac9adf72e 100644 (file)
@@ -314,9 +314,10 @@ _mesa_initialize_buffer_object( struct gl_buffer_object *obj,
  * \param usage   Hints about how the data will be used.
  * \param bufObj  Object to be used.
  *
+ * \return GL_TRUE for success, GL_FALSE for failure
  * \sa glBufferDataARB, dd_function_table::BufferData.
  */
-static void
+static GLboolean
 _mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
                   const GLvoid * data, GLenum usage,
                   struct gl_buffer_object * bufObj )
@@ -334,6 +335,11 @@ _mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
       if (data) {
         _mesa_memcpy( bufObj->Data, data, size );
       }
+
+      return GL_TRUE;
+   }
+   else {
+      return GL_FALSE;
    }
 }
 
@@ -428,6 +434,8 @@ _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
       return NULL;
    }
    bufObj->Pointer = bufObj->Data;
+   bufObj->Length = bufObj->Size;
+   bufObj->Offset = 0;
    return bufObj->Pointer;
 }
 
@@ -443,11 +451,13 @@ _mesa_buffer_map_range( GLcontext *ctx, GLenum target, GLintptr offset,
 {
    (void) ctx;
    (void) target;
-   (void) access;
-   (void) length;
    assert(!_mesa_bufferobj_mapped(bufObj));
    /* Just return a direct pointer to the data */
-   return bufObj->Data + offset;
+   bufObj->Pointer = bufObj->Data + offset;
+   bufObj->Length = length;
+   bufObj->Offset = offset;
+   bufObj->AccessFlags = access;
+   return bufObj->Pointer;
 }
 
 
@@ -484,6 +494,9 @@ _mesa_buffer_unmap( GLcontext *ctx, GLenum target,
    (void) target;
    /* XXX we might assert here that bufObj->Pointer is non-null */
    bufObj->Pointer = NULL;
+   bufObj->Length = 0;
+   bufObj->Offset = 0;
+   bufObj->AccessFlags = 0x0;
    return GL_TRUE;
 }
 
@@ -645,6 +658,8 @@ _mesa_update_default_objects_buffer_objects(GLcontext *ctx)
  * currently mapped.  Whoever calls this function should check for that.
  * Remember, we can't use a PBO when it's mapped!
  *
+ * If we're not using a PBO, this is a no-op.
+ *
  * \param width  width of image to read/write
  * \param height  height of image to read/write
  * \param depth  depth of image to read/write
@@ -663,7 +678,8 @@ _mesa_validate_pbo_access(GLuint dimensions,
    GLvoid *start, *end;
    const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
 
-   ASSERT(_mesa_is_bufferobj(pack->BufferObj));
+   if (!_mesa_is_bufferobj(pack->BufferObj))
+      return GL_TRUE;  /* no PBO, OK */
 
    if (pack->BufferObj->Size == 0)
       /* no buffer! */
@@ -695,17 +711,18 @@ _mesa_validate_pbo_access(GLuint dimensions,
 
 
 /**
- * If the source of glBitmap data is a PBO, check that we won't read out
- * of buffer bounds, then map the buffer.
- * If not sourcing from a PBO, just return the bitmap pointer.
- * This is a helper function for (some) drivers.
- * Return NULL if error.
- * If non-null return, must call _mesa_unmap_bitmap_pbo() when done.
+ * For commands that read from a PBO (glDrawPixels, glTexImage,
+ * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
+ * and return the pointer into the PBO.  If we're not reading from a
+ * PBO, return \p src as-is.
+ * If non-null return, must call _mesa_unmap_pbo_source() when done.
+ *
+ * \return NULL if error, else pointer to start of data
  */
-const GLubyte *
-_mesa_map_bitmap_pbo(GLcontext *ctx,
+const GLvoid *
+_mesa_map_pbo_source(GLcontext *ctx,
                      const struct gl_pixelstore_attrib *unpack,
-                     const GLubyte *bitmap)
+                     const GLvoid *src)
 {
    const GLubyte *buf;
 
@@ -717,11 +734,11 @@ _mesa_map_bitmap_pbo(GLcontext *ctx,
       if (!buf)
          return NULL;
 
-      buf = ADD_POINTERS(buf, bitmap);
+      buf = ADD_POINTERS(buf, src);
    }
    else {
       /* unpack from normal memory */
-      buf = bitmap;
+      buf = src;
    }
 
    return buf;
@@ -729,56 +746,54 @@ _mesa_map_bitmap_pbo(GLcontext *ctx,
 
 
 /**
- * Counterpart to _mesa_map_bitmap_pbo()
- * This is a helper function for (some) drivers.
- */
-void
-_mesa_unmap_bitmap_pbo(GLcontext *ctx,
-                       const struct gl_pixelstore_attrib *unpack)
-{
-   if (_mesa_is_bufferobj(unpack->BufferObj)) {
-      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
-                              unpack->BufferObj);
-   }
-}
-
-
-/**
- * \sa _mesa_map_bitmap_pbo
+ * Combine PBO-read validation and mapping.
+ * If any GL errors are detected, they'll be recorded and NULL returned.
+ * \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_drawpix_pbo(GLcontext *ctx,
-                      const struct gl_pixelstore_attrib *unpack,
-                      const GLvoid *pixels)
+_mesa_map_validate_pbo_source(GLcontext *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)
 {
-   const GLvoid *buf;
+   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
 
-   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);
-      if (!buf)
-         return NULL;
+   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+      /* non-PBO access: no validation to be done */
+      return ptr;
+   }
 
-      buf = ADD_POINTERS(buf, pixels);
+   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;
    }
-   else {
-      /* unpack from normal memory */
-      buf = pixels;
+
+   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;
    }
 
-   return buf;
+   ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
+   return ptr;
 }
 
 
 /**
- * \sa _mesa_unmap_bitmap_pbo
+ * Counterpart to _mesa_map_pbo_source()
  */
 void
-_mesa_unmap_drawpix_pbo(GLcontext *ctx,
-                        const struct gl_pixelstore_attrib *unpack)
+_mesa_unmap_pbo_source(GLcontext *ctx,
+                       const struct gl_pixelstore_attrib *unpack)
 {
+   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);
@@ -787,14 +802,17 @@ _mesa_unmap_drawpix_pbo(GLcontext *ctx,
 
 
 /**
- * If PBO is bound, map the buffer, return dest pointer in mapped buffer.
- * Call _mesa_unmap_readpix_pbo() when finished
- * \return NULL if error
+ * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
+ * if we're writing to a PBO, map it write-only and return the pointer
+ * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
+ * If non-null return, must call _mesa_unmap_pbo_dest() when done.
+ *
+ * \return NULL if error, else pointer to start of data
  */
 void *
-_mesa_map_readpix_pbo(GLcontext *ctx,
-                      const struct gl_pixelstore_attrib *pack,
-                      GLvoid *dest)
+_mesa_map_pbo_dest(GLcontext *ctx,
+                   const struct gl_pixelstore_attrib *pack,
+                   GLvoid *dest)
 {
    void *buf;
 
@@ -818,12 +836,54 @@ _mesa_map_readpix_pbo(GLcontext *ctx,
 
 
 /**
- * Counterpart to _mesa_map_readpix_pbo()
+ * Combine PBO-write validation and mapping.
+ * If any GL errors are detected, they'll be recorded and NULL returned.
+ * \sa _mesa_validate_pbo_access
+ * \sa _mesa_map_pbo_dest
+ * A call to this function should have a matching call to
+ * _mesa_unmap_pbo_dest().
+ */
+GLvoid *
+_mesa_map_validate_pbo_dest(GLcontext *ctx,
+                            GLuint dimensions,
+                            const struct gl_pixelstore_attrib *unpack,
+                            GLsizei width, GLsizei height, GLsizei depth,
+                            GLenum format, GLenum type, 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;
+   }
+
+   ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
+   return ptr;
+}
+
+
+/**
+ * Counterpart to _mesa_map_pbo_dest()
  */
 void
-_mesa_unmap_readpix_pbo(GLcontext *ctx,
-                        const struct gl_pixelstore_attrib *pack)
+_mesa_unmap_pbo_dest(GLcontext *ctx,
+                     const struct gl_pixelstore_attrib *pack)
 {
+   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);
    }
@@ -1095,13 +1155,11 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
       /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
       ctx->Driver.UnmapBuffer(ctx, target, bufObj);
       bufObj->AccessFlags = DEFAULT_ACCESS;
-      bufObj->Pointer = NULL;
+      ASSERT(bufObj->Pointer == NULL);
    }  
 
    FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
 
-   ASSERT(ctx->Driver.BufferData);
-
    bufObj->Written = GL_TRUE;
 
 #ifdef VBO_DEBUG
@@ -1112,8 +1170,11 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
 #ifdef BOUNDS_CHECK
    size += 100;
 #endif
-   /* Give the buffer object to the driver!  <data> may be null! */
-   ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj );
+
+   ASSERT(ctx->Driver.BufferData);
+   if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()");
+   }
 }
 
 
@@ -1165,6 +1226,8 @@ _mesa_MapBufferARB(GLenum target, GLenum access)
    GET_CURRENT_CONTEXT(ctx);
    struct gl_buffer_object * bufObj;
    GLbitfield accessFlags;
+   void *map;
+
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
 
    switch (access) {
@@ -1197,14 +1260,21 @@ _mesa_MapBufferARB(GLenum target, GLenum access)
    }
 
    ASSERT(ctx->Driver.MapBuffer);
-   bufObj->Pointer = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
-   if (!_mesa_bufferobj_mapped(bufObj)) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)");
+   map = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
+   if (!map) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
+      return NULL;
+   }
+   else {
+      /* The driver callback should have set these fields.
+       * This is important because other modules (like VBO) might call
+       * the driver function directly.
+       */
+      ASSERT(bufObj->Pointer == map);
+      ASSERT(bufObj->Length == bufObj->Size);
+      ASSERT(bufObj->Offset == 0);
+      bufObj->AccessFlags = accessFlags;
    }
-
-   bufObj->AccessFlags = accessFlags;
-   bufObj->Offset = 0;
-   bufObj->Length = bufObj->Size;
 
    if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
       bufObj->Written = GL_TRUE;
@@ -1295,9 +1365,9 @@ _mesa_UnmapBufferARB(GLenum target)
 
    status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
    bufObj->AccessFlags = DEFAULT_ACCESS;
-   bufObj->Pointer = NULL;
-   bufObj->Offset = 0;
-   bufObj->Length = 0;
+   ASSERT(bufObj->Pointer == NULL);
+   ASSERT(bufObj->Offset == 0);
+   ASSERT(bufObj->Length == 0);
 
    return status;
 }
@@ -1455,6 +1525,8 @@ _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
 {
    GET_CURRENT_CONTEXT(ctx);
    struct gl_buffer_object *bufObj;
+   void *map;
+
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
 
    if (!ctx->Extensions.ARB_map_buffer_range) {
@@ -1518,14 +1590,23 @@ _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
    }
       
    ASSERT(ctx->Driver.MapBufferRange);
-   bufObj->Pointer = ctx->Driver.MapBufferRange(ctx, target, offset, length,
-                                                access, bufObj);
-
-   bufObj->Offset = offset;
-   bufObj->Length = length;
-   bufObj->AccessFlags = access;
+   map = ctx->Driver.MapBufferRange(ctx, target, offset, length,
+                                    access, bufObj);
+   if (!map) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
+   }
+   else {
+      /* The driver callback should have set all these fields.
+       * This is important because other modules (like VBO) might call
+       * the driver function directly.
+       */
+      ASSERT(bufObj->Pointer == map);
+      ASSERT(bufObj->Length == length);
+      ASSERT(bufObj->Offset == offset);
+      ASSERT(bufObj->AccessFlags == access);
+   }
 
-   return bufObj->Pointer;
+   return map;
 }