[Mesa-dev] [PATCH 2/5] st/mesa: add support for ETC2 formats

Marek Olšák maraeo at gmail.com
Sun Aug 3 10:10:17 PDT 2014


On Sun, Aug 3, 2014 at 6:23 PM, Glenn Kennard <glenn.kennard at gmail.com> wrote:
> On Sun, 03 Aug 2014 14:40:37 +0200, Marek Olšák <maraeo at gmail.com> wrote:
>
>> From: Marek Olšák <marek.olsak at amd.com>
>>
>> The formats are emulated by translating them into plain uncompressed
>> formats, because I don't know of any hardware which supports them.
>>
>> This is required for GLES 3.0 and ARB_ES3_compatibility (GL 4.3).
>> ---
>>  src/mesa/state_tracker/st_cb_texture.c | 54
>> ++++++++++++++++++++++++++++++++--
>>  src/mesa/state_tracker/st_format.c     | 24 +++++++++++++++
>>  src/mesa/state_tracker/st_texture.c    | 11 +++----
>>  src/mesa/state_tracker/st_texture.h    | 12 +++++++-
>>  4 files changed, 93 insertions(+), 8 deletions(-)
>>
>> diff --git a/src/mesa/state_tracker/st_cb_texture.c
>> b/src/mesa/state_tracker/st_cb_texture.c
>> index aa6b05f..88c4b25 100644
>> --- a/src/mesa/state_tracker/st_cb_texture.c
>> +++ b/src/mesa/state_tracker/st_cb_texture.c
>> @@ -37,6 +37,7 @@
>>  #include "main/pbo.h"
>>  #include "main/pixeltransfer.h"
>>  #include "main/texcompress.h"
>> +#include "main/texcompress_etc.h"
>>  #include "main/texgetimage.h"
>>  #include "main/teximage.h"
>>  #include "main/texobj.h"
>> @@ -207,8 +208,31 @@ st_MapTextureImage(struct gl_context *ctx,
>>     map = st_texture_image_map(st, stImage, pipeMode, x, y, slice, w, h,
>> 1,
>>                                &transfer);
>>     if (map) {
>> -      *mapOut = map;
>> -      *rowStrideOut = transfer->stride;
>> +      if (_mesa_is_format_etc2(texImage->TexFormat)) {
>> +         /* ETC isn't supported by gallium and it's represented
>
>
> Freedreno could definitely support it natively, at least for a3xx. Though it
> can cross that bridge once it gets there i suppose.
>
>
>> +          * by uncompressed formats. Only write transfers with
>> precompressed
>> +          * data are supported by ES3, which makes this really simple.
>> +          *
>> +          * Just create a temporary storage where the ETC texture will
>> +          * be stored. It will be decompressed in the Unmap function.
>> +          */
>
>
> Question: Is it possible to create a permanent map of a texture in GL?

No, it's not. OpenGL doesn't have an API for mapping textures.

>
>
>> +         unsigned z = transfer->box.z;
>
>
> Nitpick: transfer->box.z is a signed int.

In this case, it's set to slice+face, which is always a positive number.

>
>
>> +         struct st_texture_image_transfer *itransfer =
>> &stImage->transfer[z];
>> +
>> +         itransfer->temp_data =
>> +            malloc(_mesa_format_image_size(texImage->TexFormat, w, h,
>> 1));
>> +         itransfer->temp_stride =
>> +            _mesa_format_row_stride(texImage->TexFormat, w);
>> +         itransfer->map = map;
>> +
>> +         *mapOut = itransfer->temp_data;
>> +         *rowStrideOut = itransfer->temp_stride;
>> +      }
>> +      else {
>> +         /* supported mapping */
>> +         *mapOut = map;
>> +         *rowStrideOut = transfer->stride;
>> +      }
>>     }
>>     else {
>>        *mapOut = NULL;
>> @@ -225,6 +249,26 @@ st_UnmapTextureImage(struct gl_context *ctx,
>>  {
>>     struct st_context *st = st_context(ctx);
>>     struct st_texture_image *stImage  = st_texture_image(texImage);
>> +
>> +   if (_mesa_is_format_etc2(texImage->TexFormat)) {
>> +      /* Decompress the ETC texture to the mapped one. */
>> +      unsigned z = slice + stImage->base.Face;
>
>
> int
>
>
>> +      struct st_texture_image_transfer *itransfer =
>> &stImage->transfer[z];
>> +      struct pipe_transfer *transfer = itransfer->transfer;
>> +
>> +      assert(z == transfer->box.z);
>> +
>> +      _mesa_unpack_etc2_format(itransfer->map, transfer->stride,
>> +                               itransfer->temp_data,
>> itransfer->temp_stride,
>> +                               transfer->box.width, transfer->box.height,
>> +                               texImage->TexFormat);
>
>
> Is the ETC source data always an integer number of blocks?

Yes. Compressed texture uploads must always be aligned to 4x4.

>
>
>> +
>> +      free(itransfer->temp_data);
>> +      itransfer->temp_data = NULL;
>> +      itransfer->temp_stride = 0;
>> +      itransfer->map = 0;
>> +   }
>> +
>>     st_texture_image_unmap(st, stImage, slice);
>>  }
>> @@ -613,6 +657,8 @@ st_TexSubImage(struct gl_context *ctx, GLuint dims,
>>     unsigned bind;
>>     GLubyte *map;
>> +   assert(!_mesa_is_format_etc2(texImage->TexFormat));
>> +
>>     if (!st->prefer_blit_based_texture_transfer) {
>>        goto fallback;
>>     }
>> @@ -870,6 +916,8 @@ st_GetTexImage(struct gl_context * ctx,
>>     ubyte *map = NULL;
>>     boolean done = FALSE;
>> +   assert(!_mesa_is_format_etc2(texImage->TexFormat));
>> +
>>     if (!st->prefer_blit_based_texture_transfer &&
>>         !_mesa_is_format_compressed(texImage->TexFormat)) {
>>        /* Try to avoid the fallback if we're doing texture decompression
>> here */
>> @@ -1306,6 +1354,8 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint
>> dims,
>>     unsigned bind;
>>     GLint srcY0, srcY1;
>> +   assert(!_mesa_is_format_etc2(texImage->TexFormat));
>> +
>>     if (!strb || !strb->surface || !stImage->pt) {
>>        debug_printf("%s: null strb or stImage\n", __FUNCTION__);
>>        return;
>> diff --git a/src/mesa/state_tracker/st_format.c
>> b/src/mesa/state_tracker/st_format.c
>> index 409079b..ff3f494 100644
>> --- a/src/mesa/state_tracker/st_format.c
>> +++ b/src/mesa/state_tracker/st_format.c
>> @@ -402,6 +402,26 @@ st_mesa_format_to_pipe_format(mesa_format mesaFormat)
>>     case MESA_FORMAT_B8G8R8X8_SRGB:
>>        return PIPE_FORMAT_B8G8R8X8_SRGB;
>> +   /* ETC2 formats are emulated as uncompressed ones.
>> +    * The destination formats mustn't be changed, because they are also
>> +    * destination formats of the unpack/decompression function. */
>> +   case MESA_FORMAT_ETC2_RGB8:
>> +   case MESA_FORMAT_ETC2_RGBA8_EAC:
>> +   case MESA_FORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1:
>> +      return PIPE_FORMAT_R8G8B8A8_UNORM;
>> +   case MESA_FORMAT_ETC2_SRGB8:
>> +   case MESA_FORMAT_ETC2_SRGB8_ALPHA8_EAC:
>> +   case MESA_FORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:
>> +      return PIPE_FORMAT_B8G8R8A8_SRGB;
>> +   case MESA_FORMAT_ETC2_R11_EAC:
>> +      return PIPE_FORMAT_R16_UNORM;
>> +   case MESA_FORMAT_ETC2_RG11_EAC:
>> +      return PIPE_FORMAT_R16G16_UNORM;
>> +   case MESA_FORMAT_ETC2_SIGNED_R11_EAC:
>> +      return PIPE_FORMAT_R16_SNORM;
>> +   case MESA_FORMAT_ETC2_SIGNED_RG11_EAC:
>> +      return PIPE_FORMAT_R16G16_SNORM;
>> +
>>     default:
>>        return PIPE_FORMAT_NONE;
>>     }
>> @@ -781,6 +801,10 @@ test_format_conversion(void)
>>    /* test all Mesa formats */
>>     for (i = 1; i < MESA_FORMAT_COUNT; i++) {
>> +      /* ETC2 formats are translated differently, skip them. */
>> +      if (_mesa_is_format_etc2(i))
>> +         continue;
>> +
>>        enum pipe_format pf = st_mesa_format_to_pipe_format(i);
>>        if (pf != PIPE_FORMAT_NONE) {
>>           mesa_format mf = st_pipe_format_to_mesa_format(pf);
>> diff --git a/src/mesa/state_tracker/st_texture.c
>> b/src/mesa/state_tracker/st_texture.c
>> index c148821..9f57cfb 100644
>> --- a/src/mesa/state_tracker/st_texture.c
>> +++ b/src/mesa/state_tracker/st_texture.c
>> @@ -269,14 +269,15 @@ st_texture_image_map(struct st_context *st, struct
>> st_texture_image *stImage,
>>           unsigned new_size = z + 1;
>>          stImage->transfer = realloc(stImage->transfer,
>> -                                     new_size * sizeof(void*));
>> +                     new_size * sizeof(struct
>> st_texture_image_transfer));
>>           memset(&stImage->transfer[stImage->num_transfers], 0,
>> -               (new_size - stImage->num_transfers) * sizeof(void*));
>> +                (new_size - stImage->num_transfers) *
>> +                sizeof(struct st_texture_image_transfer));
>>           stImage->num_transfers = new_size;
>>        }
>> -      assert(!stImage->transfer[z]);
>> -      stImage->transfer[z] = *transfer;
>> +      assert(!stImage->transfer[z].transfer);
>> +      stImage->transfer[z].transfer = *transfer;
>>     }
>>     return map;
>>  }
>> @@ -288,7 +289,7 @@ st_texture_image_unmap(struct st_context *st,
>>  {
>>     struct pipe_context *pipe = st->pipe;
>>     struct pipe_transfer **transfer =
>> -      &stImage->transfer[slice + stImage->base.Face];
>> +      &stImage->transfer[slice + stImage->base.Face].transfer;
>>    DBG("%s\n", __FUNCTION__);
>> diff --git a/src/mesa/state_tracker/st_texture.h
>> b/src/mesa/state_tracker/st_texture.h
>> index affb568..04b886e 100644
>> --- a/src/mesa/state_tracker/st_texture.h
>> +++ b/src/mesa/state_tracker/st_texture.h
>> @@ -38,6 +38,16 @@
>>  struct pipe_resource;
>> +struct st_texture_image_transfer {
>> +   struct pipe_transfer *transfer;
>> +
>> +   /* For ETC fallback. */
>> +   GLubyte *temp_data; /**< Temporary ETC texture storage. */
>> +   unsigned temp_stride; /**< Stride of the ETC texture storage. */
>> +   GLubyte *map; /**< Saved map pointer of the uncompressed transfer. */
>> +};
>> +
>> +
>>  /**
>>   * Subclass of gl_texure_image.
>>   */
>> @@ -59,7 +69,7 @@ struct st_texture_image
>>     /* List of transfers, allocated on demand.
>>      * transfer[layer] is a mapping for that layer.
>>      */
>> -   struct pipe_transfer **transfer;
>> +   struct st_texture_image_transfer *transfer;
>
>
> Nitpick: Might want to call it texture_image_transfer to distinguish it from
> pipe_transfer where its used.

To me, it doesn't seem to make any difference in readability and
"texture_image_transfer" is too long.

Marek


More information about the mesa-dev mailing list