ping
On Sat, Jul 16, 2016 at 12:21 PM, Ilia Mirkin <imir...@alum.mit.edu> wrote: > 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> > --- > 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 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 54f338f..8db11ed 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 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 d5e8281..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; > + }; > > > /** > -- > 2.7.3 > _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev