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 <imir...@alum.mit.edu> --- This passes the ETC-related dEQP tests. 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 | 87 +++++++++++++++++++---------- src/mesa/state_tracker/st_extensions.c | 12 +--- src/mesa/state_tracker/st_texture.h | 10 +++- 6 files changed, 164 insertions(+), 44 deletions(-) diff --git a/docs/GL3.txt b/docs/GL3.txt index ce34869..6da5225 100644 --- a/docs/GL3.txt +++ b/docs/GL3.txt @@ -255,7 +255,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 096f551..abdd83af 100644 --- a/docs/relnotes/12.1.0.html +++ b/docs/relnotes/12.1.0.html @@ -47,6 +47,7 @@ Note: some of the new features are only available with certain drivers. <li>GL_ARB_shader_group_vote on nvc0</li> <li>GL_ARB_ES3_1_compatibility on i965</li> <li>GL_EXT_window_rectangles on nv50, nvc0</li> +<li>GL_OES_copy_image on nv50, nvc0, r600, radeonsi, softpipe, llvmpipe</li> </ul> <h2>Bug fixes</h2> diff --git a/src/mesa/state_tracker/st_cb_copyimage.c b/src/mesa/state_tracker/st_cb_copyimage.c index f670bd9..d160c8c 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 7852d45..bf370ca 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -187,15 +187,40 @@ 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; + } } -static void -etc_fallback(struct st_context *st, struct gl_texture_image *texImage) +bool +st_etc_fallback(struct st_context *st, struct gl_texture_image *texImage) { return (_mesa_is_format_etc2(texImage->TexFormat) && !st->has_etc2) || (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, @@ -221,25 +246,24 @@ st_MapTextureImage(struct gl_context *ctx, map = st_texture_image_map(st, stImage, pipeMode, x, y, slice, w, h, 1, &transfer); if (map) { - if (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. + if (st_etc_fallback(st, texImage)) { + /* 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 */ @@ -263,7 +287,7 @@ st_UnmapTextureImage(struct gl_context *ctx, struct st_context *st = st_context(ctx); struct st_texture_image *stImage = st_texture_image(texImage); - if (etc_fallback(st, texImage)) { + if (st_etc_fallback(st, texImage)) { /* Decompress the ETC texture to the mapped one. */ unsigned z = slice + stImage->base.Face; struct st_texture_image_transfer *itransfer = &stImage->transfer[z]; @@ -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 && @@ -1622,7 +1649,7 @@ st_CompressedTexSubImage(struct gl_context *ctx, GLuint dims, if (!_mesa_is_bufferobj(ctx->Unpack.BufferObj)) goto fallback; - if (etc_fallback(st, texImage)) { + if (st_etc_fallback(st, texImage)) { /* ETC isn't supported and is represented by uncompressed formats. */ goto fallback; } @@ -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 4033452..493db12 100644 --- a/src/mesa/state_tracker/st_extensions.c +++ b/src/mesa/state_tracker/st_extensions.c @@ -579,6 +579,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 }, @@ -951,17 +952,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 ae9e2b4..b2ddc14 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; + }; /** @@ -245,4 +250,7 @@ st_texture_release_all_sampler_views(struct st_context *st, void st_texture_free_sampler_views(struct st_texture_object *stObj); +bool +st_etc_fallback(struct st_context *st, struct gl_texture_image *texImage); + #endif -- 2.7.3 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev