From c16a8411bc8dca714a29b6c38fe60efce99bc29a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Nov 2024 08:33:29 +0900 Subject: [PATCH] [qfcc] Extend handles to support image types Images are just handles, but they have additional type data like dimensionality, array, etc that distinguishes between the image types. --- tools/qfcc/include/glsl-lang.h | 27 ++++++ tools/qfcc/include/struct.h | 2 + tools/qfcc/include/type.h | 6 ++ tools/qfcc/source/glsl-builtins.c | 31 +++++++ tools/qfcc/source/glsl-parse.y | 133 +++++++++++++++++++++++++++++- tools/qfcc/source/struct.c | 7 ++ 6 files changed, 203 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/include/glsl-lang.h b/tools/qfcc/include/glsl-lang.h index 5f8381609..93d594583 100644 --- a/tools/qfcc/include/glsl-lang.h +++ b/tools/qfcc/include/glsl-lang.h @@ -28,6 +28,8 @@ #ifndef __glsl_lang_h #define __glsl_lang_h +#include "QF/darray.h" + typedef struct specifier_s specifier_t; typedef struct attribute_s attribute_t; typedef struct expr_s expr_t; @@ -78,6 +80,31 @@ typedef struct glsl_block_s { symbol_t *instance_name; } glsl_block_t; +typedef enum { + glid_1d, + glid_2d, + glid_3d, + glid_cube, + glid_rect, + glid_buffer, + glid_subpassdata, +} glsl_imagedim_t; + +typedef struct glsl_image_s { + const type_t *sample_type; + glsl_imagedim_t dim; + char depth; + bool arrayed; + bool multisample; + char sampled; + unsigned format; +} glsl_image_t; + +typedef struct DARRAY_TYPE (glsl_image_t) glsl_imageset_t; +extern glsl_imageset_t glsl_imageset; +extern type_t type_glsl_image; +extern type_t type_glsl_sampler; + typedef struct glsl_sublang_s { const char *name; const char **interface_default_names; diff --git a/tools/qfcc/include/struct.h b/tools/qfcc/include/struct.h index bfc642d83..a4d02b9a4 100644 --- a/tools/qfcc/include/struct.h +++ b/tools/qfcc/include/struct.h @@ -68,4 +68,6 @@ struct def_s * emit_structure (const char *name, int su, struct_def_t *defs, struct defspace_s *space, enum storage_class_e storage); +struct symbol_s *make_handle (const char *name, type_t *type); + #endif//__struct_h diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 33d3d366e..54aac865e 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -68,6 +68,11 @@ typedef struct ty_alias_s { const struct type_s *full_type; ///< full alias chain } ty_alias_t; +typedef struct ty_handle_s { + const type_t *type; ///< descriptor for extra + unsigned extra; ///< handle for extra +} ty_handle_t; + typedef struct type_s { etype_t type; ///< ev_invalid means structure/array etc unsigned id; ///< internal id for registerd types @@ -90,6 +95,7 @@ typedef struct type_s { struct algebra_s *algebra; struct multivector_s *multivec; ty_alias_t alias; + ty_handle_t handle; }; attribute_t *attributes; struct type_s *next; diff --git a/tools/qfcc/source/glsl-builtins.c b/tools/qfcc/source/glsl-builtins.c index ef0ef2789..011517d43 100644 --- a/tools/qfcc/source/glsl-builtins.c +++ b/tools/qfcc/source/glsl-builtins.c @@ -33,6 +33,30 @@ #include "tools/qfcc/include/qfcc.h" #include "tools/qfcc/include/rua-lang.h" #include "tools/qfcc/include/spirv.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/type.h" + +glsl_imageset_t glsl_imageset = DARRAY_STATIC_INIT (16); + +static struct_def_t glsl_image_struct[] = { + {"type", &type_ptr}, + {"dim", &type_uint}, //FIXME enum + {"depth", &type_uint}, //FIXME enum + {"arrayed", &type_bool}, + {"multisample", &type_bool}, + {"sampled", &type_uint}, //FIXME enum + {"format", &type_uint}, //FIXME enum + {} +}; + +type_t type_glsl_image = { + .type = ev_invalid, + .meta = ty_struct, +}; +type_t type_glsl_sampler = { + .type = ev_int, + .meta = ty_handle, +}; #define SRC_LINE_EXP2(l,f) "#line " #l " " #f "\n" #define SRC_LINE_EXP(l,f) SRC_LINE_EXP2(l,f) @@ -921,6 +945,13 @@ glsl_init_common (void) static module_t module; //FIXME probably not what I want pr.module = &module; + make_structure ("@image", 's', glsl_image_struct, &type_glsl_image); + make_handle ("@sampler", &type_glsl_sampler); + chain_type (&type_glsl_image); + chain_type (&type_glsl_sampler); + + DARRAY_RESIZE (&glsl_imageset, 0); + spirv_set_addressing_model (pr.module, SpvAddressingModelLogical); spirv_set_memory_model (pr.module, SpvMemoryModelGLSL450); diff --git a/tools/qfcc/source/glsl-parse.y b/tools/qfcc/source/glsl-parse.y index 7e0bfc284..8b83637c2 100644 --- a/tools/qfcc/source/glsl-parse.y +++ b/tools/qfcc/source/glsl-parse.y @@ -1554,7 +1554,7 @@ static keyword_t glsl_keywords[] = { {"textureBuffer", GLSL_TYPE_SPEC}, {"itextureBuffer", GLSL_TYPE_SPEC}, {"utextureBuffer", GLSL_TYPE_SPEC}, - {"sampler", GLSL_TYPE_SPEC}, + {"sampler", GLSL_TYPE_SPEC, .spec = {.type = &type_glsl_sampler}}, {"samplerShadow", GLSL_TYPE_SPEC}, {"subpassInput", GLSL_TYPE_SPEC}, {"isubpassInput", GLSL_TYPE_SPEC}, @@ -1635,14 +1635,141 @@ glsl_directive (const char *token) return directive; } +typedef struct { + const char *substr; + int val; + const type_t *type; +} image_sub_t; + +static image_sub_t * __attribute__((pure)) +find_image_sub (image_sub_t *sub, const char *str) +{ + for (; sub->substr; sub++) { + if (strncmp (sub->substr, str, strlen(sub->substr)) == 0) { + return sub; + } + } + return nullptr; +} + +static symbol_t * +glsl_parse_image (const char *token) +{ + static image_sub_t image_type[] = { + { .substr = "sampler", .val = 0, .type = &type_float }, + { .substr = "image", .val = 1, .type = &type_float }, + { .substr = "texture", .val = 2, .type = &type_float }, + { .substr = "isampler", .val = 0, .type = &type_int }, + { .substr = "iimage", .val = 1, .type = &type_int }, + { .substr = "itexture", .val = 2, .type = &type_int }, + { .substr = "usampler", .val = 0, .type = &type_uint }, + { .substr = "uimage", .val = 1, .type = &type_uint }, + { .substr = "utexture", .val = 2, .type = &type_uint }, + { .substr = "i", .val = 1, .type = &type_int }, + { .substr = "u", .val = 1, .type = &type_uint }, + { .substr = "", .val = 1, .type = &type_float }, + // subpassInput is dimension in spir-v + {} + }; + static image_sub_t image_dim[] = { + { "2DRect", glid_rect }, // so 2D doesn't falsly match + { "1D", glid_1d }, + { "2D", glid_2d }, + { "3D", glid_3d }, + { "Cube", glid_cube }, + { "Buffer", glid_buffer }, + { "subpassInput", glid_subpassdata }, + {} + }; + static image_sub_t image_ms[] = { + { "MS", true }, + { "", false }, + {} + }; + static image_sub_t image_array[] = { + { "Array", true }, + { "", false }, + {} + }; + static image_sub_t image_shadow[] = { + { "Shadow", true }, + { "", false }, + {} + }; + + int offset = 0; + auto type = *find_image_sub (image_type, token + offset);// always succeeds + offset += strlen (type.substr); + auto dim = find_image_sub (image_dim, token + offset); + if (!dim) { + goto invalid; + } + offset += strlen (dim->substr); + if (!is_float (type.type)) { + type.substr++; // skip over type char + } + if (dim->val == glid_subpassdata) { + type.substr = dim->substr; + } + auto ms = *find_image_sub (image_ms, token + offset); + offset += strlen (ms.substr); + auto array = *find_image_sub (image_array, token + offset); + offset += strlen (array.substr); + + glsl_image_t image = { + .sample_type = type.type, + .dim = dim->val, + .depth = 0, //XXX what sets this? + .arrayed = array.val, + .multisample = ms.val, + .format = 0, //unknown (comes from layout) + }; + if (type.val == 0) { // sampler + auto shad = *find_image_sub (image_shadow, token + offset); + offset += strlen (shad.substr); + if (shad.val) { + type.substr = "samplerShadow"; + } + } + if (token[offset]) { + goto invalid; + } + + unsigned index = 0; + // slot 0 is never used + for (unsigned i = 1; i < glsl_imageset.size; i++) { + if (memcmp (&glsl_imageset.a[i], &image, sizeof (image)) == 0) { + index = i; + break; + } + } + if (!index) { + index = glsl_imageset.size; + DARRAY_APPEND (&glsl_imageset, image); + } + + auto sym = new_symbol (token); + sym = find_handle (sym, &type_int); + //FIXME the type isn't chained yet and so doesn't need to be const, but + // symbols keep the type in a const pointer. + auto t = (type_t *) sym->type; + if (t->handle.extra) { + internal_error (0, "image type handle alread set"); + } + t->handle.extra = index; + + return sym; +invalid: + internal_error (0, "invalid image type: %s", token); +} + static int glsl_process_keyword (rua_val_t *lval, keyword_t *keyword, const char *token) { if (keyword->value == GLSL_STRUCT) { lval->op = token[0]; } else if (keyword->value == GLSL_TYPE_SPEC && !keyword->spec.type) { - auto sym = new_symbol (token); - sym = find_handle (sym, &type_int); + auto sym = glsl_parse_image (token); keyword->spec.type = sym->type; lval->spec = keyword->spec; } else if (keyword->use_name) { diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 74b873970..10e0114ac 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -441,3 +441,10 @@ emit_structure (const char *name, int su, struct_def_t *defs, } return struct_def; } + +symbol_t * +make_handle (const char *name, type_t *type) +{ + auto tag = new_symbol (name); + return find_tag (ty_handle, tag, type); +}