From 463b0ea1f6762b7e0536cfadc4e384840af3e8e0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sat, 2 Aug 2014 20:31:07 +0200 Subject: [PATCH] st/mesa: add support for ETC2 formats 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 c4b2107ba6e..62075c67463 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 + * 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. + */ + unsigned z = transfer->box.z; + 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; + 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); + + 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; } @@ -872,6 +918,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 */ @@ -1308,6 +1356,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 409079bd453..ff3f494f39f 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 c1488214220..9f57cfb3d96 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 affb5681264..04b886ee39f 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; unsigned num_transfers; }; -- 2.30.2