[Mesa-dev] [PATCH 11/12] mesa/meta: Support decompressing floating-point formats

Neil Roberts neil at linux.intel.com
Wed Aug 6 09:27:56 PDT 2014


Previously the Meta implementation of glGetTexImage would fall back to
_mesa_get_teximage if the texturing is not using an unsigned normalised
format. However in order to support the half-float formats of BPTC textures we
can make it render to a floating-point renderbuffer instead. This patch makes
decompression_state have two FBOs, one for the GL_RGBA format and one for
GL_RGBA32F. If a floating-point texture is encountered it will try setting up
a floating-point FBO. It will now also check the status of the FBO and fall
back to _mesa_get_teximage if the FBO is not complete.
---
 src/mesa/drivers/common/meta.c | 97 ++++++++++++++++++++++++++++--------------
 src/mesa/drivers/common/meta.h | 14 +++++-
 2 files changed, 78 insertions(+), 33 deletions(-)

diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
index f8f0ee3..c3764ee 100644
--- a/src/mesa/drivers/common/meta.c
+++ b/src/mesa/drivers/common/meta.c
@@ -2940,14 +2940,22 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
    free(buf);
 }
 
+static void
+meta_decompress_fbo_cleanup(struct decompress_fbo_state *decompress_fbo)
+{
+   if (decompress_fbo->FBO != 0) {
+      _mesa_DeleteFramebuffers(1, &decompress_fbo->FBO);
+      _mesa_DeleteRenderbuffers(1, &decompress_fbo->RBO);
+   }
+
+   memset(decompress_fbo, 0, sizeof(*decompress_fbo));
+}
 
 static void
 meta_decompress_cleanup(struct decompress_state *decompress)
 {
-   if (decompress->FBO != 0) {
-      _mesa_DeleteFramebuffers(1, &decompress->FBO);
-      _mesa_DeleteRenderbuffers(1, &decompress->RBO);
-   }
+   meta_decompress_fbo_cleanup(&decompress->byteFBO);
+   meta_decompress_fbo_cleanup(&decompress->floatFBO);
 
    if (decompress->VAO != 0) {
       _mesa_DeleteVertexArrays(1, &decompress->VAO);
@@ -2969,7 +2977,7 @@ meta_decompress_cleanup(struct decompress_state *decompress)
  * \param dest  destination buffer
  * \param destRowLength  dest image rowLength (ala GL_PACK_ROW_LENGTH)
  */
-static void
+static bool
 decompress_texture_image(struct gl_context *ctx,
                          struct gl_texture_image *texImage,
                          GLuint slice,
@@ -2977,17 +2985,33 @@ decompress_texture_image(struct gl_context *ctx,
                          GLvoid *dest)
 {
    struct decompress_state *decompress = &ctx->Meta->Decompress;
+   struct decompress_fbo_state *decompress_fbo;
    struct gl_texture_object *texObj = texImage->TexObject;
    const GLint width = texImage->Width;
    const GLint height = texImage->Height;
    const GLint depth = texImage->Height;
    const GLenum target = texObj->Target;
+   GLenum rbFormat;
    GLenum faceTarget;
    struct vertex verts[4];
    GLuint samplerSave;
+   GLenum status;
    const bool use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
                                       ctx->Extensions.ARB_fragment_shader;
 
+   switch (_mesa_get_format_datatype(texImage->TexFormat)) {
+   case GL_FLOAT:
+      decompress_fbo = &decompress->floatFBO;
+      rbFormat = GL_RGBA32F;
+      break;
+   case GL_UNSIGNED_NORMALIZED:
+      decompress_fbo = &decompress->byteFBO;
+      rbFormat = GL_RGBA;
+      break;
+   default:
+      return false;
+   }
+
    if (slice > 0) {
       assert(target == GL_TEXTURE_3D ||
              target == GL_TEXTURE_2D_ARRAY ||
@@ -2998,11 +3022,11 @@ decompress_texture_image(struct gl_context *ctx,
    case GL_TEXTURE_1D:
    case GL_TEXTURE_1D_ARRAY:
       assert(!"No compressed 1D textures.");
-      return;
+      return false;
 
    case GL_TEXTURE_3D:
       assert(!"No compressed 3D textures.");
-      return;
+      return false;
 
    case GL_TEXTURE_CUBE_MAP_ARRAY:
       faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + (slice % 6);
@@ -3024,27 +3048,35 @@ decompress_texture_image(struct gl_context *ctx,
          ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
 
    /* Create/bind FBO/renderbuffer */
-   if (decompress->FBO == 0) {
-      _mesa_GenFramebuffers(1, &decompress->FBO);
-      _mesa_GenRenderbuffers(1, &decompress->RBO);
-      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO);
-      _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO);
+   if (decompress_fbo->FBO == 0) {
+      _mesa_GenFramebuffers(1, &decompress_fbo->FBO);
+      _mesa_GenRenderbuffers(1, &decompress_fbo->RBO);
+      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress_fbo->FBO);
+      _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress_fbo->RBO);
       _mesa_FramebufferRenderbuffer(GL_FRAMEBUFFER_EXT,
                                        GL_COLOR_ATTACHMENT0_EXT,
                                        GL_RENDERBUFFER_EXT,
-                                       decompress->RBO);
+                                       decompress_fbo->RBO);
    }
    else {
-      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO);
+      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress_fbo->FBO);
    }
 
    /* alloc dest surface */
-   if (width > decompress->Width || height > decompress->Height) {
-      _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO);
-      _mesa_RenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA,
-                                   width, height);
-      decompress->Width = width;
-      decompress->Height = height;
+   if (width > decompress_fbo->Width || height > decompress_fbo->Height) {
+      _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress_fbo->RBO);
+      _mesa_RenderbufferStorage(GL_RENDERBUFFER_EXT, rbFormat,
+                                width, height);
+      status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+      if (status != GL_FRAMEBUFFER_COMPLETE) {
+         /* If the framebuffer isn't complete then we'll leave
+          * decompress_fbo->Width as zero so that it will fail again next time
+          * too */
+         _mesa_meta_end(ctx);
+         return false;
+      }
+      decompress_fbo->Width = width;
+      decompress_fbo->Height = height;
    }
 
    if (use_glsl_version) {
@@ -3166,6 +3198,8 @@ decompress_texture_image(struct gl_context *ctx,
    _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave);
 
    _mesa_meta_end(ctx);
+
+   return true;
 }
 
 
