On Tue, Mar 6, 2018 at 5:06 AM, Pohjolainen, Topi < topi.pohjolai...@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.pohjolai...@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@lists.freedesktop.org > > https://lists.freedesktop.org/mailman/listinfo/mesa-dev >
_______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev