--- /dev/null
+#! /usr/bin/env python3
+
+# script to parse nvidia CL headers and generate inlines to be used in pushbuffer encoding.
+# probably needs python3.9
+
+import argparse
+import sys
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--out_h', required=True, help='Output C header.')
+parser.add_argument('--in_h',
+ help='Input class header file.',
+ required=True)
+args = parser.parse_args()
+
+filein = args.in_h
+fileout = args.out_h
+
+if (filein.strip == ""):
+ print("class_parser.py class.h output.h")
+ sys.exit()
+
+nvcl = filein.split("/")[-1]
+clheader = nvcl
+nvcl = nvcl.removeprefix("cl")
+nvcl = nvcl.removesuffix(".h")
+nvcl = nvcl.upper()
+
+nvcl = "NV" + nvcl
+
+f = open(filein)
+
+fout = open(fileout, 'w')
+
+class method(object):
+ pass
+
+# Simple state machine
+# state 0 looking for a new method define
+# state 1 looking for new fields in a method
+# state 2 looking for enums for a fields in a method
+# blank lines reset the state machine to 0
+
+state = 0
+mthddict = {}
+for line in f:
+
+ if line.strip() == "":
+ state = 0
+ curmthd = {}
+ continue
+
+ if line.startswith("#define"):
+ list = line.split();
+ if "_cl_" in list[1]:
+ continue
+
+ if not list[1].startswith(nvcl):
+ continue
+
+ if state == 2:
+ teststr = nvcl + "_" + curmthd.name + "_" + curfield + "_"
+ if ":" in list[2]:
+ state = 1
+ elif teststr in list[1]:
+ curmthd.field_defs[curfield][list[1].removeprefix(teststr)] = list[2]
+ else:
+ state = 1
+
+ if state == 1:
+ teststr = nvcl + "_" + curmthd.name + "_"
+ if teststr in list[1]:
+ if ("0x" in list[2]):
+ state = 1
+ else:
+ field = list[1].removeprefix(teststr)
+ bitfield = list[2].split(":")
+ curmthd.field_name_start[field] = bitfield[1]
+ curmthd.field_name_end[field] = bitfield[0]
+ curmthd.field_defs[field] = {}
+ curfield = field
+ state = 2
+ else:
+ state = 0
+
+ if state == 0:
+ teststr = nvcl + "_"
+ is_array = 0
+ name = list[1].removeprefix(teststr)
+ if name.endswith("(i)"):
+ is_array = 1
+ name = name.removesuffix("(i)")
+ if name.endswith("(j)"):
+ is_array = 1
+ name = name.removesuffix("(j)")
+ x = method()
+ x.name = name
+ x.addr = list[2]
+ x.is_array = is_array
+ x.field_name_start = {}
+ x.field_name_end = {}
+ x.field_defs = {}
+ mthddict[x.name] = x
+
+ curmthd = x
+ state = 1
+
+sys.stdout = fout
+print("/* parsed class " + nvcl + " */")
+
+print("#include \"" + clheader + "\"")
+for mthd in mthddict:
+ structname = "nv_" + nvcl.lower() + "_" + mthd
+ print("struct " + structname + " {")
+ for field_name in mthddict[mthd].field_name_start:
+ print("\tuint32_t " + field_name.lower() + ";")
+ print("};")
+ print("static inline void __" + nvcl.strip() + "_" + mthd + "(uint32_t *val_out, struct " + structname + " st" + ") {")
+ print("\tuint32_t val = 0;")
+ for field_name in mthddict[mthd].field_name_start:
+ field_width = int(mthddict[mthd].field_name_end[field_name]) - int(mthddict[mthd].field_name_start[field_name]) + 1
+ if (field_width == 32):
+ print("\tval |= st." + field_name.lower() + ";")
+ else:
+ print("\tassert(st." + field_name.lower() + " < (1ULL << " + str(field_width) + "));")
+ print("\tval |= (st." + field_name.lower() + " & ((1ULL << " + str(field_width) + ") - 1)) << " + mthddict[mthd].field_name_start[field_name] + ";");
+ print("\t*val_out = val;");
+ print("}")
+ print("#define V_" + nvcl + "_" + mthd + "(val, args...) { \\")
+ for field_name in mthddict[mthd].field_name_start:
+ if len(mthddict[mthd].field_defs[field_name]):
+ for d in mthddict[mthd].field_defs[field_name]:
+ print("UNUSED uint32_t " + field_name + "_" + d + " = " + nvcl + "_" + mthd + "_" + field_name + "_" + d+"; \\")
+ if len(mthddict[mthd].field_name_start) > 1:
+ print("\tstruct " + structname + " __data = args; \\")
+ else:
+ print("\tstruct " + structname + " __data = { ." + next(iter(mthddict[mthd].field_name_start)).lower() + " = (args) }; \\")
+ print("\t__" + nvcl.strip() + "_" + mthd + "(&val, __data); \\")
+ print("\t}")
+ print("#define P_" + nvcl + "_" + mthd + "(push, " + ("idx, " if mthddict[mthd].is_array else "") + "args...) do { \\")
+ for field_name in mthddict[mthd].field_name_start:
+ if len(mthddict[mthd].field_defs[field_name]):
+ for d in mthddict[mthd].field_defs[field_name]:
+ print("UNUSED uint32_t " + field_name + "_" + d + " = " + nvcl + "_" + mthd + "_" + field_name + "_" + d+"; \\")
+ print("\tuint32_t nvk_p_ret;\\")
+ print("\tV_" + nvcl + "_" + mthd + "(nvk_p_ret, args)\\");
+ print("\tnvk_push_val(push, " + nvcl + "_" + mthd + ("(idx), " if mthddict[mthd].is_array else ",") + " nvk_p_ret);\\");
+ print("\t} while(0)")
+
+fout.close()
+f.close()
idep_nvidia_headers = declare_dependency(
- include_directories : include_directories('.')
+ include_directories : include_directories('.', 'classes')
)
+
+nvk_classes = [
+ 'cl902d',
+ 'cl90b5',
+ 'cla0b5',
+ 'clc1b5',
+]
+
+nvk_cl_header_depend_files = [
+ files('class_parser.py')
+]
+
+cl_generated = []
+foreach cl : nvk_classes
+ cl_generated += custom_target(
+ cl + '.h',
+ input : ['class_parser.py', 'classes/'+cl+'.h'],
+ output : 'nvk_'+cl+'.h',
+ command : [prog_python, '@INPUT0@', '--in_h', '@INPUT1@', '--out_h', '@OUTPUT0@'],
+ depend_files: nvk_cl_header_depend_files,
+ )
+endforeach
'vulkan_nouveau',
[
nvk_entrypoints,
+ cl_generated,
nvk_files,
],
include_directories : [
#ifndef NVK_PRIVATE_H
#define NVK_PRIVATE_H 1
+#include <assert.h>
+
#include "nvk_entrypoints.h"
#include "util/log.h"
uint32_t *orig_map;
uint32_t *map;
uint32_t *end;
+
+ uint32_t *last_size;
};
struct nouveau_ws_push *nouveau_ws_push_new(struct nouveau_ws_device *, uint64_t size);
#define PUSH_1INC(A...) PUSH_NV(NV1I, ##A)
#define PUSH_NINC(A...) PUSH_NV(NVNI, ##A)
+#define SUBC_NV902D 3
+
+#define SUBC_NV90B5 4
+
+static inline uint32_t
+NVC0_FIFO_PKHDR_SQ(int subc, int mthd, unsigned size)
+{
+ return 0x20000000 | (size << 16) | (subc << 13) | (mthd >> 2);
+}
+
+static inline void
+__push_mthd(struct nouveau_ws_push *push, int subc, uint32_t mthd)
+{
+ push->last_size = push->map;
+ *push->map = NVC0_FIFO_PKHDR_SQ(subc, mthd, 0);
+ push->map++;
+}
+
+#define P_MTHD(push, class, mthd) __push_mthd(push, SUBC_##class, class##_##mthd)
+
+static inline uint32_t
+NVC0_FIFO_PKHDR_IL(int subc, int mthd, uint16_t data)
+{
+ assert(data < 0x2000);
+ return 0x80000000 | (data << 16) | (subc << 13) | (mthd >> 2);
+}
+
+static inline void
+__push_immd(struct nouveau_ws_push *push, int subc, uint32_t mthd, uint32_t val)
+{
+ push->last_size = push->map;
+ *push->map = NVC0_FIFO_PKHDR_IL(subc, mthd, val);
+ push->map++;
+}
+
+#define P_IMMD(push, class, mthd, args...) do {\
+ uint32_t __val; \
+ V_##class##_##mthd(__val, args); \
+ __push_immd(push, SUBC_##class, class##_##mthd, __val); \
+ } while(0)
+
+static inline uint32_t
+NVC0_FIFO_PKHDR_1I(int subc, int mthd, unsigned size)
+{
+ return 0xa0000000 | (size << 16) | (subc << 13) | (mthd >> 2);
+}
+
+static inline void
+__push_1inc(struct nouveau_ws_push *push, int subc, uint32_t mthd)
+{
+ push->last_size = push->map;
+ *push->map = NVC0_FIFO_PKHDR_1I(subc, mthd, 0);
+ push->map++;
+}
+
+#define P_1INC(push, class, mthd) __push_1inc(push, SUBC_##class, class##_##mthd)
+
+static inline uint32_t
+NVC0_FIFO_PKHDR_0I(int subc, int mthd, unsigned size)
+{
+ return 0x60000000 | (size << 16) | (subc << 13) | (mthd >> 2);
+}
+
+static inline void
+__push_0inc(struct nouveau_ws_push *push, int subc, uint32_t mthd)
+{
+ push->last_size = push->map;
+ *push->map = NVC0_FIFO_PKHDR_0I(subc, mthd, 0);
+ push->map++;
+}
+
+#define P_0INC(push, class, mthd) __push_0inc(push, SUBC_##class, class##_##mthd)
+
+static inline bool
+nvk_push_update_count(struct nouveau_ws_push *push, uint16_t count)
+{
+ uint32_t last_hdr_val = *push->last_size;
+
+ assert(count <= 0x1fff);
+ if (count > 0x1fff)
+ return false;
+
+ /* size is encoded at 28:16 */
+ uint32_t new_count = (count + (last_hdr_val >> 16)) & 0x1fff;
+ bool overflow = new_count < count;
+ /* if we would overflow, don't change anything and just let it be */
+ assert(!overflow);
+ if (overflow)
+ return false;
+
+ last_hdr_val &= ~0x1fff0000;
+ last_hdr_val |= new_count << 16;
+ *push->last_size = last_hdr_val;
+ return true;
+}
+
+static inline void
+P_INLINE_DATA(struct nouveau_ws_push *push, uint32_t value)
+{
+ if (nvk_push_update_count(push, 1)) {
+ /* push new value */
+ *push->map = value;
+ push->map++;
+ }
+}
+
+static inline void
+P_INLINE_ARRAY(struct nouveau_ws_push *push, const uint32_t *data, int num_dw)
+{
+ if (nvk_push_update_count(push, num_dw)) {
+ /* push new value */
+ memcpy(push->map, data, num_dw * 4);
+ push->map += num_dw;
+ }
+}
+
+/* internally used by generated inlines. */
+static inline void
+nvk_push_val(struct nouveau_ws_push *push, uint32_t idx, uint32_t val)
+{
+ UNUSED uint32_t last_hdr_val = *push->last_size;
+ UNUSED bool is_1inc = (last_hdr_val & 0xe0000000) == 0xa0000000;
+ UNUSED bool is_immd = (last_hdr_val & 0xe0000000) == 0x80000000;
+ UNUSED uint16_t last_method = (last_hdr_val & 0x1fff) << 2;
+
+ uint16_t distance = push->map - push->last_size - 1;
+ if (is_1inc)
+ distance = MIN2(1, distance);
+ last_method += distance * 4;
+
+ /* can't have empty headers ever */
+ assert(last_hdr_val);
+ assert(!is_immd);
+ assert(last_method == idx);
+
+ P_INLINE_DATA(push, val);
+}
#endif