From a4acfc30d783bce92231e1966828b8f4c2a8c5aa Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 18 Jan 2025 11:59:05 +0900 Subject: [PATCH] [qfcc] Implement shadow coord/comp extraction This took sorting out a few issues with type property evaluation, but it seems to work nicely now. Just one known error to sort out and then it's time to get the spir-v correct. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/expr_process.c | 2 +- tools/qfcc/source/expr_type.c | 27 ++++++++++---- tools/qfcc/source/glsl-builtins.c | 60 +++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 7 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 85aa3196e..dfc2fa911 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -1166,6 +1166,7 @@ void decl_process (const expr_t *expr, rua_ctx_t *ctx); const expr_t *expr_process (const expr_t *expr, rua_ctx_t *ctx); specifier_t spec_process (specifier_t spec, rua_ctx_t *ctx); bool can_inline (const expr_t *expr, symbol_t *fsym); +bool proc_do_list (ex_list_t *out, const ex_list_t *in, rua_ctx_t *ctx); ///@} diff --git a/tools/qfcc/source/expr_process.c b/tools/qfcc/source/expr_process.c index 92f5f210a..f53364a97 100644 --- a/tools/qfcc/source/expr_process.c +++ b/tools/qfcc/source/expr_process.c @@ -405,7 +405,7 @@ proc_symbol (const expr_t *expr, rua_ctx_t *ctx) return error (expr, "undefined symbol `%s`", expr->symbol->name); } -static bool +bool proc_do_list (ex_list_t *out, const ex_list_t *in, rua_ctx_t *ctx) { int count = list_count (in); diff --git a/tools/qfcc/source/expr_type.c b/tools/qfcc/source/expr_type.c index 55ea19cb6..01361e767 100644 --- a/tools/qfcc/source/expr_type.c +++ b/tools/qfcc/source/expr_type.c @@ -198,8 +198,20 @@ evaluate_property (int arg_count, const expr_t **args, rua_ctx_t *ctx) if (!type->property) { return error (args[0], "type doesn't support properties"); } else { - auto e = type->property (type, args[1]->typ.property); - if (!is_error (e)) { + auto property = args[1]->typ.property; + if (property->params) { + scoped_src_loc (property->params); + auto params = new_list_expr (nullptr); + if (!proc_do_list (¶ms->list, &property->params->list, + ctx)) { + return nullptr; + } + auto prop = new_type_expr (nullptr); + property = new_attrfunc (property->name, params); + args[1] = prop; + } + auto e = type->property (type, property); + if (e->type == ex_type) { e = eval_type (e, ctx); } return e; @@ -873,10 +885,7 @@ process_type (const expr_t *te, rua_ctx_t *ctx) int arg_count = list_count (&te->typ.params->list); const expr_t *args[arg_count]; list_scatter (&te->typ.params->list, args); - if (type_funcs[op].resolve) { - auto type = type_funcs[op].resolve (arg_count, args, ctx); - return new_type_expr (type); - } else if (type_funcs[op].evaluate) { + if (type_funcs[op].evaluate) { return type_funcs[op].evaluate (arg_count, args, ctx); } else { internal_error (te, "invalid type op: %s", type_funcs[op].name); @@ -920,6 +929,12 @@ eval_type (const expr_t *te, rua_ctx_t *ctx) internal_error (te, "not a type expression"); } unsigned op = te->typ.op; + if (op == 0) { + if (!te->typ.type) { + internal_error (te, "type ref with no type"); + } + return te; + } if (op >= sizeof (type_funcs) / sizeof (type_funcs[0]) || !type_funcs[op].name) { internal_error (te, "invalid type op: %d", op); diff --git a/tools/qfcc/source/glsl-builtins.c b/tools/qfcc/source/glsl-builtins.c index 1ab965fd5..a497c3c49 100644 --- a/tools/qfcc/source/glsl-builtins.c +++ b/tools/qfcc/source/glsl-builtins.c @@ -66,6 +66,24 @@ static struct_def_t glsl_sampled_image_struct[] = { static int dim_widths[7] = { 1, 2, 3, 3, 2, 1, 0 }; static int size_widths[7] = { 1, 2, 3, 2, 2, 1, 0 }; static int shadow_widths[7] = { 3, 3, 0, 4, 3, 0, 0 }; +static const char *shadow_swizzle[7][2] = { + { "x", "xy" }, + { "xy", "xyz" }, + {}, + { "xyz", "xyzw" }, + { "xy", "xyz" }, + {}, + {}, +}; +static const char *shadow_comp_swizzle[7][2] = { + { "z", "z" }, // glsl braindeadery for 1d (non-arrayed) images + { "z", "w" }, + {}, + { "w", "" }, // cubemap array shadows get comp from a param + { "z", "w" }, + {}, + {}, +}; static const expr_t * image_property (const type_t *type, const attribute_t *property) @@ -103,6 +121,33 @@ image_property (const type_t *type, const attribute_t *property) return error (0, "no property %s on %s", property->name, type->name + 4); } +static const expr_t * +sampled_shadow_swizzle (const attribute_t *property, const char *swizzle[7][2], + glsl_image_t *image) +{ + int count = list_count (&property->params->list); + if (count != 1) { + return error (property->params, "wrong number of params"); + } + const expr_t *params[count]; + list_scatter (&property->params->list, params); + const char *swiz = swizzle[image->dim][image->arrayed]; + if (!swiz) { + return error (property->params, "image does not support" + " shadow sampling"); + } + if (!swiz[0]) { + // cube map array + return error (property->params, "cube map array shadow compare is not" + " in the coordinate vector"); + } + if (strcmp (swiz, "xyzw") == 0) { + // no-op swizzle + return params[0]; + } + return new_swizzle_expr (params[0], swiz); +} + static const expr_t * sampled_image_property (const type_t *type, const attribute_t *property) { @@ -123,6 +168,21 @@ sampled_image_property (const type_t *type, const attribute_t *property) return new_type_expr (vector_type (&type_float, width)); } else if (strcmp (property->name, "shadow_coord") == 0) { if (property->params) { + return sampled_shadow_swizzle (property, shadow_swizzle, image); + } else { + int width = shadow_widths[image->dim]; + if (!image->depth || !width) { + return new_type_expr (&type_void); + } + if (image->dim == glid_2d) { + width += image->arrayed; + } + return new_type_expr (vector_type (&type_float, width)); + } + } else if (strcmp (property->name, "comp") == 0) { + if (property->params) { + return sampled_shadow_swizzle (property, shadow_comp_swizzle, + image); } else { int width = shadow_widths[image->dim]; if (!image->depth || !width) {