|
|
|
@@ -24,8 +24,17 @@
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
#include "isl.h"
|
|
|
|
|
#include "isl_priv.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 {
|
|
|
|
|
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);
|
|
|
|
|
assert(fmtl->channels.p.bits == 0);
|
|
|
|
|
}
|
|
|
|
|