summaryrefslogtreecommitdiffstats
path: root/src/mesa/state_tracker/st_cb_texture.c
diff options
context:
space:
mode:
authorIlia Mirkin <[email protected]>2016-07-08 02:44:57 -0400
committerIlia Mirkin <[email protected]>2016-08-12 20:21:08 -0400
commitd816a51b81f42b0aa4819a32587b4aa167e4b541 (patch)
treea8a69c2e756c2d5e1925d3f2de62fa64bc937e8f /src/mesa/state_tracker/st_cb_texture.c
parent7727e6f67c47ab0a36d5646092ee89852523cad8 (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.c77
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);
}
}