panfrost: Enable rendering to 16-bit and 32-bit
authorAlyssa Rosenzweig <alyssa@collabora.com>
Thu, 27 Oct 2022 20:29:37 +0000 (16:29 -0400)
committerMarge Bot <emma+marge@anholt.net>
Sat, 29 Oct 2022 18:23:55 +0000 (18:23 +0000)
Bifrost onwards handle this in hardware, and the Midgard lowering isn't
too terrible. Enable the format, otherwise desktop GL apps such as
Hacknet try to render to the format and get an incomplete framebuffer.

Cc stable because apparently we've been advertising this format
unintentionally as a result of some other interaction? Unclear how
Hacknet is hitting this, maybe it's an app bug. Shrug, it's not a big
deal regardless.

Additionally, we need to restrict texturing from 32-bit normalized due
to a restriction added with the v7 pixel format fiasco. That means
restricting rendering to 32-bit normalized on v7 onwards.

Closes: #7251
Signed-off-by: Alyssa Rosenzweig <alyssa@collabora.com>
Tested-by: Dang Huynh <danct12@disroot.org>
Cc: mesa-stable
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19358>

src/panfrost/lib/pan_format.c
src/panfrost/util/pan_lower_framebuffer.c

index bcb3ff0..e27f207 100644 (file)
@@ -398,15 +398,11 @@ const struct panfrost_format GENX(panfrost_pipe_format)[PIPE_FORMAT_COUNT] = {
         FMT(R9G9B9E5_FLOAT,          R9F_G9F_B9F_E5F, RGB1, L, VT__),
         FMT(R8_SNORM,                R8_SNORM,        R001, L, VT__),
         FMT(R16_SNORM,               R16_SNORM,       R001, L, VT__),
-        FMT(R32_SNORM,               R32_SNORM,       R001, L, VT__),
         FMT(R8G8_SNORM,              RG8_SNORM,       RG01, L, VT__),
         FMT(R16G16_SNORM,            RG16_SNORM,      RG01, L, VT__),
-        FMT(R32G32_SNORM,            RG32_SNORM,      RG01, L, VT__),
         FMT(R8G8B8_SNORM,            RGB8_SNORM,      RGB1, L, VT__),
-        FMT(R32G32B32_SNORM,         RGB32_SNORM,     RGB1, L, VT__),
         FMT(R8G8B8A8_SNORM,          RGBA8_SNORM,     RGBA, L, VT__),
         FMT(R16G16B16A16_SNORM,      RGBA16_SNORM,    RGBA, L, VT__),
-        FMT(R32G32B32A32_SNORM,      RGBA32_SNORM,    RGBA, L, VT__),
         FMT(I8_SINT,                 R8I,             RRRR, L, VTR_),
         FMT(L8_SINT,                 R8I,             RRR1, L, VTR_),
         FMT(I8_UINT,                 R8UI,            RRRR, L, VTR_),
@@ -441,13 +437,34 @@ const struct panfrost_format GENX(panfrost_pipe_format)[PIPE_FORMAT_COUNT] = {
         FMT(R32G32B32_FLOAT,         RGB32F,          RGB1, L, VTR_),
         FMT(R32G32B32A32_FLOAT,      RGBA32F,         RGBA, L, VTR_),
         FMT(R8_UNORM,                R8_UNORM,        R001, L, VTR_),
-        FMT(R16_UNORM,               R16_UNORM,       R001, L, VT__),
-        FMT(R32_UNORM,               R32_UNORM,       R001, L, VT__),
+        FMT(R16_UNORM,               R16_UNORM,       R001, L, VTR_),
         FMT(R8G8_UNORM,              RG8_UNORM,       RG01, L, VTR_),
-        FMT(R16G16_UNORM,            RG16_UNORM,      RG01, L, VT__),
-        FMT(R32G32_UNORM,            RG32_UNORM,      RG01, L, VT__),
+        FMT(R16G16_UNORM,            RG16_UNORM,      RG01, L, VTR_),
         FMT(R8G8B8_UNORM,            RGB8_UNORM,      RGB1, L, VTR_),
 
+        /* 32-bit NORM is not texturable in v7 onwards. It's renderable
+         * everywhere, but rendering without texturing is not useful.
+         */
+#if PAN_ARCH <= 6
+        FMT(R32_UNORM,               R32_UNORM,       R001, L, VTR_),
+        FMT(R32G32_UNORM,            RG32_UNORM,      RG01, L, VTR_),
+        FMT(R32G32B32_UNORM,         RGB32_UNORM,     RGB1, L, VT__),
+        FMT(R32G32B32A32_UNORM,      RGBA32_UNORM,    RGBA, L, VTR_),
+        FMT(R32_SNORM,               R32_SNORM,       R001, L, VT__),
+        FMT(R32G32_SNORM,            RG32_SNORM,      RG01, L, VT__),
+        FMT(R32G32B32_SNORM,         RGB32_SNORM,     RGB1, L, VT__),
+        FMT(R32G32B32A32_SNORM,      RGBA32_SNORM,    RGBA, L, VT__),
+#else
+        FMT(R32_UNORM,               R32_UNORM,       R001, L, V___),
+        FMT(R32G32_UNORM,            RG32_UNORM,      RG01, L, V___),
+        FMT(R32G32B32_UNORM,         RGB32_UNORM,     RGB1, L, V___),
+        FMT(R32G32B32A32_UNORM,      RGBA32_UNORM,    RGBA, L, V___),
+        FMT(R32_SNORM,               R32_SNORM,       R001, L, V___),
+        FMT(R32G32_SNORM,            RG32_SNORM,      RG01, L, V___),
+        FMT(R32G32B32_SNORM,         RGB32_SNORM,     RGB1, L, V___),
+        FMT(R32G32B32A32_SNORM,      RGBA32_SNORM,    RGBA, L, V___),
+#endif
+
         /* Don't allow render/texture for 48-bit  */
         FMT(R16G16B16_UNORM,         RGB16_UNORM,     RGB1, L, V___),
         FMT(R16G16B16_SINT,          RGB16I,          RGB1, L, V___),
@@ -456,16 +473,9 @@ const struct panfrost_format GENX(panfrost_pipe_format)[PIPE_FORMAT_COUNT] = {
         FMT(R16G16B16_SSCALED,       RGB16I,          RGB1, L, V___),
         FMT(R16G16B16_SNORM,         RGB16_SNORM,     RGB1, L, V___),
         FMT(R16G16B16_UINT,          RGB16UI,         RGB1, L, V___),
-
-#if PAN_ARCH <= 6
-        FMT(R32G32B32_UNORM,         RGB32_UNORM,     RGB1, L, VT__),
-#else
-        FMT(R32G32B32_UNORM,         RGB32_UNORM,     RGB1, L, V___),
-#endif
         FMT(R4G4B4A4_UNORM,          RGBA4_UNORM,     RGBA, L, VTR_),
         FMT(B4G4R4A4_UNORM,          RGBA4_UNORM,     BGRA, L, VTR_),
-        FMT(R16G16B16A16_UNORM,      RGBA16_UNORM,    RGBA, L, VT__),
-        FMT(R32G32B32A32_UNORM,      RGBA32_UNORM,    RGBA, L, VT__),
+        FMT(R16G16B16A16_UNORM,      RGBA16_UNORM,    RGBA, L, VTR_),
         FMT(B8G8R8A8_UNORM,          RGBA8_UNORM,     BGRA, L, VTR_),
         FMT(B8G8R8X8_UNORM,          RGBA8_UNORM,     BGR1, L, VTR_),
         FMT(A8R8G8B8_UNORM,          RGBA8_UNORM,     GBAR, L, VTR_),
index 80a88f6..c31d043 100644 (file)
@@ -99,6 +99,13 @@ pan_is_format_native(const struct util_format_description *desc, bool broken_ld_
         if (desc->format == PIPE_FORMAT_R11G11B10_FLOAT)
                 return false;
 
+        if (desc->is_array) {
+                int c = util_format_get_first_non_void_channel(desc->format);
+                assert(c >= 0);
+                if (desc->channel[c].size > 8)
+                        return false;
+        }
+
         return true;
 }
 
@@ -118,12 +125,6 @@ pan_replicate(nir_builder *b, nir_ssa_def *v, unsigned num_components)
         return nir_vec(b, replicated, 4);
 }
 
-static nir_ssa_def *
-pan_unpack_pure_32(nir_builder *b, nir_ssa_def *pack, unsigned num_components)
-{
-        return nir_channels(b, pack, (1 << num_components) - 1);
-}
-
 /* Pure x16 formats are x16 unpacked, so it's similar, but we need to pack
  * upper/lower halves of course */
 
@@ -205,6 +206,24 @@ pan_unpack_pure_8(nir_builder *b, nir_ssa_def *pack, unsigned num_components)
         return nir_channels(b, unpacked, (1 << num_components) - 1);
 }
 
+static nir_ssa_def *
+pan_fsat(nir_builder *b, nir_ssa_def *v, bool is_signed)
+{
+        if (is_signed)
+                return nir_fsat_signed_mali(b, v);
+        else
+                return nir_fsat(b, v);
+}
+
+static float
+norm_scale(bool snorm, unsigned bits)
+{
+        if (snorm)
+                return (1 << (bits - 1)) - 1;
+        else
+                return (1 << bits) - 1;
+}
+
 /* For <= 8-bits per channel, [U,S]NORM formats are packed like [U,S]NORM 8,
  * with zeroes spacing out each component as needed */
 
@@ -226,11 +245,7 @@ pan_pack_norm(nir_builder *b, nir_ssa_def *v,
 
         /* If a channel has N bits, we pad out to the byte by (8 - N) bits */
         nir_ssa_def *shifts = nir_imm_ivec4(b, 8 - x, 8 - y, 8 - z, 8 - w);
-
-        nir_ssa_def *clamped =
-                is_signed ?
-                nir_fsat_signed_mali(b, nir_pad_vec4(b, v)) :
-                nir_fsat(b, nir_pad_vec4(b, v));
+        nir_ssa_def *clamped = pan_fsat(b, nir_pad_vec4(b, v), is_signed);
 
         nir_ssa_def *f = nir_fmul(b, clamped, scales);
         nir_ssa_def *u8 = nir_f2u8(b, nir_fround_even(b, f));
@@ -371,6 +386,21 @@ pan_linear_to_srgb(nir_builder *b, nir_ssa_def *linear)
         return nir_vec(b, comp, 4);
 }
 
+static nir_ssa_def *
+pan_unpack_pure(nir_builder *b, nir_ssa_def *packed, unsigned size, unsigned nr)
+{
+        switch (size) {
+        case 32:
+                return nir_trim_vector(b, packed, nr);
+        case 16:
+                return pan_unpack_pure_16(b, packed, nr);
+        case 8:
+                return pan_unpack_pure_8(b, packed, nr);
+        default:
+                unreachable("Unrenderable size");
+        }
+}
+
 /* Generic dispatches for un/pack regardless of format */
 
 static nir_ssa_def *
@@ -382,18 +412,23 @@ pan_unpack(nir_builder *b,
                 int c = util_format_get_first_non_void_channel(desc->format);
                 assert(c >= 0);
                 struct util_format_channel_description d = desc->channel[c];
+                nir_ssa_def *unpacked = pan_unpack_pure(b, packed, d.size, desc->nr_channels);
 
-                if (d.size == 32 || d.size == 16) {
-                        assert(!d.normalized);
-                        assert(d.type == UTIL_FORMAT_TYPE_FLOAT || d.pure_integer);
+                /* Normalized formats are unpacked as integers. We need to
+                 * convert to float for the final result.
+                 */
+                if (d.normalized) {
+                        bool snorm = desc->is_snorm;
+                        unsigned float_sz = (d.size <= 8 ? 16 : 32);
+                        float multiplier = norm_scale(snorm, d.size);
 
-                        return d.size == 32 ? pan_unpack_pure_32(b, packed, desc->nr_channels) :
-                                pan_unpack_pure_16(b, packed, desc->nr_channels);
-                } else if (d.size == 8) {
-                        assert(d.pure_integer);
-                        return pan_unpack_pure_8(b, packed, desc->nr_channels);
+                        nir_ssa_def *as_float =
+                                snorm ? nir_i2fN(b, unpacked, float_sz) :
+                                        nir_u2fN(b, unpacked, float_sz);
+
+                        return nir_fmul_imm(b, as_float, 1.0 / multiplier);
                 } else {
-                        unreachable("Unrenderable size");
+                        return unpacked;
                 }
         }
 
@@ -422,28 +457,33 @@ pan_pack(nir_builder *b,
         if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
                 unpacked = pan_linear_to_srgb(b, unpacked);
 
-        if (util_format_is_unorm8(desc))
-                return pan_pack_unorm(b, unpacked, 8, 8, 8, 8);
-
-        if (util_format_is_snorm8(desc->format))
-                return pan_pack_snorm(b, unpacked, 8, 8, 8, 8);
-
         if (desc->is_array) {
                 int c = util_format_get_first_non_void_channel(desc->format);
                 assert(c >= 0);
                 struct util_format_channel_description d = desc->channel[c];
 
-                if (d.size == 32 || d.size == 16) {
-                        assert(!d.normalized);
-                        assert(d.type == UTIL_FORMAT_TYPE_FLOAT || d.pure_integer);
+                /* Pure formats are packed as-is */
+                nir_ssa_def *raw = unpacked;
 
-                        return d.size == 32 ?
-                                pan_replicate(b, unpacked, desc->nr_channels) :
-                                pan_pack_pure_16(b, unpacked, desc->nr_channels);
-                } else if (d.size == 8) {
-                        assert(d.pure_integer);
-                        return pan_pack_pure_8(b, unpacked, desc->nr_channels);
-                } else {
+                /* Normalized formats get normalized first */
+                if (d.normalized) {
+                        bool snorm = desc->is_snorm;
+                        float multiplier = norm_scale(snorm, d.size);
+                        nir_ssa_def *clamped = pan_fsat(b, unpacked, snorm);
+                        nir_ssa_def *normed = nir_fmul_imm(b, clamped, multiplier);
+
+                        raw = nir_f2uN(b, normed, d.size);
+                }
+
+                /* Pack the raw format */
+                switch (d.size) {
+                case 32:
+                        return pan_replicate(b, raw, desc->nr_channels);
+                case 16:
+                        return pan_pack_pure_16(b, raw, desc->nr_channels);
+                case 8:
+                        return pan_pack_pure_8(b, raw, desc->nr_channels);
+                default:
                         unreachable("Unrenderable size");
                 }
         }