@@ -3179,15 +3213,11 @@ _mesa_meta_GetTexImage(struct gl_context *ctx,
                        GLenum format, GLenum type, GLvoid *pixels,
                        struct gl_texture_image *texImage)
 {
-   /* We can only use the decompress-with-blit method here if the texels are
-    * unsigned, normalized values.  We could handle signed and unnormalized 
-    * with floating point renderbuffers...
-    */
-   if (_mesa_is_format_compressed(texImage->TexFormat) &&
-       _mesa_get_format_datatype(texImage->TexFormat)
-       == GL_UNSIGNED_NORMALIZED) {
+   if (_mesa_is_format_compressed(texImage->TexFormat)) {
       struct gl_texture_object *texObj = texImage->TexObject;
       GLuint slice;
+      bool result;
+
       /* Need to unlock the texture here to prevent deadlock... */
       _mesa_unlock_texture(ctx, texObj);
       for (slice = 0; slice < texImage->Depth; slice++) {
@@ -3209,14 +3239,19 @@ _mesa_meta_GetTexImage(struct gl_context *ctx,
          else {
             dst = pixels;
          }
-         decompress_texture_image(ctx, texImage, slice, format, type, dst);
+         result = decompress_texture_image(ctx, texImage, slice,
+                                           format, type, dst);
+         if (!result)
+            break;
       }
       /* ... and relock it */
       _mesa_lock_texture(ctx, texObj);
+
+      if (result)
+         return;
    }
-   else {
-      _mesa_get_teximage(ctx, format, type, pixels, texImage);
-   }
+
+   _mesa_get_teximage(ctx, format, type, pixels, texImage);
 }
 
 
diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h
index b269dce..982e69d 100644
--- a/src/mesa/drivers/common/meta.h
+++ b/src/mesa/drivers/common/meta.h
@@ -343,13 +343,23 @@ struct gen_mipmap_state
 };
 
 /**
+ * One of the FBO states for decompress_state. There will be one for each
+ * required renderbuffer format.
+ */
+struct decompress_fbo_state
+{
+   GLuint FBO, RBO;
+   GLint Width, Height;
+};
+
+/**
  * State for texture decompression
  */
 struct decompress_state
 {
    GLuint VAO;
-   GLuint VBO, FBO, RBO, Sampler;
-   GLint Width, Height;
+   struct decompress_fbo_state byteFBO, floatFBO;
+   GLuint VBO, Sampler;
 
    struct blit_shader_table shaders;
 };
-- 
1.9.3



More information about the mesa-dev mailing list