Mesa (main): pvr: csbgen: Add *_unpack() functions for all generated struct types

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Jun 8 09:22:03 UTC 2022


Module: Mesa
Branch: main
Commit: 7c615b4103819e7c71e000b42f4821def70e780b
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=7c615b4103819e7c71e000b42f4821def70e780b

Author: Matt Coster <matt.coster at imgtec.com>
Date:   Thu May 12 12:00:44 2022 +0100

pvr: csbgen: Add *_unpack() functions for all generated struct types

Signed-off-by: Matt Coster <matt.coster at imgtec.com>
Reviewed-by: Frank Binns <frank.binns at imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16884>

---

 src/imagination/csbgen/gen_pack_header.py      | 88 ++++++++++++++++++++++++++
 src/imagination/csbgen/pvr_packet_helpers.h    | 54 ++++++++++++++++
 src/imagination/include/hwdef/rogue_hw_utils.h |  4 ++
 src/imagination/rogue/rogue_build_data.c       |  2 +
 src/imagination/vulkan/pvr_csb.h               |  3 +
 5 files changed, 151 insertions(+)

diff --git a/src/imagination/csbgen/gen_pack_header.py b/src/imagination/csbgen/gen_pack_header.py
index 9a932c45244..1261837c078 100644
--- a/src/imagination/csbgen/gen_pack_header.py
+++ b/src/imagination/csbgen/gen_pack_header.py
@@ -200,6 +200,9 @@ class Csbgen(Node):
     def get_enum(self, enum_name: str) -> Enum:
         return self._enums[enum_name]
 
+    def get_struct(self, struct_name: str) -> Struct:
+        return self._structs[struct_name]
+
 
 class Enum(Node):
     __slots__ = ["_values"]
@@ -369,6 +372,23 @@ class Struct(Node):
 
         print("}\n")
 
+    def _emit_unpack_function(self, root: Csbgen) -> None:
+        print(textwrap.dedent("""\
+            static inline __attribute__((always_inline)) void
+            %s_unpack(__attribute__((unused)) const void * restrict src,
+                    %s__attribute__((unused)) struct %s * restrict values)
+            {""") % (self.full_name, ' ' * len(self.full_name), self.full_name))
+
+        group = Group(0, 1, self.size, self.fields)
+        dwords, length = group.collect_dwords_and_length()
+        if length:
+            # Cast src to make header C++ friendly
+            print("    const uint32_t * restrict dw = (const uint32_t * restrict) src;")
+
+        group.emit_unpack_function(root, dwords, length)
+
+        print("}\n")
+
     def emit(self, root: Csbgen) -> None:
         print("#define %-33s %6d" % (self.full_name + "_length", self.length))
 
@@ -382,6 +402,7 @@ class Struct(Node):
         print("};\n")
 
         self._emit_pack_function(root)
+        self._emit_unpack_function(root)
 
 
 class Field(Node):
@@ -839,6 +860,73 @@ class Group:
             print("    dw[%d] = %s;" % (index, v))
             print("    dw[%d] = %s >> 32;" % (index + 1, v))
 
