mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-04-22 16:10:36 +02:00
intel/isl: Add format conversion code
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. Reviewed-by: Topi Pohjolainen <topi.pohjolainen@intel.com>
This commit is contained in:
parent
8152c60e01
commit
09ced65420
5 changed files with 224 additions and 2 deletions
|
|
@ -50,8 +50,8 @@ TEST_LIBS = \
|
||||||
common/libintel_common.la \
|
common/libintel_common.la \
|
||||||
dev/libintel_dev.la \
|
dev/libintel_dev.la \
|
||||||
$(top_builddir)/src/compiler/nir/libnir.la \
|
$(top_builddir)/src/compiler/nir/libnir.la \
|
||||||
$(top_builddir)/src/util/libmesautil.la \
|
|
||||||
$(top_builddir)/src/intel/isl/libisl.la \
|
$(top_builddir)/src/intel/isl/libisl.la \
|
||||||
|
$(top_builddir)/src/util/libmesautil.la \
|
||||||
$(PTHREAD_LIBS) \
|
$(PTHREAD_LIBS) \
|
||||||
$(DLOPEN_LIBS)
|
$(DLOPEN_LIBS)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ TESTS += $(check_PROGRAMS)
|
||||||
isl_tests_isl_surf_get_image_offset_test_LDADD = \
|
isl_tests_isl_surf_get_image_offset_test_LDADD = \
|
||||||
dev/libintel_dev.la \
|
dev/libintel_dev.la \
|
||||||
isl/libisl.la \
|
isl/libisl.la \
|
||||||
|
$(top_builddir)/src/util/libmesautil.la \
|
||||||
-lm
|
-lm
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1576,6 +1576,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_rgb_to_rgbx(enum isl_format rgb) ATTRIBUTE_CONST;
|
||||||
enum isl_format isl_format_rgbx_to_rgba(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);
|
bool isl_is_storage_image_format(enum isl_format fmt);
|
||||||
|
|
||||||
enum isl_format
|
enum isl_format
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,17 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "isl.h"
|
#include "isl.h"
|
||||||
|
#include "isl_priv.h"
|
||||||
#include "dev/gen_device_info.h"
|
#include "dev/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 {
|
struct surface_format_info {
|
||||||
bool exists;
|
bool exists;
|
||||||
uint8_t sampling;
|
uint8_t sampling;
|
||||||
|
|
@ -806,3 +815,208 @@ isl_format_rgbx_to_rgba(enum isl_format rgbx)
|
||||||
return 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);
|
||||||
|
assert(fmtl->channels.p.bits == 0);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ if with_tests
|
||||||
'tests/isl_surf_get_image_offset_test.c',
|
'tests/isl_surf_get_image_offset_test.c',
|
||||||
dependencies : dep_m,
|
dependencies : dep_m,
|
||||||
include_directories : [inc_common, inc_intel],
|
include_directories : [inc_common, inc_intel],
|
||||||
link_with : [libisl, libintel_dev],
|
link_with : [libisl, libintel_dev, libmesa_util],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue