[Mesa-dev] [PATCH 22/29] intel/isl: Add format conversion code

Jason Ekstrand jason at jlekstrand.net
Tue Mar 6 16:53:38 UTC 2018


On Tue, Mar 6, 2018 at 5:06 AM, Pohjolainen, Topi <
topi.pohjolainen at gmail.com> wrote:

> On Fri, Jan 26, 2018 at 05:59:51PM -0800, Jason Ekstrand wrote:
> > This adds helpers to ISL to convert an isl_color_value to and from
> > binary data encoded with a given isl_format.  The conversion is done
> > using ISL's built-in format introspection so it's fairly slow as format
> > conversions go but it should be fine for a single pixel value.  In
> > particular, we can use this to convert clear colors.
> >
> > As a side-effect, we now rely on the sRGB helpers in libmesautil so we
> > need to tweak the build system a bit.  All prior uses of src/util in ISL
> > were header-only.
> > ---
> >  src/intel/Makefile.compiler.am |   2 +-
> >  src/intel/Makefile.isl.am      |   1 +
> >  src/intel/isl/isl.h            |   7 ++
> >  src/intel/isl/isl_format.c     | 214 ++++++++++++++++++++++++++++++
> +++++++++++
> >  src/intel/isl/meson.build      |   2 +-
> >  5 files changed, 224 insertions(+), 2 deletions(-)
> >
> > diff --git a/src/intel/Makefile.compiler.am b/src/intel/
> Makefile.compiler.am
> > index 45e7a6c..d5b9920 100644
> > --- a/src/intel/Makefile.compiler.am
> > +++ b/src/intel/Makefile.compiler.am
> > @@ -49,8 +49,8 @@ TEST_LIBS = \
> >       compiler/libintel_compiler.la \
> >       common/libintel_common.la \
> >       $(top_builddir)/src/compiler/nir/libnir.la \
> > -     $(top_builddir)/src/util/libmesautil.la \
> >       $(top_builddir)/src/intel/isl/libisl.la \
> > +     $(top_builddir)/src/util/libmesautil.la \
> >       $(PTHREAD_LIBS) \
> >       $(DLOPEN_LIBS)
> >
> > diff --git a/src/intel/Makefile.isl.am b/src/intel/Makefile.isl.am
> > index 31273af..8e2cf20 100644
> > --- a/src/intel/Makefile.isl.am
> > +++ b/src/intel/Makefile.isl.am
> > @@ -78,6 +78,7 @@ TESTS += $(check_PROGRAMS)
> >  isl_tests_isl_surf_get_image_offset_test_LDADD = \
> >       common/libintel_common.la \
> >       isl/libisl.la \
> > +     $(top_builddir)/src/util/libmesautil.la \
> >       -lm
> >
> >  # ------------------------------------------------------------
> ----------------
> > diff --git a/src/intel/isl/isl.h b/src/intel/isl/isl.h
> > index 04d0f0b..4806c0c 100644
> > --- a/src/intel/isl/isl.h
> > +++ b/src/intel/isl/isl.h
> > @@ -1535,6 +1535,13 @@ enum isl_format isl_format_rgb_to_rgba(enum
> isl_format rgb) ATTRIBUTE_CONST;
> >  enum isl_format isl_format_rgb_to_rgbx(enum isl_format rgb)
> ATTRIBUTE_CONST;
> >  enum isl_format isl_format_rgbx_to_rgba(enum isl_format rgb)
> ATTRIBUTE_CONST;
> >
> > +void isl_color_value_pack(const union isl_color_value *value,
> > +                          enum isl_format format,
> > +                          uint32_t *data_out);
> > +void isl_color_value_unpack(union isl_color_value *value,
> > +                            enum isl_format format,
> > +                            const uint32_t *data_in);
> > +
> >  bool isl_is_storage_image_format(enum isl_format fmt);
> >
> >  enum isl_format
> > diff --git a/src/intel/isl/isl_format.c b/src/intel/isl/isl_format.c
> > index 46af175..793c84b 100644
> > --- a/src/intel/isl/isl_format.c
> > +++ b/src/intel/isl/isl_format.c
> > @@ -24,8 +24,17 @@
> >  #include <assert.h>
> >
> >  #include "isl.h"
> > +#include "isl_priv.h"
> >  #include "common/gen_device_info.h"
> >
> > +#include "main/macros.h" /* Needed for MAX3 and MAX2 for format_rgb9e5
> */
> > +#include "util/format_srgb.h"
> > +#include "util/format_rgb9e5.h"
> > +#include "util/format_r11g11b10f.h"
> > +
> > +/* Header-only format conversion include */
> > +#include "main/format_utils.h"
> > +
> >  struct surface_format_info {
> >     bool exists;
> >     uint8_t sampling;
> > @@ -806,3 +815,208 @@ isl_format_rgbx_to_rgba(enum isl_format rgbx)
> >        return rgbx;
> >     }
> >  }
> > +
> > +static inline void
> > +pack_channel(const union isl_color_value *value, unsigned i,
> > +             const struct isl_channel_layout *layout,
> > +             enum isl_colorspace colorspace,
> > +             uint32_t data_out[4])
> > +{
> > +   if (layout->type == ISL_VOID)
> > +      return;
> > +
> > +   if (colorspace == ISL_COLORSPACE_SRGB)
> > +      assert(layout->type == ISL_UNORM);
> > +
> > +   uint32_t packed;
> > +   switch (layout->type) {
> > +   case ISL_UNORM:
> > +      if (colorspace == ISL_COLORSPACE_SRGB) {
> > +         if (layout->bits == 8) {
> > +            packed = util_format_linear_float_to_
> srgb_8unorm(value->f32[i]);
> > +         } else {
> > +            float srgb = util_format_linear_to_srgb_
> float(value->f32[i]);
> > +            packed = _mesa_float_to_unorm(srgb, layout->bits);
> > +         }
> > +      } else {
> > +         packed = _mesa_float_to_unorm(value->f32[i], layout->bits);
> > +      }
> > +      break;
> > +   case ISL_SNORM:
> > +      packed = _mesa_float_to_snorm(value->f32[i], layout->bits);
> > +      break;
> > +   case ISL_SFLOAT:
> > +      assert(layout->bits == 16 || layout->bits == 32);
> > +      if (layout->bits == 16) {
> > +         packed = _mesa_float_to_half(value->f32[i]);
> > +      } else {
> > +         packed = value->u32[i];
> > +      }
> > +      break;
> > +   case ISL_UINT:
> > +      packed = MIN(value->u32[i], MAX_UINT(layout->bits));
> > +      break;
> > +   case ISL_SINT:
> > +      packed = MIN(MAX(value->u32[i], MIN_INT(layout->bits)),
> > +                   MAX_INT(layout->bits));
> > +      break;
> > +
> > +   default:
> > +      unreachable("Invalid channel type");
> > +   }
> > +
> > +   unsigned dword = layout->start_bit / 32;
> > +   unsigned bit = layout->start_bit % 32;
> > +   assert(bit + layout->bits <= 32);
> > +   data_out[dword] |= (packed & MAX_UINT(layout->bits)) << bit;
> > +}
> > +
> > +/**
> > + * Take an isl_color_value and pack it into the actual bits as
> specified by
> > + * the isl_format.  This function is very slow for a format conversion
> > + * function but should be fine for a single pixel worth of data.
> > + */
> > +void
> > +isl_color_value_pack(const union isl_color_value *value,
> > +                     enum isl_format format,
> > +                     uint32_t *data_out)
> > +{
> > +   const struct isl_format_layout *fmtl = isl_format_get_layout(format);
> > +   assert(fmtl->colorspace == ISL_COLORSPACE_LINEAR ||
> > +          fmtl->colorspace == ISL_COLORSPACE_SRGB);
> > +   assert(!isl_format_is_compressed(format));
> > +
> > +   memset(data_out, 0, isl_align(fmtl->bpb, 32) / 8);
> > +
> > +   if (format == ISL_FORMAT_R9G9B9E5_SHAREDEXP) {
> > +      data_out[0] = float3_to_rgb9e5(value->f32);
> > +      return;
> > +   } else if (format == ISL_FORMAT_R11G11B10_FLOAT) {
> > +      data_out[0] = float3_to_r11g11b10f(value->f32);
> > +      return;
> > +   }
> > +
> > +   pack_channel(value, 0, &fmtl->channels.r, fmtl->colorspace,
> data_out);
> > +   pack_channel(value, 1, &fmtl->channels.g, fmtl->colorspace,
> data_out);
> > +   pack_channel(value, 2, &fmtl->channels.b, fmtl->colorspace,
> data_out);
> > +   pack_channel(value, 3, &fmtl->channels.a, ISL_COLORSPACE_LINEAR,
> data_out);
> > +   pack_channel(value, 0, &fmtl->channels.l, fmtl->colorspace,
> data_out);
> > +   pack_channel(value, 0, &fmtl->channels.i, ISL_COLORSPACE_LINEAR,
> data_out);
> > +   assert(fmtl->channels.p.bits == 0);
> > +}
> > +
> > +/** Extend an N-bit signed integer to 32 bits */
> > +static inline int32_t
> > +sign_extend(int32_t x, unsigned bits)
> > +{
> > +   if (bits < 32) {
> > +      unsigned shift = 32 - bits;
> > +      return (x << shift) >> shift;
> > +   } else {
> > +      return x;
> > +   }
> > +}
> > +
> > +static inline void
> > +unpack_channel(union isl_color_value *value,
> > +               unsigned start, unsigned count,
> > +               const struct isl_channel_layout *layout,
> > +               enum isl_colorspace colorspace,
> > +               const uint32_t *data_in)
> > +{
> > +   if (layout->type == ISL_VOID)
> > +      return;
> > +
> > +   unsigned dword = layout->start_bit / 32;
> > +   unsigned bit = layout->start_bit % 32;
> > +   assert(bit + layout->bits <= 32);
> > +   uint32_t packed = (data_in[dword] >> bit) & MAX_UINT(layout->bits);
> > +
> > +   union {
> > +      uint32_t u32;
> > +      float f32;
> > +   } unpacked;
> > +
> > +   if (colorspace == ISL_COLORSPACE_SRGB)
> > +      assert(layout->type == ISL_UNORM);
> > +
> > +   switch (layout->type) {
> > +   case ISL_UNORM:
> > +      unpacked.f32 = _mesa_unorm_to_float(packed, layout->bits);
> > +      if (colorspace == ISL_COLORSPACE_SRGB) {
> > +         if (layout->bits == 8) {
> > +            unpacked.f32 = util_format_srgb_8unorm_to_
> linear_float(packed);
> > +         } else {
> > +            float srgb = _mesa_unorm_to_float(packed, layout->bits);
> > +            unpacked.f32 = util_format_srgb_to_linear_float(srgb);
> > +         }
> > +      } else {
> > +         unpacked.f32 = _mesa_unorm_to_float(packed, layout->bits);
> > +      }
> > +      break;
> > +   case ISL_SNORM:
> > +      unpacked.f32 = _mesa_snorm_to_float(sign_extend(packed,
> layout->bits),
> > +                                          layout->bits);
> > +      break;
> > +   case ISL_SFLOAT:
> > +      assert(layout->bits == 16 || layout->bits == 32);
> > +      if (layout->bits == 16) {
> > +         unpacked.f32 = _mesa_half_to_float(packed);
> > +      } else {
> > +         unpacked.u32 = packed;
> > +      }
> > +      break;
> > +   case ISL_UINT:
> > +      unpacked.u32 = packed;
> > +      break;
> > +   case ISL_SINT:
> > +      unpacked.u32 = sign_extend(packed, layout->bits);
> > +      break;
> > +
> > +   default:
> > +      unreachable("Invalid channel type");
> > +   }
> > +
> > +   for (unsigned i = 0; i < count; i++)
> > +      value->u32[start + i] = unpacked.u32;
> > +}
> > +
> > +/**
> > + * Take unpack an isl_color_value from the actual bits as specified by
> > + * the isl_format.  This function is very slow for a format conversion
> > + * function but should be fine for a single pixel worth of data.
> > + */
> > +void
> > +isl_color_value_unpack(union isl_color_value *value,
> > +                       enum isl_format format,
> > +                       const uint32_t data_in[4])
> > +{
> > +   const struct isl_format_layout *fmtl = isl_format_get_layout(format);
> > +   assert(fmtl->colorspace == ISL_COLORSPACE_LINEAR ||
> > +          fmtl->colorspace == ISL_COLORSPACE_SRGB);
> > +   assert(!isl_format_is_compressed(format));
> > +
> > +   /* Default to opaque black. */
> > +   memset(value, 0, sizeof(*value));
> > +   if (isl_format_has_int_channel(format)) {
> > +      value->u32[3] = 1u;
> > +   } else {
> > +      value->f32[3] = 1.0f;
> > +   }
> > +
> > +   if (format == ISL_FORMAT_R9G9B9E5_SHAREDEXP) {
> > +      rgb9e5_to_float3(data_in[0], value->f32);
> > +      return;
> > +   } else if (format == ISL_FORMAT_R11G11B10_FLOAT) {
> > +      r11g11b10f_to_float3(data_in[0], value->f32);
> > +      return;
> > +   }
> > +
> > +   unpack_channel(value, 0, 1, &fmtl->channels.r, fmtl->colorspace,
> data_in);
> > +   unpack_channel(value, 1, 1, &fmtl->channels.g, fmtl->colorspace,
> data_in);
> > +   unpack_channel(value, 2, 1, &fmtl->channels.b, fmtl->colorspace,
> data_in);
> > +   unpack_channel(value, 3, 1, &fmtl->channels.a,
> ISL_COLORSPACE_LINEAR, data_in);
> > +   unpack_channel(value, 0, 3, &fmtl->channels.l, fmtl->colorspace,
> data_in);
> > +   unpack_channel(value, 0, 4, &fmtl->channels.i,
> ISL_COLORSPACE_LINEAR, data_in);
>
> I guess I don't know enough about formats to understand why we leave alpha
> channel intact for luminance but trash it in case of intensity?
>

Luminance effectively has a swizzle of RRR1 but intensity is RRRR.


> Other than that this looks good to me. Patches 22 and 23 are:
>
> Reviewed-by: Topi Pohjolainen <topi.pohjolainen at intel.com>
>
> > +   assert(fmtl->channels.p.bits == 0);
> > +}
> > diff --git a/src/intel/isl/meson.build b/src/intel/isl/meson.build
> > index 0838c32..e9ec5ba 100644
> > --- a/src/intel/isl/meson.build
> > +++ b/src/intel/isl/meson.build
> > @@ -95,7 +95,7 @@ if with_tests
> >        'tests/isl_surf_get_image_offset_test.c',
> >        dependencies : dep_m,
> >        include_directories : [inc_common, inc_intel],
> > -      link_with : [libisl, libintel_common],
> > +      link_with : [libisl, libintel_common, libmesa_util],
> >      )
> >    )
> >  endif
> > --
> > 2.5.0.400.gff86faf
> >
> > _______________________________________________
> > mesa-dev mailing list
> > mesa-dev at lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20180306/95e303b0/attachment-0001.html>


More information about the mesa-dev mailing list