+    def emit_unpack_function(self, root: Csbgen, dwords: t.Dict[int, Group.DWord], length: int) -> None:
+        for index in range(length):
+            # Ignore MBZ dwords
+            if index not in dwords:
+                continue
+
+            # For 64 bit dwords, we aliased the two dword entries in the dword
+            # dict it occupies. Now that we're emitting the unpack function,
+            # skip the duplicate entries.
+            dw = dwords[index]
+            if index > 0 and index - 1 in dwords and dw == dwords[index - 1]:
+                continue
+
+            # Special case: only one field and it's a struct at the beginning
+            # of the dword. In this case we unpack directly from the
+            # source. This is the only way we handle embedded structs
+            # larger than 32 bits.
+            if len(dw.fields) == 1:
+                field = dw.fields[0]
+                if root.is_known_struct(field.type) and field.start % 32 == 0:
+                    prefix = root.get_struct(field.type)
+                    print("")
+                    print("    %s_unpack(data, &dw[%d], &values->%s);" % (prefix, index, field.name))
+                    continue
+
+            dword_start = index * 32
+
+            if dw.size == 32:
+                v = "dw[%d]" % index
+            elif dw.size == 64:
+                v = "v%d" % index
+                print("    const uint%d_t %s = dw[%d] | ((uint64_t)dw[%d] << 32);" % (dw.size, v, index, index + 1))
+            else:
+                raise RuntimeError("Unsupported dword size %d" % dw.size)
+
+            # Unpack any fields of struct type first.
+            for field_index, field in enumerate(f for f in dw.fields if root.is_known_struct(f.type)):
+                prefix = root.get_struct(field.type).prefix
+                vname = "v%d_%d" % (index, field_index)
+                print("")
+                print("    uint32_t %s = __pvr_uint_unpack(%s, %d, %d);"
+                      % (vname, v, field.start - dword_start, field.end - dword_start))
+                print("    %s_unpack(data, &%s, &values->%s);" % (prefix, vname, field.name))
+
+            for field in dw.fields:
+                dword_field_start = field.start - dword_start
+                dword_field_end = field.end - dword_start
+
+                if field.type == "mbo" or root.is_known_struct(field.type):
+                    continue
+                elif field.type == "uint" or root.is_known_enum(field.type) or field.type == "bool":
+                    print("    values->%s = __pvr_uint_unpack(%s, %d, %d);"
+                          % (field.name, v, dword_field_start, dword_field_end))
+                elif field.type == "int":
+                    print("    values->%s = __pvr_sint_unpack(%s, %d, %d);"
+                          % (field.name, v, dword_field_start, dword_field_end))
+                elif field.type == "float":
+                    print("    values->%s = __pvr_float_unpack(%s);" % (field.name, v))
+                elif field.type == "offset":
+                    print("    values->%s = __pvr_offset_unpack(%s, %d, %d);"
+                          % (field.name, v, dword_field_start, dword_field_end))
+                elif field.type == "address":
+                    print("    values->%s = __pvr_address_unpack(%s, %d, %d, %d);"
+                          % (field.name, v, field.shift, dword_field_start, dword_field_end))
+                else:
+                    print("/* unhandled field %s, type %s */" % (field.name, field.type))
+
 
 class Parser:
     __slots__ = ["parser", "context", "filename"]
diff --git a/src/imagination/csbgen/pvr_packet_helpers.h b/src/imagination/csbgen/pvr_packet_helpers.h
index 9cef13265a6..ae2b5fd89b0 100644
--- a/src/imagination/csbgen/pvr_packet_helpers.h
+++ b/src/imagination/csbgen/pvr_packet_helpers.h
@@ -51,6 +51,10 @@
 #   error #define __pvr_get_address before including this file
 #endif
 
+#ifndef __pvr_make_address
+#   error #define __pvr_make_address before including this file
+#endif
+
 union __pvr_value {
    float f;
    uint32_t dw;
@@ -78,6 +82,15 @@ __pvr_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end)
    return v << start;
 }
 
+static inline __attribute__((always_inline)) uint64_t
+__pvr_uint_unpack(uint64_t packed, uint32_t start, uint32_t end)
+{
+   const int width = end - start + 1;
+   const uint64_t mask = ~0ull >> (64 - width);
+
+   return (packed >> start) & mask;
+}
+
 static inline __attribute__((always_inline)) uint64_t
 __pvr_sint(int64_t v, uint32_t start, uint32_t end)
 {
@@ -98,6 +111,15 @@ __pvr_sint(int64_t v, uint32_t start, uint32_t end)
    return (v & mask) << start;
 }
 
