mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-26 04:10:09 +01:00
nir: Add a format unpack helper and tests
Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28793>
This commit is contained in:
parent
faf4c2edfe
commit
5f5f4474f6
3 changed files with 228 additions and 0 deletions
|
|
@ -398,6 +398,23 @@ nir_format_pack_11f11f10f(nir_builder *b, nir_def *color)
|
|||
return packed;
|
||||
}
|
||||
|
||||
nir_def *
|
||||
nir_format_unpack_r9g9b9e5(nir_builder *b, nir_def *packed)
|
||||
{
|
||||
nir_def *rgb = nir_vec3(b, nir_ubitfield_extract_imm(b, packed, 0, 9),
|
||||
nir_ubitfield_extract_imm(b, packed, 9, 9),
|
||||
nir_ubitfield_extract_imm(b, packed, 18, 9));
|
||||
|
||||
/* exponent = (rgb >> 27) - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS;
|
||||
* scale.u = (exponent + 127) << 23;
|
||||
*/
|
||||
nir_def *exp = nir_ubitfield_extract_imm(b, packed, 27, 5);
|
||||
exp = nir_iadd_imm(b, exp, 127 - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS);
|
||||
nir_def *scale = nir_ishl_imm(b, exp, 23);
|
||||
|
||||
return nir_fmul(b, rgb, scale);
|
||||
}
|
||||
|
||||
nir_def *
|
||||
nir_format_pack_r9g9b9e5(nir_builder *b, nir_def *color)
|
||||
{
|
||||
|
|
@ -462,6 +479,155 @@ nir_format_pack_r9g9b9e5(nir_builder *b, nir_def *color)
|
|||
return packed;
|
||||
}
|
||||
|
||||
nir_def *
|
||||
nir_format_unpack_rgba(nir_builder *b, nir_def *packed,
|
||||
enum pipe_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case PIPE_FORMAT_R9G9B9E5_FLOAT: {
|
||||
nir_def *rgb = nir_format_unpack_r9g9b9e5(b, packed);
|
||||
return nir_vec4(b, nir_channel(b, rgb, 0),
|
||||
nir_channel(b, rgb, 1),
|
||||
nir_channel(b, rgb, 2),
|
||||
nir_imm_float(b, 1.0));
|
||||
}
|
||||
|
||||
case PIPE_FORMAT_R11G11B10_FLOAT: {
|
||||
nir_def *rgb = nir_format_unpack_11f11f10f(b, packed);
|
||||
return nir_vec4(b, nir_channel(b, rgb, 0),
|
||||
nir_channel(b, rgb, 1),
|
||||
nir_channel(b, rgb, 2),
|
||||
nir_imm_float(b, 1.0));
|
||||
}
|
||||
|
||||
default:
|
||||
/* Handled below */
|
||||
break;
|
||||
}
|
||||
|
||||
const struct util_format_description *desc = util_format_description(format);
|
||||
assert(desc->layout == UTIL_FORMAT_LAYOUT_PLAIN);
|
||||
|
||||
nir_def *unpacked;
|
||||
if (desc->block.bits <= 32) {
|
||||
unsigned bits[4] = { 0, };
|
||||
for (uint32_t c = 0; c < desc->nr_channels; c++) {
|
||||
if (c != 0) {
|
||||
assert(desc->channel[c].shift ==
|
||||
desc->channel[c - 1].shift + desc->channel[c - 1].size);
|
||||
}
|
||||
bits[c] = desc->channel[c].size;
|
||||
}
|
||||
unpacked = nir_format_unpack_uint(b, packed, bits, desc->nr_channels);
|
||||
} else {
|
||||
unsigned bits = desc->channel[0].size;
|
||||
for (uint32_t c = 1; c < desc->nr_channels; c++)
|
||||
assert(desc->channel[c].size == bits);
|
||||
unpacked = nir_format_bitcast_uvec_unmasked(b, packed, 32, bits);
|
||||
|
||||
/* 3-channel formats can unpack extra components */
|
||||
unpacked = nir_trim_vector(b, unpacked, desc->nr_channels);
|
||||
}
|
||||
|
||||
nir_def *comps[4] = { NULL, };
|
||||
for (uint32_t c = 0; c < desc->nr_channels; c++) {
|
||||
const struct util_format_channel_description *chan = &desc->channel[c];
|
||||
|
||||
nir_def *raw = nir_channel(b, unpacked, c);
|
||||
|
||||
/* Most of the helpers work on an array of bits */
|
||||
unsigned bits[1] = { chan->size };
|
||||
|
||||
switch (chan->type) {
|
||||
case UTIL_FORMAT_TYPE_VOID:
|
||||
comps[c] = nir_imm_int(b, 0);
|
||||
break;
|
||||
|
||||
case UTIL_FORMAT_TYPE_UNSIGNED:
|
||||
if (chan->normalized) {
|
||||
comps[c] = nir_format_unorm_to_float(b, raw, bits);
|
||||
} else if (chan->pure_integer) {
|
||||
comps[c] = nir_u2u32(b, raw);
|
||||
} else {
|
||||
comps[c] = nir_u2f32(b, raw);
|
||||
}
|
||||
break;
|
||||
|
||||
case UTIL_FORMAT_TYPE_SIGNED:
|
||||
raw = nir_format_sign_extend_ivec(b, raw, bits);
|
||||
if (chan->normalized) {
|
||||
comps[c] = nir_format_snorm_to_float(b, raw, bits);
|
||||
} else if (chan->pure_integer) {
|
||||
comps[c] = nir_i2i32(b, raw);
|
||||
} else {
|
||||
comps[c] = nir_i2f32(b, raw);
|
||||
}
|
||||
break;
|
||||
|
||||
case UTIL_FORMAT_TYPE_FIXED:
|
||||
unreachable("Fixed formats not supported");
|
||||
|
||||
case UTIL_FORMAT_TYPE_FLOAT:
|
||||
switch (chan->size) {
|
||||
case 16:
|
||||
comps[c] = nir_unpack_half_2x16_split_x(b, raw);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
comps[c] = raw;
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Unknown number of float bits");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Unknown format channel type");
|
||||
}
|
||||
}
|
||||
|
||||
nir_def *swiz_comps[4] = { NULL, };
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
enum pipe_swizzle s = desc->swizzle[i];
|
||||
switch (s) {
|
||||
case PIPE_SWIZZLE_X:
|
||||
case PIPE_SWIZZLE_Y:
|
||||
case PIPE_SWIZZLE_Z:
|
||||
case PIPE_SWIZZLE_W:
|
||||
swiz_comps[i] = comps[s - PIPE_SWIZZLE_X];
|
||||
break;
|
||||
|
||||
case PIPE_SWIZZLE_0:
|
||||
case PIPE_SWIZZLE_NONE:
|
||||
swiz_comps[i] = nir_imm_int(b, 0);
|
||||
break;
|
||||
|
||||
case PIPE_SWIZZLE_1:
|
||||
if (util_format_is_pure_integer(format))
|
||||
swiz_comps[i] = nir_imm_int(b, 1);
|
||||
else
|
||||
swiz_comps[i] = nir_imm_float(b, 1.0);
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Unknown swizzle");
|
||||
}
|
||||
}
|
||||
nir_def *rgba = nir_vec(b, swiz_comps, 4);
|
||||
|
||||
assert(desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
|
||||
desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);
|
||||
if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
|
||||
nir_def *linear = nir_format_srgb_to_linear(b, rgba);
|
||||
if (rgba->num_components == 4)
|
||||
linear = nir_vector_insert_imm(b, linear, nir_channel(b, rgba, 3), 3);
|
||||
rgba = linear;
|
||||
}
|
||||
|
||||
return rgba;
|
||||
}
|
||||
|
||||
nir_def *
|
||||
nir_format_pack_rgba(nir_builder *b, enum pipe_format format, nir_def *rgba)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -121,8 +121,11 @@ nir_def *nir_format_clamp_sint(nir_builder *b, nir_def *f,
|
|||
|
||||
nir_def *nir_format_unpack_11f11f10f(nir_builder *b, nir_def *packed);
|
||||
nir_def *nir_format_pack_11f11f10f(nir_builder *b, nir_def *color);
|
||||
nir_def *nir_format_unpack_r9g9b9e5(nir_builder *b, nir_def *packed);
|
||||
nir_def *nir_format_pack_r9g9b9e5(nir_builder *b, nir_def *color);
|
||||
|
||||
nir_def *nir_format_unpack_rgba(nir_builder *b, nir_def *packed,
|
||||
enum pipe_format format);
|
||||
nir_def *nir_format_pack_rgba(nir_builder *b, enum pipe_format format,
|
||||
nir_def *rgba);
|
||||
|
||||
|
|
|
|||
|
|
@ -259,6 +259,65 @@ TEST_P(rgba, pack)
|
|||
}
|
||||
}
|
||||
|
||||
TEST_P(rgba, unpack)
|
||||
{
|
||||
pipe_format format = GetParam();
|
||||
auto desc = util_format_description(format);
|
||||
const unsigned dwords = DIV_ROUND_UP(desc->block.bits, 32);
|
||||
|
||||
struct {
|
||||
uint32_t u32[4];
|
||||
} colors[NUM_COLORS];
|
||||
memset(colors, 0, sizeof(colors));
|
||||
|
||||
for (unsigned i = 0; i < NUM_COLORS; i++) {
|
||||
for (unsigned dw = 0; dw < dwords; dw++) {
|
||||
unsigned bits = MIN2(32, desc->block.bits - dw * 32);
|
||||
colors[i].u32[dw] = rand_uint(bits);
|
||||
}
|
||||
}
|
||||
|
||||
nir_intrinsic_instr *uses[NUM_COLORS];
|
||||
for (unsigned i = 0; i < NUM_COLORS; i++) {
|
||||
nir_def *packed_comps[4];
|
||||
for (unsigned dw = 0; dw < dwords; dw++)
|
||||
packed_comps[dw] = nir_imm_int(b, colors[i].u32[dw]);
|
||||
nir_def *packed = nir_vec(b, packed_comps, dwords);
|
||||
nir_def *rgba = nir_format_unpack_rgba(b, packed, format);
|
||||
uses[i] = nir_use(b, rgba);
|
||||
}
|
||||
|
||||
nir_lower_undef_to_zero(b->shader);
|
||||
ASSERT_TRUE(nir_opt_constant_folding(b->shader));
|
||||
ASSERT_TRUE(nir_opt_dce(b->shader));
|
||||
|
||||
for (unsigned i = 0; i < NUM_COLORS; i++) {
|
||||
char expected[16] = { 0, };
|
||||
util_format_unpack_rgba(format, expected, colors[i].u32, 1);
|
||||
|
||||
nir_def *rgba_ssa = uses[i]->src[0].ssa;
|
||||
assert(rgba_ssa->bit_size == 32);
|
||||
assert(rgba_ssa->num_components == 4);
|
||||
|
||||
const nir_const_value *rgba =
|
||||
nir_instr_as_load_const(rgba_ssa->parent_instr)->value;
|
||||
|
||||
if (util_format_is_pure_integer(format)) {
|
||||
uint32_t *exp_u32 = (uint32_t *)expected;
|
||||
for (uint32_t c = 0; c < 4; c++)
|
||||
EXPECT_EQ(exp_u32[c], rgba[c].u32);
|
||||
} else {
|
||||
float *exp_f32 = (float *)expected;
|
||||
for (uint32_t c = 0; c < 4; c++) {
|
||||
EXPECT_EQ(isnan(exp_f32[c]), isnan(uif(rgba[c].u32)));
|
||||
if (!isnan(exp_f32[c]) && !isnan(uif(rgba[c].u32))) {
|
||||
EXPECT_FLOAT_EQ(exp_f32[c], uif(rgba[c].u32));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(nir_format_convert_test, rgba, testing::Values(
|
||||
// There's no way to get bit-for-bit identical with the CPU for these
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue