[Mesa-dev] [PATCH 05/37] meta: added _mesa_meta_decompress_texture_image()

Ian Romanick idr at freedesktop.org
Mon Aug 15 14:43:37 PDT 2011


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/15/2011 11:53 AM, Eric Anholt wrote:
> From: Brian Paul <brianp at vmware.com>
> 
> Decompress a texture by drawing quad with the texture.
> ---
>  src/mesa/drivers/common/meta.c |  200 ++++++++++++++++++++++++++++++++++++++++
>  src/mesa/drivers/common/meta.h |    6 +
>  2 files changed, 206 insertions(+), 0 deletions(-)
> 
> diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
> index 19eae42..751f3b6 100644
> --- a/src/mesa/drivers/common/meta.c
> +++ b/src/mesa/drivers/common/meta.c
> @@ -287,6 +287,19 @@ struct gen_mipmap_state
>     GLuint FBO;
>  };
>  
> +
> +/**
> + * State for texture decompression
> + */
> +struct decompress_state
> +{
> +   GLuint ArrayObj;
> +   GLuint VBO, FBO, RBO;
> +   GLint Width, Height;
> +   GLenum RBFormat;
> +};
> +
> +
>  #define MAX_META_OPS_DEPTH      2
>  /**
>   * All per-context meta state.
> @@ -306,6 +319,7 @@ struct gl_meta_state
>     struct drawpix_state DrawPix;  /**< For _mesa_meta_DrawPixels() */
>     struct bitmap_state Bitmap;    /**< For _mesa_meta_Bitmap() */
>     struct gen_mipmap_state Mipmap;    /**< For _mesa_meta_GenerateMipmap() */
> +   struct decompress_state Decompress;  /**< For texture decompression */
>  };
>  
>  
> @@ -3094,3 +3108,189 @@ _mesa_meta_CopyColorSubTable(struct gl_context *ctx,GLenum target, GLsizei start
>  
>     free(buf);
>  }
> +
> +
> +/**
> + * Decompress a texture image by drawing a quad with the compressed
> + * texture and reading the pixels out of the color buffer.
> + * \param slice  which slice of a 3D texture or layer of a 1D/2D texture
> + * \param destFormat  format, ala glReadPixels
> + * \param destType  type, ala glReadPixels
> + * \param dest  destination buffer
> + * \param destRowLength  dest image rowLength (ala GL_PACK_ROW_LENGTH)
> + */
> +void
> +_mesa_meta_decompress_texture_image(struct gl_context *ctx,
> +                                    struct gl_texture_image *texImage,
> +                                    GLuint slice,
> +                                    GLenum destFormat, GLenum destType,
> +                                    GLvoid *dest, GLint destRowLength)
> +{
> +   struct decompress_state *decompress = &ctx->Meta->Decompress;
> +   struct gl_texture_object *texObj = texImage->TexObject;
> +   const GLint width = texImage->Width;
> +   const GLint height = texImage->Height;
> +   const GLenum target = texObj->Target;
> +   GLenum faceTarget, rbFormat;
> +   struct vertex {
> +      GLfloat x, y, tex[3];
> +   };
> +   struct vertex verts[4];
> +   GLuint fboDrawSave, fboReadSave;
> +   GLenum destDataType = _mesa_get_format_datatype(texImage->TexFormat);
> +
> +   if (slice > 0) {
> +      assert(target == GL_TEXTURE_3D ||
> +             target == GL_TEXTURE_2D_ARRAY);
> +   }
> +
> +   if (target == GL_TEXTURE_CUBE_MAP) {
> +      faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face;
> +   }
> +   else {
> +      faceTarget = target;
> +   }
> +
> +   /* save fbo bindings (not saved by _mesa_meta_begin()) */
> +   fboDrawSave = ctx->DrawBuffer->Name;
> +   fboReadSave = ctx->ReadBuffer->Name;
> +
> +   _mesa_meta_begin(ctx, META_ALL);
> +
> +   /* Create/bind FBO/renderbuffer */
> +   if (decompress->FBO == 0) {
> +      _mesa_GenFramebuffersEXT(1, &decompress->FBO);
> +      _mesa_GenRenderbuffersEXT(1, &decompress->RBO);
> +      _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, decompress->FBO);
> +      _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, decompress->RBO);
> +      _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
> +                                       GL_COLOR_ATTACHMENT0_EXT,
> +                                       GL_RENDERBUFFER_EXT,
> +                                       decompress->RBO);
> +   }
> +   else {
> +      _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, decompress->FBO);
> +   }
> +
> +   if (destDataType == GL_SIGNED_NORMALIZED) {
> +      rbFormat = GL_RGBA32F;
> +   } else {
> +      rbFormat = GL_RGBA;
> +   }

This bit seems odd.  Is GL_RGBA32F the right choice?  Won't this fail on
hardware that can do SIGNED_NORMALIZED but not float rendering?

