diff options
author | Ilia Mirkin <[email protected]> | 2016-07-08 02:44:57 -0400 |
---|---|---|
committer | Ilia Mirkin <[email protected]> | 2016-08-12 20:21:08 -0400 |
commit | d816a51b81f42b0aa4819a32587b4aa167e4b541 (patch) | |
tree | a8a69c2e756c2d5e1925d3f2de62fa64bc937e8f /src/mesa/state_tracker/st_cb_texture.c | |
parent | 7727e6f67c47ab0a36d5646092ee89852523cad8 (diff) |
st/mesa: provide GL_OES_copy_image support by caching the original ETC data
The additional provision of GL_OES_copy_image is that it work for ETC.
However many desktop GPUs don't have native ETC support, so st/mesa does
the decoding by hand. Instead of discarding the compressed data, keep it
around in CPU memory. Use it when performing image copies.
Signed-off-by: Ilia Mirkin <[email protected]>
Acked-by: Marek Olšák <[email protected]>
Diffstat (limited to 'src/mesa/state_tracker/st_cb_texture.c')
-rw-r--r-- | src/mesa/state_tracker/st_cb_texture.c | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index 86702615607..c2f5fdc031a 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -187,6 +187,11 @@ st_FreeTextureImageBuffer(struct gl_context *ctx, free(stImage->transfer); stImage->transfer = NULL; stImage->num_transfers = 0; + + if (stImage->etc_data) { + free(stImage->etc_data); + stImage->etc_data = NULL; + } } bool @@ -196,6 +201,26 @@ st_etc_fallback(struct st_context *st, struct gl_texture_image *texImage) (texImage->TexFormat == MESA_FORMAT_ETC1_RGB8 && !st->has_etc1); } +static void +etc_fallback_allocate(struct st_context *st, struct st_texture_image *stImage) +{ + struct gl_texture_image *texImage = &stImage->base; + + if (!st_etc_fallback(st, texImage)) + return; + + if (stImage->etc_data) + free(stImage->etc_data); + + unsigned data_size = _mesa_format_image_size(texImage->TexFormat, + texImage->Width2, + texImage->Height2, + texImage->Depth2); + + stImage->etc_data = + malloc(data_size * _mesa_num_tex_faces(texImage->TexObject->Target)); +} + /** called via ctx->Driver.MapTextureImage() */ static void st_MapTextureImage(struct gl_context *ctx, @@ -222,24 +247,23 @@ st_MapTextureImage(struct gl_context *ctx, &transfer); if (map) { if (st_etc_fallback(st, texImage)) { - /* 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. + /* ETC isn't supported by all gallium drivers, where it's represented + * by uncompressed formats. We store the compressed data (as it's + * needed for image copies in OES_copy_image), and decompress as + * necessary in Unmap. * - * Just create a temporary storage where the ETC texture will - * be stored. It will be decompressed in the Unmap function. + * Note: all ETC1/ETC2 formats have 4x4 block sizes. */ 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); + unsigned bytes = _mesa_get_format_bytes(texImage->TexFormat); + unsigned stride = *rowStrideOut = itransfer->temp_stride = + _mesa_format_row_stride(texImage->TexFormat, texImage->Width2); + *mapOut = itransfer->temp_data = + stImage->etc_data + ((x / 4) * bytes + (y / 4) * stride) + + z * stride * texImage->Height2 / 4; itransfer->map = map; - - *mapOut = itransfer->temp_data; - *rowStrideOut = itransfer->temp_stride; } else { /* supported mapping */ @@ -271,20 +295,21 @@ st_UnmapTextureImage(struct gl_context *ctx, assert(z == transfer->box.z); - if (texImage->TexFormat == MESA_FORMAT_ETC1_RGB8) { - _mesa_etc1_unpack_rgba8888(itransfer->map, transfer->stride, - itransfer->temp_data, - itransfer->temp_stride, - transfer->box.width, transfer->box.height); - } - else { - _mesa_unpack_etc2_format(itransfer->map, transfer->stride, - itransfer->temp_data, itransfer->temp_stride, - transfer->box.width, transfer->box.height, - texImage->TexFormat); + if (transfer->usage & PIPE_TRANSFER_WRITE) { + if (texImage->TexFormat == MESA_FORMAT_ETC1_RGB8) { + _mesa_etc1_unpack_rgba8888(itransfer->map, transfer->stride, + itransfer->temp_data, + itransfer->temp_stride, + transfer->box.width, transfer->box.height); + } + else { + _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; @@ -572,6 +597,8 @@ st_AllocTextureImageBuffer(struct gl_context *ctx, assert(!stImage->pt); /* xxx this might be wrong */ + etc_fallback_allocate(st, stImage); + /* Look if the parent texture object has space for this image */ if (stObj->pt && level <= stObj->pt->last_level && @@ -2680,6 +2707,8 @@ st_AllocTextureStorage(struct gl_context *ctx, struct st_texture_image *stImage = st_texture_image(texObj->Image[face][level]); pipe_resource_reference(&stImage->pt, stObj->pt); + + etc_fallback_allocate(st, stImage); } } |