diff --git a/src/gallium/drivers/panfrost/pan_job.c b/src/gallium/drivers/panfrost/pan_job.c index 15c28474fde..f21f764a7be 100644 --- a/src/gallium/drivers/panfrost/pan_job.c +++ b/src/gallium/drivers/panfrost/pan_job.c @@ -905,6 +905,7 @@ panfrost_batch_clear(struct panfrost_batch *batch, double depth, unsigned stencil) { struct panfrost_context *ctx = batch->ctx; + struct panfrost_blend_state *blend = ctx->blend; if (buffers & PIPE_CLEAR_COLOR) { for (unsigned i = 0; i < ctx->pipe_framebuffer.nr_cbufs; ++i) { @@ -912,7 +913,8 @@ panfrost_batch_clear(struct panfrost_batch *batch, continue; enum pipe_format format = ctx->pipe_framebuffer.cbufs[i]->format; - pan_pack_color(batch->clear_color[i], color, format); + bool dither = blend ? blend->base.dither : false; + pan_pack_color(batch->clear_color[i], color, format, dither); } } diff --git a/src/panfrost/lib/pan_clear.c b/src/panfrost/lib/pan_clear.c index 6247348565d..f67af951130 100644 --- a/src/panfrost/lib/pan_clear.c +++ b/src/panfrost/lib/pan_clear.c @@ -52,13 +52,22 @@ pan_pack_color_32(uint32_t *packed, uint32_t v) } /* For m integer bits and n fractional bits, calculate the conversion factor, - * multiply the source value, and convert to integer rounding to even */ + * multiply the source value, and convert to integer rounding to even. When + * dithering, the fractional bits are used. When not dithered, only the integer + * bits are used and the fractional bits must remain zero. */ static inline uint32_t -float_to_fixed(float f, unsigned bits_int, unsigned bits_frac) +float_to_fixed(float f, unsigned bits_int, unsigned bits_frac, bool dither) { - float factor = ((1 << bits_int) - 1) << bits_frac; - return _mesa_roundevenf(f * factor); + uint32_t m = (1 << bits_int) - 1; + + if (dither) { + float factor = m << bits_frac; + return _mesa_roundevenf(f * factor); + } else { + uint32_t v = _mesa_roundevenf(f * (float) m); + return v << bits_frac; + } } /* These values are shared across hardware versions. Don't include GenXML. */ @@ -116,7 +125,8 @@ pan_pack_raw(uint32_t *packed, const union pipe_color_union *color, enum pipe_fo } void -pan_pack_color(uint32_t *packed, const union pipe_color_union *color, enum pipe_format format) +pan_pack_color(uint32_t *packed, const union pipe_color_union *color, + enum pipe_format format, bool dithered) { /* Set of blendable formats is common across versions. TODO: v9 */ enum mali_color_buffer_internal_format internal = @@ -157,10 +167,10 @@ pan_pack_color(uint32_t *packed, const union pipe_color_union *color, enum pipe_ assert(count_a == 32); /* Convert the transformed float colour to the given layout */ - uint32_t ur = float_to_fixed(r, l.int_r, l.frac_r) << 0; - uint32_t ug = float_to_fixed(g, l.int_g, l.frac_g) << count_r; - uint32_t ub = float_to_fixed(b, l.int_b, l.frac_b) << count_g; - uint32_t ua = float_to_fixed(a, l.int_a, l.frac_a) << count_b; + uint32_t ur = float_to_fixed(r, l.int_r, l.frac_r, dithered) << 0; + uint32_t ug = float_to_fixed(g, l.int_g, l.frac_g, dithered) << count_r; + uint32_t ub = float_to_fixed(b, l.int_b, l.frac_b, dithered) << count_g; + uint32_t ua = float_to_fixed(a, l.int_a, l.frac_a, dithered) << count_b; pan_pack_color_32(packed, ur | ug | ub | ua); } diff --git a/src/panfrost/lib/pan_util.h b/src/panfrost/lib/pan_util.h index 0f23fc2fca2..3fd9503a663 100644 --- a/src/panfrost/lib/pan_util.h +++ b/src/panfrost/lib/pan_util.h @@ -61,6 +61,7 @@ panfrost_format_to_bifrost_blend(const struct panfrost_device *dev, bool dithered); void -pan_pack_color(uint32_t *packed, const union pipe_color_union *color, enum pipe_format format); +pan_pack_color(uint32_t *packed, const union pipe_color_union *color, + enum pipe_format format, bool dithered); #endif /* PAN_UTIL_H */ diff --git a/src/panfrost/lib/tests/test-clear.c b/src/panfrost/lib/tests/test-clear.c index 5a4a235dc7b..aa6763a93c7 100644 --- a/src/panfrost/lib/tests/test-clear.c +++ b/src/panfrost/lib/tests/test-clear.c @@ -43,10 +43,15 @@ struct test { static const struct test clear_tests[] = { /* Basic tests */ { PIPE_FORMAT_R8G8B8A8_UNORM, D, F(0.0, 0.0, 0.0, 0.0), RRRR(0x00000000) }, + { PIPE_FORMAT_R8G8B8A8_UNORM, _, F(0.0, 0.0, 0.0, 0.0), RRRR(0x00000000) }, { PIPE_FORMAT_R8G8B8A8_UNORM, D, F(1.0, 0.0, 0.0, 1.0), RRRR(0xFF0000FF) }, + { PIPE_FORMAT_R8G8B8A8_UNORM, _, F(1.0, 0.0, 0.0, 1.0), RRRR(0xFF0000FF) }, { PIPE_FORMAT_B8G8R8A8_UNORM, D, F(1.0, 0.0, 0.0, 1.0), RRRR(0xFF0000FF) }, + { PIPE_FORMAT_B8G8R8A8_UNORM, _, F(1.0, 0.0, 0.0, 1.0), RRRR(0xFF0000FF) }, { PIPE_FORMAT_R8G8B8A8_UNORM, D, F(0.664, 0.0, 0.0, 0.0), RRRR(0x000000A9) }, + { PIPE_FORMAT_R8G8B8A8_UNORM, _, F(0.664, 0.0, 0.0, 0.0), RRRR(0x000000A9) }, { PIPE_FORMAT_R4G4B4A4_UNORM, D, F(0.664, 0.0, 0.0, 0.0), RRRR(0x0000009F) }, + { PIPE_FORMAT_R4G4B4A4_UNORM, _, F(0.664, 0.0, 0.0, 0.0), RRRR(0x000000A0) }, /* Test rounding to nearest even. The values are cherrypicked to multiply * out to a fractional part of 0.5. The first test should round down and @@ -55,6 +60,16 @@ static const struct test clear_tests[] = { { PIPE_FORMAT_R4G4B4A4_UNORM, D, F(0.41875, 0.0, 0.0, 1.0), RRRR(0xF0000064) }, { PIPE_FORMAT_R4G4B4A4_UNORM, D, F(0.40625, 0.0, 0.0, 1.0), RRRR(0xF0000062) }, + /* Testing rounding direction when dithering is disabled. The packed value + * is what gets rounded. This behaves as round-to-even with the cutoff point + * at 2^-m + 2^-n for an m:n representation. */ + + { PIPE_FORMAT_R4G4B4A4_UNORM, _, F(0.03125, 0.0, 0.0, 1.0), RRRR(0xF0000000) }, + { PIPE_FORMAT_R4G4B4A4_UNORM, _, F(0.03125, 0.0, 0.0, 1.0), RRRR(0xF0000000) }, + { PIPE_FORMAT_R4G4B4A4_UNORM, _, F(0.03333, 0.0, 0.0, 1.0), RRRR(0xF0000000) }, + { PIPE_FORMAT_R4G4B4A4_UNORM, _, F(0.03334, 0.0, 0.0, 1.0), RRRR(0xF0000010) }, + { PIPE_FORMAT_R4G4B4A4_UNORM, _, F(0.09375, 0.0, 0.0, 1.0), RRRR(0xF0000010) }, + /* Check all the special formats with different edge cases */ { PIPE_FORMAT_R4G4B4A4_UNORM, D, F(0.127, 2.4, -1.0, 0.5), RRRR(0x7800F01E) }, @@ -69,6 +84,14 @@ static const struct test clear_tests[] = { { PIPE_FORMAT_R10G10B10A2_UNORM, D, F(0.718, 0.18, 1.0, 2.0), RRRR(0xFFF2E2DF) }, { PIPE_FORMAT_R8G8B8A8_SRGB, D, F(0.718, 0.18, 1.0, 2.0), RRRR(0xFFFF76DC) }, + /* Check that values are padded when dithering is disabled */ + + { PIPE_FORMAT_R4G4B4A4_UNORM, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0xF0F030B0) }, + { PIPE_FORMAT_R5G6B5_UNORM, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0x3E02C2C0) }, + { PIPE_FORMAT_R5G5B5A1_UNORM, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0xBE0302C0) }, + { PIPE_FORMAT_R10G10B10A2_UNORM, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0xFFF2E2DF) }, + { PIPE_FORMAT_R8G8B8A8_SRGB, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0xFFFF76DC) }, + /* Check that blendable tilebuffer values are invariant under swizzling */ { PIPE_FORMAT_B4G4R4A4_UNORM, D, F(0.127, 2.4, -1.0, 0.5), RRRR(0x7800F01E) }, @@ -83,19 +106,36 @@ static const struct test clear_tests[] = { { PIPE_FORMAT_B10G10R10A2_UNORM, D, F(0.718, 0.18, 1.0, 2.0), RRRR(0xFFF2E2DF) }, { PIPE_FORMAT_B8G8R8A8_SRGB, D, F(0.718, 0.18, 1.0, 2.0), RRRR(0xFFFF76DC) }, - /* Check raw formats, which are not invariant under swizzling */ + { PIPE_FORMAT_B4G4R4A4_UNORM, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0xF0F030B0) }, + { PIPE_FORMAT_B5G6R5_UNORM, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0x3E02C2C0) }, + { PIPE_FORMAT_B5G5R5A1_UNORM, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0xBE0302C0) }, + { PIPE_FORMAT_B10G10R10A2_UNORM, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0xFFF2E2DF) }, + { PIPE_FORMAT_B8G8R8A8_SRGB, _, F(0.718, 0.18, 1.0, 2.0), RRRR(0xFFFF76DC) }, + + /* Check raw formats, which are not invariant under swizzling. Raw formats + * cannot be dithered. */ { PIPE_FORMAT_R8G8B8A8_UINT, D, UI(0xCA, 0xFE, 0xBA, 0xBE), RRRR(0xBEBAFECA) }, + { PIPE_FORMAT_R8G8B8A8_UINT, _, UI(0xCA, 0xFE, 0xBA, 0xBE), RRRR(0xBEBAFECA) }, + { PIPE_FORMAT_B8G8R8A8_UINT, D, UI(0xCA, 0xFE, 0xBA, 0xBE), RRRR(0xBECAFEBA) }, + { PIPE_FORMAT_B8G8R8A8_UINT, _, UI(0xCA, 0xFE, 0xBA, 0xBE), RRRR(0xBECAFEBA) }, /* Check that larger raw formats are replicated correctly */ { PIPE_FORMAT_R16G16B16A16_UINT, D, UI(0xCAFE, 0xBABE, 0xABAD, 0x1DEA), RGRG(0xBABECAFE, 0x1DEAABAD) }, + { PIPE_FORMAT_R16G16B16A16_UINT, _, UI(0xCAFE, 0xBABE, 0xABAD, 0x1DEA), + RGRG(0xBABECAFE, 0x1DEAABAD) }, + { PIPE_FORMAT_R32G32B32A32_UINT, D, UI(0xCAFEBABE, 0xABAD1DEA, 0xDEADBEEF, 0xABCDEF01), { 0xCAFEBABE, 0xABAD1DEA, 0xDEADBEEF, 0xABCDEF01 } }, + + { PIPE_FORMAT_R32G32B32A32_UINT, _, + UI(0xCAFEBABE, 0xABAD1DEA, 0xDEADBEEF, 0xABCDEF01), + { 0xCAFEBABE, 0xABAD1DEA, 0xDEADBEEF, 0xABCDEF01 } }, }; #define ASSERT_EQ(x, y) do { \ @@ -103,8 +143,8 @@ static const struct test clear_tests[] = { nr_pass++; \ } else { \ nr_fail++; \ - fprintf(stderr, "%s: Assertion failed %s (%08X %08X %08X %08X) != %s (%08X %08X %08X %08X)\n", \ - util_format_short_name(T.format), #x, x[0], x[1], x[2], x[3], #y, y[0], y[1], y[2], y[3]); \ + fprintf(stderr, "%s%s: Assertion failed %s (%08X %08X %08X %08X) != %s (%08X %08X %08X %08X)\n", \ + util_format_short_name(T.format), T.dithered ? " dithered" : "", #x, x[0], x[1], x[2], x[3], #y, y[0], y[1], y[2], y[3]); \ } \ } while(0) @@ -115,7 +155,7 @@ int main(int argc, const char **argv) for (unsigned i = 0; i < ARRAY_SIZE(clear_tests); ++i) { struct test T = clear_tests[i]; uint32_t packed[4]; - pan_pack_color(&packed[0], &T.colour, T.format); + pan_pack_color(&packed[0], &T.colour, T.format, T.dithered); ASSERT_EQ(T.packed, packed); } diff --git a/src/panfrost/vulkan/panvk_cmd_buffer.c b/src/panfrost/vulkan/panvk_cmd_buffer.c index 3a19c93ab99..c753c688db5 100644 --- a/src/panfrost/vulkan/panvk_cmd_buffer.c +++ b/src/panfrost/vulkan/panvk_cmd_buffer.c @@ -593,7 +593,7 @@ panvk_cmd_prepare_clear_values(struct panvk_cmd_buffer *cmdbuf, } } else if (attachment->load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { union pipe_color_union *col = (union pipe_color_union *) &in[i].color; - pan_pack_color(cmdbuf->state.clear[i].color, col, fmt); + pan_pack_color(cmdbuf->state.clear[i].color, col, fmt, false); } } }