[Mesa-dev] [PATCH 3/3] st/mesa: implement ARB_copy_image

Brian Paul brianp at vmware.com
Mon Oct 26 19:32:06 PDT 2015


Looks good to me.  Yeah, it is kind of crazy.  I think softpipe/llvmpipe 
just need one of my previous patches, plus minor updates.  I'll take 
care of that.

Just one minor nit below.

Oh, and you could probably mention support for GL_ARB_copy_image in the 
release notes file and GL3.txt.

Reviewed-by: Brian Paul <brianp at vmware.com>


On 10/25/2015 11:25 AM, Marek Olšák wrote:
> From: Marek Olšák <marek.olsak at amd.com>
>
> I wonder if the craziness was worth it.
> ---
>   src/mesa/Makefile.sources                |   2 +
>   src/mesa/state_tracker/st_cb_copyimage.c | 609 +++++++++++++++++++++++++++++++
>   src/mesa/state_tracker/st_cb_copyimage.h |  33 ++
>   src/mesa/state_tracker/st_cb_texture.c   |  51 ---
>   src/mesa/state_tracker/st_context.c      |   2 +
>   src/mesa/state_tracker/st_extensions.c   |   1 +
>   6 files changed, 647 insertions(+), 51 deletions(-)
>   create mode 100644 src/mesa/state_tracker/st_cb_copyimage.c
>   create mode 100644 src/mesa/state_tracker/st_cb_copyimage.h
>
> diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources
> index 4bcaa62..de0e330 100644
> --- a/src/mesa/Makefile.sources
> +++ b/src/mesa/Makefile.sources
> @@ -423,6 +423,8 @@ STATETRACKER_FILES = \
>   	state_tracker/st_cb_clear.h \
>   	state_tracker/st_cb_condrender.c \
>   	state_tracker/st_cb_condrender.h \
> +	state_tracker/st_cb_copyimage.c \
> +	state_tracker/st_cb_copyimage.h \
>   	state_tracker/st_cb_drawpixels.c \
>   	state_tracker/st_cb_drawpixels.h \
>   	state_tracker/st_cb_drawpixels_shader.c \
> diff --git a/src/mesa/state_tracker/st_cb_copyimage.c b/src/mesa/state_tracker/st_cb_copyimage.c
> new file mode 100644
> index 0000000..1740aaf
> --- /dev/null
> +++ b/src/mesa/state_tracker/st_cb_copyimage.c
> @@ -0,0 +1,609 @@
> +/*
> + * Copyright 2015 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * on the rights to use, copy, modify, merge, publish, distribute, sub
> + * license, and/or sell copies of the Software, and to permit persons to whom
> + * the Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +
> +#include "state_tracker/st_context.h"
> +#include "state_tracker/st_cb_copyimage.h"
> +#include "state_tracker/st_cb_fbo.h"
> +#include "state_tracker/st_texture.h"
> +
> +#include "util/u_box.h"
> +#include "util/u_format.h"
> +#include "util/u_inlines.h"
> +
> +
> +/**
> + * Return an equivalent canonical format without "X" channels.
> + *
> + * Copying between incompatible formats is easier when the format is
> + * canonicalized, meaning that it is in a standard form.
> + *
> + * The returned format has the same component sizes and swizzles as
> + * the source format, the type is changed to UINT or UNORM, depending on
> + * which one has the most swizzle combinations in their group.
> + *
> + * If it's not an array format, return a memcpy-equivalent array format.
> + *
> + * The key feature is that swizzled versions of formats of the same
> + * component size always return the same component type.
> + *
> + * X returns A.
> + * Luminance, intensity, alpha, depth, stencil, and 8-bit and 16-bit packed
> + * formats are not supported. (same as ARB_copy_image)
> + */
> +static enum pipe_format
> +get_canonical_format(enum pipe_format format)
> +{
> +   const struct util_format_description *desc =
> +      util_format_description(format);
> +
> +   /* Packed formats. Return the equivalent array format. */
> +   if (format == PIPE_FORMAT_R11G11B10_FLOAT ||
> +       format == PIPE_FORMAT_R9G9B9E5_FLOAT)
> +      return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT);
> +
> +   if (desc->nr_channels == 4 &&
> +       desc->channel[0].size == 10 &&
> +       desc->channel[1].size == 10 &&
> +       desc->channel[2].size == 10 &&
> +       desc->channel[3].size == 2) {
> +      if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
> +          desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_Y &&
> +          desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_Z)
> +         return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT);
> +
> +      return PIPE_FORMAT_NONE;
> +   }
> +
> +#define RETURN_FOR_SWIZZLE1(x, format) \
> +   if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_##x) \
> +      return format
> +
> +#define RETURN_FOR_SWIZZLE2(x, y, format) \
> +   if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_##x && \
> +       desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_##y) \
> +      return format
> +
> +#define RETURN_FOR_SWIZZLE3(x, y, z, format) \
> +   if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_##x && \
> +       desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_##y && \
> +       desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_##z) \
> +      return format
> +
> +#define RETURN_FOR_SWIZZLE4(x, y, z, w, format) \
> +   if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_##x && \
> +       desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_##y && \
> +       desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_##z && \
> +       desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_##w) \
> +      return format
> +
> +   /* Array formats. */
> +   if (desc->is_array) {
> +      switch (desc->nr_channels) {
> +      case 1:
> +         switch (desc->channel[0].size) {
> +         case 8:
> +            RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R8_UINT);
> +            break;
> +
> +         case 16:
> +            RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R16_UINT);
> +            break;
> +
> +         case 32:
> +            RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R32_UINT);
> +            break;
> +         }
> +         break;
> +
> +      case 2:
> +         switch (desc->channel[0].size) {
> +         case 8:
> +            /* All formats in each group must be of the same type.
> +             * We can't use UINT for R8G8 while using UNORM for G8R8.
> +             */
> +            RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R8G8_UNORM);
> +            RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G8R8_UNORM);
> +            break;
> +
> +         case 16:
> +            RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R16G16_UNORM);
> +            RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G16R16_UNORM);
> +            break;
> +
> +         case 32:
> +            RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R32G32_UINT);
> +            break;
> +         }
> +         break;
> +
> +      case 3:
> +         switch (desc->channel[0].size) {
> +         case 8:
> +            RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R8G8B8_UINT);
> +            break;
> +
> +         case 16:
> +            RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R16G16B16_UINT);
> +            break;
> +
> +         case 32:
> +            RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R32G32B32_UINT);
> +            break;
> +         }
> +         break;
> +
> +      case 4:
> +         switch (desc->channel[0].size) {
> +         case 8:
> +            RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R8G8B8A8_UNORM);
> +            RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R8G8B8A8_UNORM);
> +            RETURN_FOR_SWIZZLE4(Z, Y, X, W, PIPE_FORMAT_B8G8R8A8_UNORM);
> +            RETURN_FOR_SWIZZLE4(Z, Y, X, 1, PIPE_FORMAT_B8G8R8A8_UNORM);
> +            RETURN_FOR_SWIZZLE4(W, Z, Y, X, PIPE_FORMAT_A8B8G8R8_UNORM);
> +            RETURN_FOR_SWIZZLE4(1, Z, Y, X, PIPE_FORMAT_A8B8G8R8_UNORM);
> +            RETURN_FOR_SWIZZLE4(W, X, Y, Z, PIPE_FORMAT_A8R8G8B8_UNORM);
> +            RETURN_FOR_SWIZZLE4(1, X, Y, Z, PIPE_FORMAT_A8R8G8B8_UNORM);
> +            break;
> +
> +         case 16:
> +            RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R16G16B16A16_UINT);
> +            RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R16G16B16A16_UINT);
> +            break;
> +
> +         case 32:
> +            RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R32G32B32A32_UINT);
> +            RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R32G32B32A32_UINT);
> +            break;
> +         }
> +      }
> +
> +      unreachable("unknown array format");
> +      return PIPE_FORMAT_NONE;
> +   }
> +
> +   unreachable("unknown packed format");
> +   return PIPE_FORMAT_NONE;
> +}
> +
> +/**
> + * Return true if the swizzle is XYZW in case of a 4-channel format,
> + * XY in case of a 2-channel format, or X in case of a 1-channel format.
> + */
> +static bool
> +has_identity_swizzle(const struct util_format_description *desc)
> +{
> +   int i;
> +
> +   for (i = 0; i < desc->nr_channels; i++)
> +      if (desc->swizzle[i] != UTIL_FORMAT_SWIZZLE_X + i)
> +         return false;
> +
> +   return true;
> +}
> +
> +/**
> + * Return a canonical format for the given bits and channel size.
> + */
> +static enum pipe_format
> +canonical_format_from_bits(unsigned bits, unsigned channel_size)
> +{
> +   switch (bits) {
> +   case 8:
> +      if (channel_size == 8)
> +         return get_canonical_format(PIPE_FORMAT_R8_UINT);
> +      break;
> +
> +   case 16:
> +      if (channel_size == 8)
> +         return get_canonical_format(PIPE_FORMAT_R8G8_UINT);
> +      if (channel_size == 16)
> +         return get_canonical_format(PIPE_FORMAT_R16_UINT);
> +      break;
> +
> +   case 32:
> +      if (channel_size == 8)
> +         return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT);
> +      if (channel_size == 16)
> +         return get_canonical_format(PIPE_FORMAT_R16G16_UINT);
> +      if (channel_size == 32)
> +         return get_canonical_format(PIPE_FORMAT_R32_UINT);
> +      break;
> +
> +   case 64:
> +      if (channel_size == 16)
> +         return get_canonical_format(PIPE_FORMAT_R16G16B16A16_UINT);
> +      if (channel_size == 32)
> +         return get_canonical_format(PIPE_FORMAT_R32G32_UINT);
> +      break;
> +
> +   case 128:
> +      if (channel_size == 32)
> +         return get_canonical_format(PIPE_FORMAT_R32G32B32A32_UINT);
> +      break;
> +   }
> +
> +   unreachable("impossible format");
> +   return PIPE_FORMAT_NONE;
> +}
> +
> +static void
> +blit(struct pipe_context *pipe,
> +     struct pipe_resource *dst,
> +     enum pipe_format dst_format,
> +     unsigned dst_level,
> +     unsigned dstx, unsigned dsty, unsigned dstz,
> +     struct pipe_resource *src,
> +     enum pipe_format src_format,
> +     unsigned src_level,
> +     const struct pipe_box *src_box)
> +{
> +   struct pipe_blit_info blit = {{0}};
> +
> +   blit.src.resource = src;
> +   blit.dst.resource = dst;
> +   blit.src.format = src_format;
> +   blit.dst.format = dst_format;
> +   blit.src.level = src_level;
> +   blit.dst.level = dst_level;
> +   blit.src.box = *src_box;
> +   u_box_3d(dstx, dsty, dstz, src_box->width, src_box->height,
> +            src_box->depth, &blit.dst.box);
> +   blit.mask = PIPE_MASK_RGBA;
> +   blit.filter = PIPE_TEX_FILTER_NEAREST;
> +
> +   pipe->blit(pipe, &blit);
> +}
> +
> +static void
> +swizzled_copy(struct pipe_context *pipe,
> +              struct pipe_resource *dst,
> +              unsigned dst_level,
> +              unsigned dstx, unsigned dsty, unsigned dstz,
> +              struct pipe_resource *src,
> +              unsigned src_level,
> +              const struct pipe_box *src_box)
> +{
> +   const struct util_format_description *src_desc, *dst_desc;
> +   unsigned bits;
> +   enum pipe_format blit_src_format, blit_dst_format;
> +
> +   /* Get equivalent canonical formats. Those are always array formats and
> +    * copying between compatible canonical formats behaves either like
> +    * memcpy or like swizzled memcpy. The idea is that we won't have to care
> +    * about the channel type from this point on.
> +    * Only the swizzle and channel size.
> +    */
> +   blit_src_format = get_canonical_format(src->format);
> +   blit_dst_format = get_canonical_format(dst->format);
> +
> +   assert(blit_src_format != PIPE_FORMAT_NONE);
> +   assert(blit_dst_format != PIPE_FORMAT_NONE);
> +
> +   src_desc = util_format_description(blit_src_format);
> +   dst_desc = util_format_description(blit_dst_format);
> +
> +   assert(src_desc->block.bits == dst_desc->block.bits);
> +   bits = src_desc->block.bits;
> +
> +   if (dst_desc->channel[0].size == src_desc->channel[0].size) {
> +      /* Only the swizzle is different, which means we can just blit,
> +       * e.g. RGBA -> BGRA.
> +       */
> +   } else if (has_identity_swizzle(src_desc)) {
> +      /* Src is unswizzled and dst can be swizzled, so src is typecast
> +       * to an equivalent dst-compatible format.
> +       * e.g. R32 -> BGRA8 is realized as RGBA8 -> BGRA8
> +       */
> +      blit_src_format =
> +         canonical_format_from_bits(bits, dst_desc->channel[0].size);
> +   } else if (has_identity_swizzle(dst_desc)) {
> +      /* Dst is unswizzled and src can be swizzled, so dst is typecast
> +       * to an equivalent src-compatible format.
> +       * e.g. BGRA8 -> R32 is realized as BGRA8 -> RGBA8
> +       */
> +      blit_dst_format =
> +         canonical_format_from_bits(bits, src_desc->channel[0].size);
> +   } else {
> +      unreachable("This should have been handled by handle_complex_copy.");
> +      return;
> +   }
> +
> +   blit(pipe, dst, blit_dst_format, dst_level, dstx, dsty, dstz,
> +        src, blit_src_format, src_level, src_box);
> +}
> +
> +static bool
> +same_size_and_swizzle(const struct util_format_description *d1,
> +                      const struct util_format_description *d2)
> +{
> +   int i;
> +
> +   if (d1->layout != d2->layout ||
> +       d1->nr_channels != d2->nr_channels ||
> +       d1->is_array != d2->is_array)
> +      return false;
> +
> +   for (i = 0; i < d1->nr_channels; i++) {
> +      if (d1->channel[i].size != d2->channel[i].size)
> +         return false;
> +
> +      if (d1->swizzle[i] <= UTIL_FORMAT_SWIZZLE_W &&
> +          d2->swizzle[i] <= UTIL_FORMAT_SWIZZLE_W &&
> +          d1->swizzle[i] != d2->swizzle[i])
> +         return false;
> +   }
> +
> +   return true;
> +}
> +
> +static bool
> +is_bgr10_a2_variant(const struct util_format_description *desc)
> +{
> +   return desc->nr_channels == 4 &&
> +          desc->channel[0].size == 10 &&
> +          desc->channel[1].size == 10 &&
> +          desc->channel[2].size == 10 &&
> +          desc->channel[3].size == 2 &&
> +          desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_Z &&
> +          desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_Y &&
> +          desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X;
> +}
> +
> +static bool
> +is_rgb10_a2_variant(const struct util_format_description *desc)
> +{
> +   return desc->nr_channels == 4 &&
> +          desc->channel[0].size == 10 &&
> +          desc->channel[1].size == 10 &&
> +          desc->channel[2].size == 10 &&
> +          desc->channel[3].size == 2 &&
> +          desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
> +          desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_Y &&
> +          desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_Z;
> +}
> +
> +static struct pipe_resource *
> +create_texture(struct pipe_screen *screen, enum pipe_format format,
> +               unsigned width, unsigned height, unsigned depth)
> +{
> +   struct pipe_resource templ;
> +
> +   memset(&templ, 0, sizeof(templ));
> +   templ.format = format;
> +   templ.width0 = width;
> +   templ.height0 = height;
> +   templ.depth0 = 1;
> +   templ.array_size = depth;
> +   templ.usage = PIPE_USAGE_DEFAULT;
> +   templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
> +
> +   if (depth > 1)
> +           templ.target = PIPE_TEXTURE_2D_ARRAY;
> +   else
> +           templ.target = PIPE_TEXTURE_2D;

Too much indentation for those two clauses.


> +
> +   return screen->resource_create(screen, &templ);
> +}
> +
> +/**
> + * Handle complex format conversions using 2 blits with a temporary texture
> + * in between, e.g. blitting from B10G10R10A2 to G16R16.
> + *
> + * This example is implemented this way:
> + * 1) First, blit from B10G10R10A2 to R10G10B10A2, which is canonical, so it
> + *    can be reinterpreted as a different canonical format of the same bpp,
> + *    such as R16G16. This blit only swaps R and B 10-bit components.
> + * 2) Finnaly, blit the result, which is R10G10B10A2, as R16G16 to G16R16.
> + *    This blit only swaps R and G 16-bit components.
> + */
> +static bool
> +handle_complex_copy(struct pipe_context *pipe,
> +                    struct pipe_resource *dst,
> +                    unsigned dst_level,
> +                    unsigned dstx, unsigned dsty, unsigned dstz,
> +                    struct pipe_resource *src,
> +                    unsigned src_level,
> +                    const struct pipe_box *src_box,
> +                    enum pipe_format noncanon_format,
> +                    enum pipe_format canon_format)
> +{
> +   struct pipe_box temp_box;
> +   struct pipe_resource *temp = NULL;
> +   const struct util_format_description *src_desc, *dst_desc;
> +   const struct util_format_description *canon_desc, *noncanon_desc;
> +   bool src_is_canon;
> +   bool src_is_noncanon;
> +   bool dst_is_canon;
> +   bool dst_is_noncanon;
> +
> +   src_desc = util_format_description(src->format);
> +   dst_desc = util_format_description(dst->format);
> +   canon_desc = util_format_description(canon_format);
> +   noncanon_desc = util_format_description(noncanon_format);
> +
> +   src_is_canon = same_size_and_swizzle(src_desc, canon_desc);
> +   dst_is_canon = same_size_and_swizzle(dst_desc, canon_desc);
> +   src_is_noncanon = same_size_and_swizzle(src_desc, noncanon_desc);
> +   dst_is_noncanon = same_size_and_swizzle(dst_desc, noncanon_desc);
> +
> +   src_is_canon = is_rgb10_a2_variant(src_desc);
> +   dst_is_canon = is_rgb10_a2_variant(dst_desc);
> +   src_is_noncanon = is_bgr10_a2_variant(src_desc);
> +   dst_is_noncanon = is_bgr10_a2_variant(dst_desc);
> +
> +   if (src_is_noncanon) {
> +      /* Simple case - only types differ (e.g. UNORM and UINT). */
> +      if (dst_is_noncanon) {
> +         blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, src,
> +              noncanon_format, src_level, src_box);
> +         return true;
> +      }
> +
> +      /* Simple case - only types and swizzles differ. */
> +      if (dst_is_canon) {
> +         blit(pipe, dst, canon_format, dst_level, dstx, dsty, dstz, src,
> +              noncanon_format, src_level, src_box);
> +         return true;
> +      }
> +
> +      /* Use the temporary texture. Src is converted to a canonical format,
> +       * then proceed the generic swizzled_copy.
> +       */
> +      temp = create_texture(pipe->screen, canon_format, src_box->width,
> +                            src_box->height, src_box->depth);
> +
> +      u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
> +               &temp_box);
> +
> +      blit(pipe, temp, canon_format, 0, 0, 0, 0, src, noncanon_format,
> +           src_level, src_box);
> +      swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, temp, 0,
> +                    &temp_box);
> +      pipe_resource_reference(&temp, NULL);
> +      return true;
> +   }
> +
> +   if (dst_is_noncanon) {
> +      /* Simple case - only types and swizzles differ. */
> +      if (src_is_canon) {
> +         blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, src,
> +              canon_format, src_level, src_box);
> +         return true;
> +      }
> +
> +      /* Use the temporary texture. First, use the generic copy, but use
> +       * a canonical format in the destination. Then convert */
> +      temp = create_texture(pipe->screen, canon_format, src_box->width,
> +                            src_box->height, src_box->depth);
> +
> +      u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
> +               &temp_box);
> +
> +      swizzled_copy(pipe, temp, 0, 0, 0, 0, src, src_level, src_box);
> +      blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, temp,
> +           canon_format, 0, &temp_box);
> +      pipe_resource_reference(&temp, NULL);
> +      return true;
> +   }
> +
> +   return false;
> +}
> +
> +static void
> +copy_image(struct pipe_context *pipe,
> +           struct pipe_resource *dst,
> +           unsigned dst_level,
> +           unsigned dstx, unsigned dsty, unsigned dstz,
> +           struct pipe_resource *src,
> +           unsigned src_level,
> +           const struct pipe_box *src_box)
> +{
> +   if (src->format == dst->format ||
> +       util_format_is_compressed(src->format) ||
> +       util_format_is_compressed(dst->format)) {
> +      pipe->resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
> +                                 src, src_level, src_box);
> +      return;
> +   }
> +
> +   /* Copying to/from B10G10R10*2 needs 2 blits with R10G10B10A2
> +    * as a temporary texture in between.
> +    */
> +   if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src,
> +                           src_level, src_box, PIPE_FORMAT_B10G10R10A2_UINT,
> +                           PIPE_FORMAT_R10G10B10A2_UINT))
> +      return;
> +
> +   /* Copying to/from G8R8 needs 2 blits with R8G8 as a temporary texture
> +    * in between.
> +    */
> +   if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src,
> +                           src_level, src_box, PIPE_FORMAT_G8R8_UNORM,
> +                           PIPE_FORMAT_R8G8_UNORM))
> +      return;
> +
> +   /* Copying to/from G16R16 needs 2 blits with R16G16 as a temporary texture
> +    * in between.
> +    */
> +   if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src,
> +                           src_level, src_box, PIPE_FORMAT_G16R16_UNORM,
> +                           PIPE_FORMAT_R16G16_UNORM))
> +      return;
> +
> +   /* Only allow non-identity swizzling on RGBA8 formats. */
> +
> +   /* Simple copy, memcpy with swizzling, no format conversion. */
> +   swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, src, src_level,
> +                 src_box);
> +}
> +
> +static void
> +st_CopyImageSubData(struct gl_context *ctx,
> +                    struct gl_texture_image *src_image,
> +                    struct gl_renderbuffer *src_renderbuffer,
> +                    int src_x, int src_y, int src_z,
> +                    struct gl_texture_image *dst_image,
> +                    struct gl_renderbuffer *dst_renderbuffer,
> +                    int dst_x, int dst_y, int dst_z,
> +                    int src_width, int src_height)
> +{
> +   struct st_context *st = st_context(ctx);
> +   struct pipe_context *pipe = st->pipe;
> +   struct pipe_resource *src_res, *dst_res;
> +   struct pipe_box box;
> +   int src_level, dst_level;
> +
> +   if (src_image) {
> +      struct st_texture_image *src = st_texture_image(src_image);
> +      src_res = src->pt;
> +      src_level = src_image->Level;
> +      src_z += src_image->Face;
> +   } else {
> +      struct st_renderbuffer *src = st_renderbuffer(src_renderbuffer);
> +      src_res = src->texture;
> +      src_level = 0;
> +   }
> +
> +   if (dst_image) {
> +      struct st_texture_image *dst = st_texture_image(dst_image);
> +      dst_res = dst->pt;
> +      dst_level = dst_image->Level;
> +      dst_z += dst_image->Face;
> +   } else {
> +      struct st_renderbuffer *dst = st_renderbuffer(dst_renderbuffer);
> +      dst_res = dst->texture;
> +      dst_level = 0;
> +   }
> +
> +   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);
> +}
> +
> +void
> +st_init_copy_image_functions(struct dd_function_table *functions)
> +{
> +   functions->CopyImageSubData = st_CopyImageSubData;
> +}
> diff --git a/src/mesa/state_tracker/st_cb_copyimage.h b/src/mesa/state_tracker/st_cb_copyimage.h
> new file mode 100644
> index 0000000..d17f35c
> --- /dev/null
> +++ b/src/mesa/state_tracker/st_cb_copyimage.h
> @@ -0,0 +1,33 @@
> +/*
> + * Copyright 2015 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * on the rights to use, copy, modify, merge, publish, distribute, sub
> + * license, and/or sell copies of the Software, and to permit persons to whom
> + * the Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +
> +#ifndef ST_CB_COPY_IMAGE_H
> +#define ST_CB_COPY_IMAGE_H
> +
> +struct dd_function_table;
> +
> +extern void
> +st_init_copy_image_functions(struct dd_function_table *functions);
> +
> +#endif /* ST_CB_COPY_IMAGE_H */
> diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c
> index 5d25fed..d4c916e 100644
> --- a/src/mesa/state_tracker/st_cb_texture.c
> +++ b/src/mesa/state_tracker/st_cb_texture.c
> @@ -1873,55 +1873,6 @@ st_TextureView(struct gl_context *ctx,
>      return GL_TRUE;
>   }
>
> -/* HACK: this is only enough for the most basic uses of CopyImage. Must fix
> - * before actually exposing the extension.
> - */
> -static void
> -st_CopyImageSubData(struct gl_context *ctx,
> -                    struct gl_texture_image *src_image,
> -                    struct gl_renderbuffer *src_renderbuffer,
> -                    int src_x, int src_y, int src_z,
> -                    struct gl_texture_image *dst_image,
> -                    struct gl_renderbuffer *dst_renderbuffer,
> -                    int dst_x, int dst_y, int dst_z,
> -                    int src_width, int src_height)
> -{
> -   struct st_context *st = st_context(ctx);
> -   struct pipe_context *pipe = st->pipe;
> -   struct pipe_resource *src_res, *dst_res;
> -   struct pipe_box box;
> -   int src_level, dst_level;
> -
> -   if (src_image) {
> -      struct st_texture_image *src = st_texture_image(src_image);
> -      src_res = src->pt;
> -      src_level = src_image->Level;
> -   }
> -   else {
> -      struct st_renderbuffer *src = st_renderbuffer(src_renderbuffer);
> -      src_res = src->texture;
> -      src_level = 0;
> -   }
> -
> -   if (dst_image) {
> -      struct st_texture_image *dst = st_texture_image(dst_image);
> -      dst_res = dst->pt;
> -      dst_level = dst_image->Level;
> -   }
> -   else {
> -      struct st_renderbuffer *dst = st_renderbuffer(dst_renderbuffer);
> -      dst_res = dst->texture;
> -      dst_level = 0;
> -   }
> -
> -   u_box_2d_zslice(src_x, src_y, src_z, src_width, src_height, &box);
> -   pipe->resource_copy_region(pipe, dst_res, dst_level,
> -                              dst_x, dst_y, dst_z,
> -                              src_res, src_level,
> -                              &box);
> -}
> -
> -
>   void
>   st_init_texture_functions(struct dd_function_table *functions)
>   {
> @@ -1953,6 +1904,4 @@ st_init_texture_functions(struct dd_function_table *functions)
>
>      functions->AllocTextureStorage = st_AllocTextureStorage;
>      functions->TextureView = st_TextureView;
> -
> -   functions->CopyImageSubData = st_CopyImageSubData;
>   }
> diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
> index 5abb173..6e20fd1 100644
> --- a/src/mesa/state_tracker/st_context.c
> +++ b/src/mesa/state_tracker/st_context.c
> @@ -44,6 +44,7 @@
>   #include "st_cb_bufferobjects.h"
>   #include "st_cb_clear.h"
>   #include "st_cb_condrender.h"
> +#include "st_cb_copyimage.h"
>   #include "st_cb_drawpixels.h"
>   #include "st_cb_rasterpos.h"
>   #include "st_cb_drawtex.h"
> @@ -430,6 +431,7 @@ void st_init_driver_functions(struct pipe_screen *screen,
>      st_init_bufferobject_functions(functions);
>      st_init_clear_functions(functions);
>      st_init_bitmap_functions(functions);
> +   st_init_copy_image_functions(functions);
>      st_init_drawpixels_functions(functions);
>      st_init_rasterpos_functions(functions);
>
> diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c
> index d4724b4..bd7cbcc 100644
> --- a/src/mesa/state_tracker/st_extensions.c
> +++ b/src/mesa/state_tracker/st_extensions.c
> @@ -439,6 +439,7 @@ void st_init_extensions(struct pipe_screen *screen,
>         { o(ARB_base_instance),                PIPE_CAP_START_INSTANCE                   },
>         { o(ARB_buffer_storage),               PIPE_CAP_BUFFER_MAP_PERSISTENT_COHERENT   },
>         { o(ARB_color_buffer_float),           PIPE_CAP_VERTEX_COLOR_UNCLAMPED           },
> +      { o(ARB_copy_image),                   PIPE_CAP_COPY_BETWEEN_COMPRESSED_AND_PLAIN_FORMATS },
>         { o(ARB_depth_clamp),                  PIPE_CAP_DEPTH_CLIP_DISABLE               },
>         { o(ARB_depth_texture),                PIPE_CAP_TEXTURE_SHADOW_MAP               },
>         { o(ARB_draw_buffers_blend),           PIPE_CAP_INDEP_BLEND_FUNC                 },
>



More information about the mesa-dev mailing list