> +
> +   /* alloc dest surface */
> +   if (width != decompress->Width || height != decompress->Height ||
> +       decompress->RBFormat != rbFormat) {
> +      _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, rbFormat,
> +                                   width, height);
> +      decompress->Width = width;
> +      decompress->Height = height;
> +      decompress->RBFormat = rbFormat;
> +   }
> +
> +   /* setup VBO data */
> +   if (decompress->ArrayObj == 0) {
> +      /* create vertex array object */
> +      _mesa_GenVertexArrays(1, &decompress->ArrayObj);
> +      _mesa_BindVertexArray(decompress->ArrayObj);
> +
> +      /* create vertex array buffer */
> +      _mesa_GenBuffersARB(1, &decompress->VBO);
> +      _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, decompress->VBO);
> +
> +      /* setup vertex arrays */
> +      _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
> +      _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(tex));
> +      _mesa_EnableClientState(GL_VERTEX_ARRAY);
> +      _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
> +   }
> +   else {
> +      _mesa_BindVertexArray(decompress->ArrayObj);
> +      _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, decompress->VBO);
> +   }
> +
> +   setup_texture_coords(faceTarget, slice, width, height,
> +                        verts[0].tex,
> +                        verts[1].tex,
> +                        verts[2].tex,
> +                        verts[3].tex);
> +
> +   /* setup vertex positions */
> +   verts[0].x = 0.0F;
> +   verts[0].y = 0.0F;
> +   verts[1].x = width;
> +   verts[1].y = 0.0F;
> +   verts[2].x = width;
> +   verts[2].y = height;
> +   verts[3].x = 0.0F;
> +   verts[3].y = height;
> +
> +   /* upload new vertex data */
> +   _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
> +		       GL_DYNAMIC_DRAW_ARB);
> +
> +   /* setup texture state */
> +   _mesa_BindTexture(target, texObj->Name);
> +   _mesa_Enable(target);
> +
> +   {
> +      /* save texture object state */
> +      const GLenum minFilterSave = texObj->Sampler.MinFilter;
> +      const GLenum magFilterSave = texObj->Sampler.MagFilter;
> +      const GLint baseLevelSave = texObj->BaseLevel;
> +      const GLint maxLevelSave = texObj->MaxLevel;
> +      const GLenum wrapSSave = texObj->Sampler.WrapS;
> +      const GLenum wrapTSave = texObj->Sampler.WrapT;
> +      const GLenum srgbSave = texObj->Sampler.sRGBDecode;
> +
> +      /* restrict sampling to the texture level of interest */
> +      _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, texImage->Level);
> +      _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, texImage->Level);
> +      /* nearest filtering */
> +      _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
> +      _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
> +
> +      /* No sRGB decode or encode.*/
> +      if (ctx->Extensions.EXT_texture_sRGB_decode) {
> +         _mesa_TexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT,
> +                             GL_SKIP_DECODE_EXT);
> +      }
> +      if (ctx->Extensions.EXT_framebuffer_sRGB) {
> +         _mesa_Disable(GL_FRAMEBUFFER_SRGB_EXT);
> +      }
> +
> +      /* render quad w/ texture into renderbuffer */
> +      _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
> +      
> +      /* Restore texture object state, the texture binding will
> +       * be restored by _mesa_meta_end().
> +       */
> +      _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave);
> +      _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave);
> +      if (target != GL_TEXTURE_RECTANGLE_ARB) {
> +         _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave);
> +         _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave);
> +      }
> +      _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, wrapSSave);
> +      _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, wrapTSave);
> +      if (ctx->Extensions.EXT_texture_sRGB_decode) {
> +         _mesa_TexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT, srgbSave);
> +      }
> +   }
> +
> +   /* read pixels from renderbuffer */
> +   ctx->Pack.RowLength = destRowLength;
> +   _mesa_ReadPixels(0, 0, width, height, destFormat, destType, dest);
> +
> +   _mesa_meta_end(ctx);
> +
> +   /* restore fbo bindings */
> +   if (fboDrawSave == fboReadSave) {
> +      _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboDrawSave);
> +   }
> +   else {
> +      _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fboDrawSave);
> +      _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fboReadSave);
> +   }
> +}
> +
> diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h
> index 95b4b55..50389c9 100644
> --- a/src/mesa/drivers/common/meta.h
> +++ b/src/mesa/drivers/common/meta.h
> @@ -107,5 +107,11 @@ _mesa_meta_CopyConvolutionFilter2D(struct gl_context *ctx, GLenum target,
>                                     GLenum internalFormat, GLint x, GLint y,
>                                     GLsizei width, GLsizei height);
>  
> +void
> +_mesa_meta_decompress_texture_image(struct gl_context *ctx,
> +                                    struct gl_texture_image *texImage,
> +                                    GLuint slice,
> +                                    GLenum destFormat, GLenum destType,
> +                                    GLvoid *dest, GLint destRowLength);
>  
>  #endif /* META_H */

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAk5JkwkACgkQX1gOwKyEAw/dmwCfYOivz5pJ81hNzdO1xp1LuAlH
2hEAn3RoDYcDvWQvn761mbZI6rKmFjl8
=ylMP
-----END PGP SIGNATURE-----


More information about the mesa-dev mailing list