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).
This commit is contained in:
Marek Olšák
2014-08-02 20:31:07 +02:00
parent ddc8003c61
commit 463b0ea1f6
4 changed files with 93 additions and 8 deletions
+52 -2
View File
@@ -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;
+24
View File
@@ -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);
+6 -5
View File
@@ -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__);
+11 -1
View File
@@ -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;
};