From: Dave Airlie Date: Thu, 9 Jun 2022 20:51:16 +0000 (+1000) Subject: nvk: move to new command stream generator. X-Git-Tag: upstream/23.3.3~4565 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4cd3d74136e22e22ece74299659829ac858486ad;p=platform%2Fupstream%2Fmesa.git nvk: move to new command stream generator. This auto generates macros/inlines/structs from the nvidia class headers using a python for noobs script v2: use argparse. Part-of: --- diff --git a/src/nouveau/nvidia-headers/class_parser.py b/src/nouveau/nvidia-headers/class_parser.py new file mode 100644 index 0000000..fa6636d --- /dev/null +++ b/src/nouveau/nvidia-headers/class_parser.py @@ -0,0 +1,151 @@ +#! /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() diff --git a/src/nouveau/nvidia-headers/meson.build b/src/nouveau/nvidia-headers/meson.build index 8575043..d0febf2 100644 --- a/src/nouveau/nvidia-headers/meson.build +++ b/src/nouveau/nvidia-headers/meson.build @@ -1,3 +1,25 @@ 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 diff --git a/src/nouveau/vulkan/meson.build b/src/nouveau/vulkan/meson.build index 9c26a11..7b0d6aa 100644 --- a/src/nouveau/vulkan/meson.build +++ b/src/nouveau/vulkan/meson.build @@ -79,6 +79,7 @@ libvulkan_nouveau = shared_library( 'vulkan_nouveau', [ nvk_entrypoints, + cl_generated, nvk_files, ], include_directories : [ diff --git a/src/nouveau/vulkan/nvk_private.h b/src/nouveau/vulkan/nvk_private.h index 6224192..ff005d2 100644 --- a/src/nouveau/vulkan/nvk_private.h +++ b/src/nouveau/vulkan/nvk_private.h @@ -1,6 +1,8 @@ #ifndef NVK_PRIVATE_H #define NVK_PRIVATE_H 1 +#include + #include "nvk_entrypoints.h" #include "util/log.h" diff --git a/src/nouveau/winsys/nouveau_push.h b/src/nouveau/winsys/nouveau_push.h index dbf9f82..c06b084 100644 --- a/src/nouveau/winsys/nouveau_push.h +++ b/src/nouveau/winsys/nouveau_push.h @@ -21,6 +21,8 @@ struct nouveau_ws_push { 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); @@ -325,4 +327,141 @@ void nouveau_ws_push_reset(struct nouveau_ws_push *); #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