[Mesa-dev] [PATCH v2 2/2] st/mesa: provide GL_OES_copy_image support by caching the original ETC data

Ilia Mirkin imirkin at alum.mit.edu
Tue Jul 26 01:32:18 UTC 2016


ping

On Sat, Jul 16, 2016 at 12:21 PM, Ilia Mirkin <imirkin at 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 <imirkin at 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
>


More information about the mesa-dev mailing list