From d816a51b81f42b0aa4819a32587b4aa167e4b541 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Fri, 8 Jul 2016 02:44:57 -0400 Subject: [PATCH] st/mesa: provide GL_OES_copy_image support by caching the original ETC data MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Acked-by: Marek Olšák --- docs/GL3.txt | 2 +- docs/relnotes/12.1.0.html | 1 + src/mesa/state_tracker/st_cb_copyimage.c | 96 +++++++++++++++++++++++- src/mesa/state_tracker/st_cb_texture.c | 77 +++++++++++++------ src/mesa/state_tracker/st_extensions.c | 12 +-- src/mesa/state_tracker/st_texture.h | 7 +- 6 files changed, 156 insertions(+), 39 deletions(-) diff --git a/docs/GL3.txt b/docs/GL3.txt index 6597984323c..084c17edeab 100644 --- a/docs/GL3.txt +++ b/docs/GL3.txt @@ -257,7 +257,7 @@ GLES3.2, GLSL ES 3.2: GL_KHR_debug DONE (all drivers) GL_KHR_robustness DONE (i965) GL_KHR_texture_compression_astc_ldr DONE (i965/gen9+) - GL_OES_copy_image DONE (i965) + GL_OES_copy_image DONE (all drivers) GL_OES_draw_buffers_indexed DONE (all drivers that support GL_ARB_draw_buffers_blend) GL_OES_draw_elements_base_vertex DONE (all drivers) GL_OES_geometry_shader started (idr) diff --git a/docs/relnotes/12.1.0.html b/docs/relnotes/12.1.0.html index 23249720244..5181fa01241 100644 --- a/docs/relnotes/12.1.0.html +++ b/docs/relnotes/12.1.0.html @@ -52,6 +52,7 @@ Note: some of the new features are only available with certain drivers.
  • GL_ARB_ES3_1_compatibility on i965
  • GL_EXT_window_rectangles on nv50, nvc0
  • GL_KHR_texture_compression_astc_sliced_3d on i965
  • +
  • GL_OES_copy_image on nv50, nvc0, r600, radeonsi, softpipe, llvmpipe
  • Bug fixes

    diff --git a/src/mesa/state_tracker/st_cb_copyimage.c b/src/mesa/state_tracker/st_cb_copyimage.c index f670bd9967e..d160c8c8d30 100644 --- a/src/mesa/state_tracker/st_cb_copyimage.c +++ b/src/mesa/state_tracker/st_cb_copyimage.c @@ -532,6 +532,90 @@ copy_image(struct pipe_context *pipe, src_box); } +/* Note, the only allowable compressed format for this function is ETC */ +static void +fallback_copy_image(struct st_context *st, + struct gl_texture_image *dst_image, + struct pipe_resource *dst_res, + int dst_x, int dst_y, int dst_z, + struct gl_texture_image *src_image, + struct pipe_resource *src_res, + int src_x, int src_y, int src_z, + int src_w, int src_h) +{ + uint8_t *dst, *src; + int dst_stride, src_stride; + struct pipe_transfer *dst_transfer, *src_transfer; + unsigned line_bytes; + + bool dst_is_compressed = dst_image && _mesa_is_format_compressed(dst_image->TexFormat); + bool src_is_compressed = src_image && _mesa_is_format_compressed(src_image->TexFormat); + + unsigned dst_w = src_w; + unsigned dst_h = src_h; + unsigned lines = src_h; + + if (src_is_compressed && !dst_is_compressed) { + dst_w = DIV_ROUND_UP(dst_w, 4); + dst_h = DIV_ROUND_UP(dst_h, 4); + } else if (!src_is_compressed && dst_is_compressed) { + dst_w *= 4; + dst_h *= 4; + } + if (src_is_compressed) { + lines = DIV_ROUND_UP(lines, 4); + } + + if (src_image) + line_bytes = _mesa_format_row_stride(src_image->TexFormat, src_w); + else + line_bytes = _mesa_format_row_stride(dst_image->TexFormat, dst_w); + + if (dst_image) { + st->ctx->Driver.MapTextureImage( + st->ctx, dst_image, dst_z, + dst_x, dst_y, dst_w, dst_h, + GL_MAP_WRITE_BIT, &dst, &dst_stride); + } else { + dst = pipe_transfer_map(st->pipe, dst_res, 0, dst_z, + PIPE_TRANSFER_WRITE, + dst_x, dst_y, dst_w, dst_h, + &dst_transfer); + dst_stride = dst_transfer->stride; + } + + if (src_image) { + st->ctx->Driver.MapTextureImage( + st->ctx, src_image, src_z, + src_x, src_y, src_w, src_h, + GL_MAP_READ_BIT, &src, &src_stride); + } else { + src = pipe_transfer_map(st->pipe, src_res, 0, src_z, + PIPE_TRANSFER_READ, + src_x, src_y, src_w, src_h, + &src_transfer); + src_stride = src_transfer->stride; + } + + for (int y = 0; y < lines; y++) { + memcpy(dst, src, line_bytes); + dst += dst_stride; + src += src_stride; + } + + if (dst_image) { + st->ctx->Driver.UnmapTextureImage(st->ctx, dst_image, dst_z); + } else { + pipe_transfer_unmap(st->pipe, dst_transfer); + } + + if (src_image) { + st->ctx->Driver.UnmapTextureImage(st->ctx, src_image, src_z); + } else { + pipe_transfer_unmap(st->pipe, src_transfer); + } +} + static void st_CopyImageSubData(struct gl_context *ctx, struct gl_texture_image *src_image, @@ -547,6 +631,7 @@ st_CopyImageSubData(struct gl_context *ctx, struct pipe_resource *src_res, *dst_res; struct pipe_box box; int src_level, dst_level; + int orig_src_z = src_z, orig_dst_z = dst_z; st_flush_bitmap_cache(st); st_invalidate_readpix_cache(st); @@ -583,8 +668,15 @@ st_CopyImageSubData(struct gl_context *ctx, u_box_2d_zslice(src_x, src_y, src_z, src_width, src_height, &box); - copy_image(pipe, dst_res, dst_level, dst_x, dst_y, dst_z, - src_res, src_level, &box); + if ((src_image && st_etc_fallback(st, src_image)) || + (dst_image && st_etc_fallback(st, dst_image))) { + fallback_copy_image(st, dst_image, dst_res, dst_x, dst_y, orig_dst_z, + src_image, src_res, src_x, src_y, orig_src_z, + src_width, src_height); + } else { + copy_image(pipe, dst_res, dst_level, dst_x, dst_y, dst_z, + src_res, src_level, &box); + } } void 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); } } diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c index d0e7d3840f5..1f53bdfd365 100644 --- a/src/mesa/state_tracker/st_extensions.c +++ b/src/mesa/state_tracker/st_extensions.c @@ -582,6 +582,7 @@ void st_init_extensions(struct pipe_screen *screen, { o(ARB_color_buffer_float), PIPE_CAP_VERTEX_COLOR_UNCLAMPED }, { o(ARB_conditional_render_inverted), PIPE_CAP_CONDITIONAL_RENDER_INVERTED }, { o(ARB_copy_image), PIPE_CAP_COPY_BETWEEN_COMPRESSED_AND_PLAIN_FORMATS }, + { o(OES_copy_image), PIPE_CAP_COPY_BETWEEN_COMPRESSED_AND_PLAIN_FORMATS }, { o(ARB_cull_distance), PIPE_CAP_CULL_DISTANCE }, { o(ARB_depth_clamp), PIPE_CAP_DEPTH_CLIP_DISABLE }, { o(ARB_depth_texture), PIPE_CAP_TEXTURE_SHADOW_MAP }, @@ -955,17 +956,6 @@ void st_init_extensions(struct pipe_screen *screen, extensions->OES_sample_variables = extensions->ARB_sample_shading && extensions->ARB_gpu_shader5; - /* If we don't have native ETC2 support, we don't keep track of the - * original ETC2 data. This is necessary to be able to copy images between - * compatible view classes. - */ - if (extensions->ARB_copy_image && screen->is_format_supported( - screen, PIPE_FORMAT_ETC2_RGB8, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW)) { - extensions->OES_copy_image = GL_TRUE; - } - /* Maximum sample count. */ { enum pipe_format color_formats[] = { diff --git a/src/mesa/state_tracker/st_texture.h b/src/mesa/state_tracker/st_texture.h index d5e828189ef..b2ddc14ddfc 100644 --- a/src/mesa/state_tracker/st_texture.h +++ b/src/mesa/state_tracker/st_texture.h @@ -65,7 +65,12 @@ struct st_texture_image */ struct st_texture_image_transfer *transfer; unsigned num_transfers; -}; + + /* For ETC images, keep track of the original data. This is necessary for + * mapping/unmapping, as well as image copies. + */ + GLubyte *etc_data; + }; /** -- 2.30.2