From 151efa5ad77afab16a6e3ce7d1ec817a8ef6d968 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2025 12:53:55 +0900 Subject: [PATCH] [qfcc] Rework interface block handling The types are built with the correct attributes before any expressions see them, so any necessary duplication is done early and guaranteed to be only once. Now my compute shaders pass spirv-val. However, other shaders are broken. But I think I know where to look. --- tools/qfcc/source/glsl-block.c | 105 +++++++++++++++++++++- tools/qfcc/source/glsl-declaration.c | 55 ++---------- tools/qfcc/source/target_spirv.c | 126 +-------------------------- 3 files changed, 112 insertions(+), 174 deletions(-) diff --git a/tools/qfcc/source/glsl-block.c b/tools/qfcc/source/glsl-block.c index 2d6bd0c9f..f7461403c 100644 --- a/tools/qfcc/source/glsl-block.c +++ b/tools/qfcc/source/glsl-block.c @@ -37,6 +37,7 @@ #include "tools/qfcc/include/defspace.h" #include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/glsl-lang.h" +#include "tools/qfcc/include/qfcc.h" #include "tools/qfcc/include/shared.h" #include "tools/qfcc/include/strpool.h" #include "tools/qfcc/include/symtab.h" @@ -127,6 +128,107 @@ glsl_create_block (specifier_t spec, symbol_t *block_sym) return block; } +static void +add_attribute (attribute_t **attributes, attribute_t *attr) +{ + attr->next = *attributes; + *attributes = attr; +} + +static const type_t * +glsl_matrix_type (const type_t *type) +{ + while (is_array (type)) { + type = dereference_type (type); + } + if (is_matrix (type)) { + return type; + } + return nullptr; +} + +static const type_t * +glsl_block_type (const type_t *type, const char *pre_tag) +{ + unsigned uint = sizeof (uint32_t); + if (is_array (type)) { + type = unalias_type (type); + auto ele_type = glsl_block_type (type->array.type, pre_tag); + type_t new = { + .type = ev_invalid, + .meta = ty_array, + .alignment = type->alignment, + .array = { + .type = ele_type, + .base = type->array.base, + .count = type->array.count, + }, + .attributes = type->attributes, + }; + int stride = type_aligned_size (ele_type) * uint; + add_attribute (&new.attributes, + new_attribute ("ArrayStride", new_uint_expr (stride))); + return find_type (&new); + } + // union not supported + if (is_struct (type)) { + type = unalias_type (type); + auto name = type->name + 4; // skip over "tag " + auto tag = name; + if (pre_tag) { + tag = save_string (va (0, "%s.%s", pre_tag, name)); + } + type_t new = { + .type = ev_invalid, + .name = save_string (va (0, "%.3s %s", type->name, tag)), + .meta = ty_struct, + .attributes = type->attributes, + }; + auto nt = find_type (&new); + if (nt->symtab) { + // already exists (multiple fields of the same struct in the + // block) + return nt; + } + ((type_t *)nt)->symtab = new_symtab (type->symtab->parent, stab_struct); + unsigned offset = 0; + int alignment = 1; + for (auto s = type->symtab->symbols; s; s = s->next) { + auto ftype = glsl_block_type (s->type, tag); + auto sym = new_symbol_type (s->name, ftype); + sym->sy_type = sy_offset; + sym->offset = -1; + sym->id = s->id; + symtab_addsymbol (nt->symtab, sym); + if (type_align (ftype) > alignment) { + alignment = type_align (ftype); + } + offset = RUP (offset, type_align (ftype) * uint); + add_attribute (&sym->attributes, + new_attribute ("Offset", new_uint_expr (offset))); + offset += type_size (ftype) * uint; + + auto mt = glsl_matrix_type (ftype); + if (mt) { + int stride = type_size (column_type (mt)) * uint; + add_attribute (&sym->attributes, + new_attribute ("MatrixStride", + new_uint_expr (stride))); + //FIXME + add_attribute (&sym->attributes, + new_attribute ("ColMajor", nullptr)); + } + } + nt->symtab->type = type->symtab->type; + nt->symtab->count = type->symtab->count; + nt->symtab->size = type->symtab->size; + nt->symtab->data = type->symtab->data; + ((type_t *)nt)->alignment = alignment; + return nt; + } + return type; +} + void glsl_finish_block (glsl_block_t *block, specifier_t spec) { @@ -169,7 +271,8 @@ glsl_declare_block_instance (glsl_block_t *block, symbol_t *instance_name) .symtab = block->members, .attributes = new_attribute ("Block", nullptr), }; - auto inst_type = find_type (&type); + auto inst_type = glsl_block_type (&type, nullptr); + block->members = inst_type->symtab; specifier_t spec = { .sym = instance_name, .storage = glsl_sc_from_iftype (block->interface), diff --git a/tools/qfcc/source/glsl-declaration.c b/tools/qfcc/source/glsl-declaration.c index ae85198a4..69d559703 100644 --- a/tools/qfcc/source/glsl-declaration.c +++ b/tools/qfcc/source/glsl-declaration.c @@ -104,59 +104,16 @@ glsl_parse_declaration (specifier_t spec, symbol_t *sym, const expr_t *init, } } -static const type_t * -glsl_block_type (const type_t *type, const char *pre_tag) -{ - if (is_array (type)) { - type = unalias_type (type); - auto ele_type = glsl_block_type (type->array.type, pre_tag); - int base = type->array.base; - int top = base + type->array.count - 1; - // calls find_type - return based_array_type (ele_type, base, top); - } - // union not supported - if (is_struct (type)) { - type = unalias_type (type); - auto name = type->name + 4; // skip over "tag " - auto tag = save_string (va (0, "%s.%s", pre_tag, name)); - type_t new = { - .type = ev_invalid, - .name = save_string (va (0, "tag %s", tag)), - .meta = ty_struct, - }; - auto nt = find_type (&new); - if (nt->symtab) { - // already exists (multiple fields of the same struct in the - // block) - return nt; - } - ((type_t *)nt)->symtab = new_symtab (type->symtab->parent, stab_struct); - for (auto s = type->symtab->symbols; s; s = s->next) { - auto ftype = glsl_block_type (s->type, tag); - auto sym = new_symbol_type (s->name, ftype); - sym->sy_type = sy_offset; - sym->offset = -1; - sym->id = s->id; - symtab_addsymbol (nt->symtab, sym); - } - nt->symtab->count = type->symtab->count; - nt->symtab->size = type->symtab->size; - return nt; - } - return type; -} - void glsl_declare_field (specifier_t spec, symtab_t *symtab, rua_ctx_t *ctx) { auto attributes = glsl_optimize_attributes (spec.attributes); - if (symtab->type == stab_block) { - spec = spec_process (spec, ctx); - spec.type = find_type (append_type (spec.sym->type, spec.type)); - spec.type = glsl_block_type (spec.type, symtab->name); - spec.sym->type = nullptr; - } + //if (symtab->type == stab_block) { + // spec = spec_process (spec, ctx); + // spec.type = find_type (append_type (spec.sym->type, spec.type)); + // spec.type = glsl_block_type (spec.type, symtab->name); + // spec.sym->type = nullptr; + //} spec.sym = declare_field (spec, symtab, ctx); spec.sym->offset = -1; glsl_apply_attributes (attributes, spec); diff --git a/tools/qfcc/source/target_spirv.c b/tools/qfcc/source/target_spirv.c index 1873eee69..bfb883335 100644 --- a/tools/qfcc/source/target_spirv.c +++ b/tools/qfcc/source/target_spirv.c @@ -461,80 +461,23 @@ spirv_type_runtime_array (unsigned tid, spirvctx_t *ctx) return id; } -static unsigned spirv_BlockType (const type_t *type, int *size, int *align, - spirvctx_t *ctx); - static unsigned -spirv_array (const type_t *type, int *size, int *align, spirvctx_t *ctx) +spirv_TypeStruct (const type_t *type, spirvctx_t *ctx) { - auto etype = dereference_type (type); - int e_size; - int e_align; - unsigned eid = spirv_BlockType (etype, &e_size, &e_align, ctx); - unsigned count = type_count (type); - - unsigned id; - if (count) { - id = spirv_type_array (eid, count, ctx); - } else { - id = spirv_type_runtime_array (eid, ctx); - count = 1; - } - e_size = RUP (e_size, e_align); - *size = e_size * count; - *align = e_align; - e_size *= sizeof (uint32_t); - spirv_DecorateLiteral (id, SpvDecorationArrayStride, &e_size, ev_int, ctx); - return id; -} - -static void -spirv_matrix_deco (const type_t *type, int id, int member, spirvctx_t *ctx) -{ - while (is_array (type)) { - type = dereference_type (type); - } - if (!is_matrix (type)) { - return; - } - int stride = type_size (column_type (type)); - stride *= sizeof (uint32_t); - spirv_MemberDecorateLiteral (id, member, SpvDecorationMatrixStride, - &stride, ev_int, ctx); - //FIXME - spirv_MemberDecorate (id, member, SpvDecorationColMajor, ctx); - -} - -static unsigned -spirv_struct (const type_t *type, int *size, int *align, spirvctx_t *ctx) -{ - bool block = size && align; auto symtab = type_symtab (type); int num_members = 0; for (auto s = symtab->symbols; s; s = s->next) { num_members++; } if (!num_members) { - *size = 0; - *align = 1; error (0, "0 sized struct"); return 0; } unsigned member_types[num_members]; - int member_sizes[num_members] = {}; - int member_align[num_members] = {}; num_members = 0; for (auto s = symtab->symbols; s; s = s->next) { int m = num_members++; - if (block) { - member_types[m] = spirv_BlockType (s->type, &member_sizes[m], - &member_align[m], ctx); - } else { - member_sizes[m] = type_size (s->type); - member_align[m] = type_align (s->type); - member_types[m] = spirv_Type (s->type, ctx); - } + member_types[m] = spirv_Type (s->type, ctx); } unsigned id = spirv_id (ctx); @@ -546,77 +489,12 @@ spirv_struct (const type_t *type, int *size, int *align, spirvctx_t *ctx) spirv_Name (id, unalias_type (type)->name + 4, ctx); - unsigned offset = 0; - unsigned total_size = 0; - int alignment = 1; int i = 0; num_members = 0; for (auto s = symtab->symbols; s; s = s->next, i++) { int m = num_members++; spirv_MemberName (id, m, s->name, ctx); spirv_member_decorate_id (id, m, s->attributes, ctx); - if (block) { - if (s->offset >= 0 && symtab->type == stab_block) { - offset = s->offset; - } - if (member_align[i] > alignment) { - alignment = member_align[i]; - } - offset = RUP (offset, member_align[i] * sizeof (uint32_t)); - spirv_MemberDecorateLiteral (id, m, SpvDecorationOffset, - &offset, ev_int, ctx); - offset += member_sizes[i] * sizeof (uint32_t); - if (offset > total_size) { - total_size = offset; - } - - spirv_matrix_deco (s->type, id, m, ctx); - } - } - if (block) { - total_size = RUP (total_size, alignment * sizeof (uint32_t)); - if (symtab->type != stab_block) { - total_size /= sizeof (uint32_t); - } - *size = total_size; - *align = alignment; - } - return id; -} - -static unsigned -spirv_BlockType (const type_t *type, int *size, int *align, spirvctx_t *ctx) -{ - if (is_structural (type)) { - unsigned id; - if (is_array (type)) { - id = spirv_array (type, size, align, ctx); - } else { - // struct or union, but union not allowed - id = spirv_struct (type, size, align, ctx); - } - spirv_add_type_id (type, id, ctx); - return id; - } else { - // non-aggregate, non-matrix type, so no need for special handling - *size = type_size (type); - *align = type_align (type); - return spirv_Type (type, ctx); - } -} - -static unsigned -spirv_TypeStruct (const type_t *type, spirvctx_t *ctx) -{ - auto symtab = type_symtab (type); - bool block = symtab->type == stab_block; - - unsigned id; - if (block) { - int size, align; - id = spirv_struct (type, &size, &align, ctx); - } else { - id = spirv_struct (type, nullptr, nullptr, ctx); } return id; }