mesa/main: Make FEATURE_dlist follow feature conventions.
[mesa.git] / src / mesa / main / texgetimage.c
index 02409d80098368889923664ce81750222cbecbcc..14d6fc76590c7ba3223793d389ebcf5da3f27402 100644 (file)
 
 
 #include "glheader.h"
+#include "bufferobj.h"
 #include "context.h"
 #include "image.h"
 #include "texcompress.h"
 #include "texformat.h"
 #include "texgetimage.h"
+#include "teximage.h"
+#include "texstate.h"
 
 
 
@@ -116,7 +119,7 @@ _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
 {
    const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
 
-   if (ctx->Pack.BufferObj->Name) {
+   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
       /* Packing texture image into a PBO.
        * Map the (potentially) VRAM-based buffer into our process space so
        * we can write into it with the code below.
@@ -296,7 +299,7 @@ _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
       } /* img */
    }
 
-   if (ctx->Pack.BufferObj->Name) {
+   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
       ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
                               ctx->Pack.BufferObj);
    }
@@ -316,7 +319,7 @@ _mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,
 {
    GLuint size;
 
-   if (ctx->Pack.BufferObj->Name) {
+   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
       /* pack texture image into a PBO */
       GLubyte *buf;
       if ((const GLubyte *) img + texImage->CompressedSize >
@@ -349,8 +352,230 @@ _mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,
    /* just memcpy, no pixelstore or pixel transfer */
    _mesa_memcpy(img, texImage->Data, size);
 
-   if (ctx->Pack.BufferObj->Name) {
+   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
       ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
                               ctx->Pack.BufferObj);
    }
 }
+
+
+
+/**
+ * Do error checking for a glGetTexImage() call.
+ * \return GL_TRUE if any error, GL_FALSE if no errors.
+ */
+static GLboolean
+getteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
+                        GLenum format, GLenum type, GLvoid *pixels )
+{
+   const struct gl_texture_unit *texUnit;
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+   const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);
+
+   if (maxLevels == 0) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
+      return GL_TRUE;
+   }
+
+   if (level < 0 || level >= maxLevels) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
+      return GL_TRUE;
+   }
+
+   if (_mesa_sizeof_packed_type(type) <= 0) {
+      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
+      return GL_TRUE;
+   }
+
+   if (_mesa_components_in_format(format) <= 0 ||
+       format == GL_STENCIL_INDEX) {
+      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
+      return GL_TRUE;
+   }
+
+   if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
+      return GL_TRUE;
+   }
+
+   if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
+      return GL_TRUE;
+   }
+
+   if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
+      return GL_TRUE;
+   }
+
+   if (!ctx->Extensions.EXT_packed_depth_stencil
+       && _mesa_is_depthstencil_format(format)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
+      return GL_TRUE;
+   }
+
+   if (!ctx->Extensions.ATI_envmap_bumpmap
+       && _mesa_is_dudv_format(format)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
+      return GL_TRUE;
+   }
+
+   texUnit = _mesa_get_current_tex_unit(ctx);
+   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+   if (!texObj || _mesa_is_proxy_texture(target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
+      return GL_TRUE;
+   }
+
+   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+   if (!texImage) {
+      /* out of memory */
+      return GL_TRUE;
+   }
+      
+   /* Make sure the requested image format is compatible with the
+    * texture's format.  Note that a color index texture can be converted
+    * to RGBA so that combo is allowed.
+    */
+   if (_mesa_is_color_format(format)
+       && !_mesa_is_color_format(texImage->TexFormat->BaseFormat)
+       && !_mesa_is_index_format(texImage->TexFormat->BaseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+      return GL_TRUE;
+   }
+   else if (_mesa_is_index_format(format)
+            && !_mesa_is_index_format(texImage->TexFormat->BaseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+      return GL_TRUE;
+   }
+   else if (_mesa_is_depth_format(format)
+            && !_mesa_is_depth_format(texImage->TexFormat->BaseFormat)
+            && !_mesa_is_depthstencil_format(texImage->TexFormat->BaseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+      return GL_TRUE;
+   }
+   else if (_mesa_is_ycbcr_format(format)
+            && !_mesa_is_ycbcr_format(texImage->TexFormat->BaseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+      return GL_TRUE;
+   }
+   else if (_mesa_is_depthstencil_format(format)
+            && !_mesa_is_depthstencil_format(texImage->TexFormat->BaseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+      return GL_TRUE;
+   }
+   else if (_mesa_is_dudv_format(format)
+            && !_mesa_is_dudv_format(texImage->TexFormat->BaseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+      return GL_TRUE;
+   }
+
+   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
+      /* packing texture image into a PBO */
+      const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
+      if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
+                                     texImage->Height, texImage->Depth,
+                                     format, type, pixels)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetTexImage(invalid PBO access)");
+         return GL_TRUE;
+      }
+   }
+
+   return GL_FALSE;
+}
+
+
+
+/**
+ * Get texture image.  Called by glGetTexImage.
+ *
+ * \param target texture target.
+ * \param level image level.
+ * \param format pixel data format for returned image.
+ * \param type pixel data type for returned image.
+ * \param pixels returned pixel data.
+ */
+void GLAPIENTRY
+_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
+                   GLenum type, GLvoid *pixels )
+{
+   const struct gl_texture_unit *texUnit;
+   struct gl_texture_object *texObj;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   if (getteximage_error_check(ctx, target, level, format, type, pixels)) {
+      return;
+   }
+
+   texUnit = _mesa_get_current_tex_unit(ctx);
+   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+   _mesa_lock_texture(ctx, texObj);
+   {
+      struct gl_texture_image *texImage =
+         _mesa_select_tex_image(ctx, texObj, target, level);
+
+      /* typically, this will call _mesa_get_teximage() */
+      ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
+                              texObj, texImage);
+   }
+   _mesa_unlock_texture(ctx, texObj);
+}
+
+
+void GLAPIENTRY
+_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
+{
+   const struct gl_texture_unit *texUnit;
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+   GLint maxLevels;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   texUnit = _mesa_get_current_tex_unit(ctx);
+   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   if (!texObj) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB");
+      return;
+   }
+
+   maxLevels = _mesa_max_texture_levels(ctx, target);
+   ASSERT(maxLevels > 0); /* 0 indicates bad target, caught above */
+
+   if (level < 0 || level >= maxLevels) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)");
+      return;
+   }
+
+   if (_mesa_is_proxy_texture(target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
+      return;
+   }
+
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+      if (texImage) {
+         if (texImage->IsCompressed) {
+            /* this typically calls _mesa_get_compressed_teximage() */
+            ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
+                                              texObj, texImage);
+         }
+         else {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glGetCompressedTexImageARB");
+         }
+      }
+      else {
+         /* probably invalid mipmap level */
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glGetCompressedTexImageARB(level)");
+      }
+   }
+   _mesa_unlock_texture(ctx, texObj);
+}