[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.
This commit is contained in:
Bill Currie 2025-02-17 12:53:55 +09:00
parent 67003c146a
commit 151efa5ad7
3 changed files with 112 additions and 174 deletions

View file

@ -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),

View file

@ -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);

View file

@ -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;
}