+static inline __attribute__((always_inline)) int64_t
+__pvr_sint_unpack(uint64_t packed, uint32_t start, uint32_t end)
+{
+   const int width = end - start + 1;
+   const uint64_t mask = ~0ull >> (64 - width);
+
+   return (int64_t)((packed >> start) & mask);
+}
+
 static inline __attribute__((always_inline)) uint64_t
 __pvr_offset(uint64_t v,
              NDEBUG_UNUSED uint32_t start,
@@ -113,6 +135,20 @@ __pvr_offset(uint64_t v,
    return v;
 }
 
+static inline __attribute__((always_inline)) uint64_t
+__pvr_offset_unpack(uint64_t packed,
+                    NDEBUG_UNUSED uint32_t start,
+                    NDEBUG_UNUSED uint32_t end)
+{
+#ifndef NDEBUG
+   uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start;
+
+   assert((packed & ~mask) == 0);
+#endif
+
+   return packed;
+}
+
 static inline __attribute__((always_inline)) uint64_t
 __pvr_address(__pvr_address_type address,
               uint32_t shift,
@@ -125,12 +161,30 @@ __pvr_address(__pvr_address_type address,
    return ((addr_u64 >> shift) << start) & mask;
 }
 
+static inline __attribute__((always_inline)) __pvr_address_type
+__pvr_address_unpack(uint64_t packed,
+                     uint32_t shift,
+                     uint32_t start,
+                     uint32_t end)
+{
+   uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start;
+   uint64_t addr_u64 = ((packed & mask) >> start) << shift;
+
+   return __pvr_make_address(addr_u64);
+}
+
 static inline __attribute__((always_inline)) uint32_t __pvr_float(float v)
 {
    __pvr_validate_value(v);
    return ((union __pvr_value){ .f = (v) }).dw;
 }
 
+static inline __attribute__((always_inline)) float
+__pvr_float_unpack(uint32_t packed)
+{
+   return ((union __pvr_value){ .dw = (packed) }).f;
+}
+
 static inline __attribute__((always_inline)) uint64_t
 __pvr_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits)
 {
diff --git a/src/imagination/include/hwdef/rogue_hw_utils.h b/src/imagination/include/hwdef/rogue_hw_utils.h
index 39e3bea0b13..db95dfce0df 100644
--- a/src/imagination/include/hwdef/rogue_hw_utils.h
+++ b/src/imagination/include/hwdef/rogue_hw_utils.h
@@ -35,10 +35,14 @@
 
 #define __pvr_address_type pvr_dev_addr_t
 #define __pvr_get_address(pvr_dev_addr) (pvr_dev_addr).addr
+/* clang-format off */
+#define __pvr_make_address(addr_u64) (pvr_dev_addr_t){ .addr = addr_u64 }
+/* clang-format on */
 
 #include "csbgen/rogue_cdm.h"
 #include "csbgen/rogue_lls.h"
 
+#undef __pvr_make_address
 #undef __pvr_get_address
 #undef __pvr_address_type
 
diff --git a/src/imagination/rogue/rogue_build_data.c b/src/imagination/rogue/rogue_build_data.c
index 010a10971dd..2eebf82f455 100644
--- a/src/imagination/rogue/rogue_build_data.c
+++ b/src/imagination/rogue/rogue_build_data.c
@@ -36,9 +36,11 @@
 
 #define __pvr_address_type uint64_t
 #define __pvr_get_address(pvr_dev_addr) (pvr_dev_addr)
+#define __pvr_make_address(addr_u64) (addr_u64)
 
 #include "csbgen/rogue_pds.h"
 
+#undef __pvr_make_address
 #undef __pvr_get_address
 #undef __pvr_address_type
 
diff --git a/src/imagination/vulkan/pvr_csb.h b/src/imagination/vulkan/pvr_csb.h
index 372c41ebd1d..500b5e1296d 100644
--- a/src/imagination/vulkan/pvr_csb.h
+++ b/src/imagination/vulkan/pvr_csb.h
@@ -42,6 +42,9 @@
 
 #define __pvr_address_type pvr_dev_addr_t
 #define __pvr_get_address(pvr_dev_addr) (pvr_dev_addr).addr
+/* clang-format off */
+#define __pvr_make_address(addr_u64) (pvr_dev_addr_t){ .addr = addr_u64 }
+/* clang-format on */
 
 #include "csbgen/rogue_hwdefs.h"
 



More information about the mesa-commit mailing list