mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 13:11:00 +00:00
[qfcc] Implement specialization constants
And they even pass validation (though it turns out there's a bug in glslangValidator regarding specialization constants with expressions (or possibly spirv-val, but it seems to be the former as my bug report shows signs of activity in that direction)). https://github.com/KhronosGroup/glslang/issues/3748
This commit is contained in:
parent
a7639a685e
commit
56f8e19f63
6 changed files with 101 additions and 17 deletions
|
@ -218,6 +218,7 @@ typedef struct ex_value_s {
|
|||
const type_t *type;
|
||||
etype_t lltype;
|
||||
unsigned id;
|
||||
bool is_constexpr;
|
||||
union {
|
||||
uint8_t raw_value; ///< for memcpy
|
||||
const char *string_val; ///< string constant
|
||||
|
|
|
@ -65,6 +65,7 @@ typedef struct symbol_s {
|
|||
vis_t visibility; ///< symbol visiblity. defaults to public
|
||||
const char *name; ///< symbol name
|
||||
sy_type_e sy_type; ///< symbol type
|
||||
unsigned id;
|
||||
const struct type_s *type; ///< type of object to which symbol refers
|
||||
struct param_s *params; ///< the parameters if a function
|
||||
bool no_auto_init:1; ///< skip for non-designated initializers
|
||||
|
|
|
@ -43,6 +43,7 @@ struct type_s;
|
|||
struct pr_type_s;
|
||||
struct operand_s;
|
||||
|
||||
struct ex_value_s *new_value (void);
|
||||
struct ex_value_s *new_string_val (const char *string_val);
|
||||
struct ex_value_s *new_double_val (double double_val);
|
||||
struct ex_value_s *new_float_val (float float_val);
|
||||
|
|
|
@ -83,6 +83,16 @@ glsl_layout_constant_id (specifier_t spec, const expr_t *qual_name,
|
|||
spec.sym->sy_type = sy_expr;
|
||||
spec.sym->expr = expr;
|
||||
}
|
||||
if (spec.sym->sy_type == sy_expr && spec.sym->expr->type == ex_value) {
|
||||
auto value = new_value ();
|
||||
*value = *spec.sym->expr->value;
|
||||
value->is_constexpr = true;
|
||||
spec.sym->expr = new_value_expr (value, false);
|
||||
} else {
|
||||
error (spec.sym->expr,
|
||||
"specialization constant must be a scalar literal");
|
||||
return;
|
||||
}
|
||||
spec.sym->is_constexpr = true;
|
||||
const char *name = expr_string (qual_name);
|
||||
set_attribute (&spec.sym->attributes, name, val);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "QF/quakeio.h"
|
||||
|
||||
#include "tools/qfcc/include/attribute.h"
|
||||
#include "tools/qfcc/include/def.h"
|
||||
#include "tools/qfcc/include/defspace.h"
|
||||
#include "tools/qfcc/include/diagnostic.h"
|
||||
|
@ -50,6 +51,7 @@ typedef struct spirvctx_s {
|
|||
defspace_t *linkage;
|
||||
defspace_t *strings;
|
||||
defspace_t *names;
|
||||
defspace_t *annotations;
|
||||
defspace_t *types;
|
||||
defspace_t *code;
|
||||
struct DARRAY_TYPE (unsigned) type_ids;
|
||||
|
@ -143,6 +145,22 @@ spirv_Name (unsigned id, const char *name, spirvctx_t *ctx)
|
|||
memcpy (&D_var_o(int, def, 2), name, len);
|
||||
}
|
||||
|
||||
static void
|
||||
spirv_Decorate (unsigned id, SpvDecoration decoration, void *literal,
|
||||
etype_t type, spirvctx_t *ctx)
|
||||
{
|
||||
if (type != ev_int) {
|
||||
internal_error (0, "unexpected type");
|
||||
}
|
||||
int size = pr_type_size[type];
|
||||
auto def = spirv_new_insn (SpvOpDecorate, 3 + size, ctx->annotations);
|
||||
D_var_o(int, def, 1) = id;
|
||||
D_var_o(int, def, 2) = decoration;
|
||||
if (type == ev_int) {
|
||||
D_var_o(int, def, 3) = *(int *)literal;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spirv_MemberName (unsigned id, unsigned member, const char *name,
|
||||
spirvctx_t *ctx)
|
||||
|
@ -571,11 +589,19 @@ spirv_uexpr (const expr_t *e, spirvctx_t *ctx)
|
|||
unsigned uid = spirv_emit_expr (e->expr.e1, ctx);
|
||||
|
||||
unsigned tid = type_id (get_type (e), ctx);
|
||||
auto def = spirv_new_insn (spv_op->op, 4, ctx->types);
|
||||
unsigned id;
|
||||
D_var_o(int, def, 1) = tid;
|
||||
D_var_o(int, def, 2) = id = spirv_id (ctx);
|
||||
D_var_o(int, def, 3) = uid;
|
||||
if (e->expr.constant) {
|
||||
auto def = spirv_new_insn (SpvOpSpecConstantOp, 5, ctx->types);
|
||||
D_var_o(int, def, 1) = tid;
|
||||
D_var_o(int, def, 2) = id = spirv_id (ctx);
|
||||
D_var_o(int, def, 3) = spv_op->op;
|
||||
D_var_o(int, def, 4) = uid;
|
||||
} else {
|
||||
auto def = spirv_new_insn (spv_op->op, 4, ctx->types);
|
||||
D_var_o(int, def, 1) = tid;
|
||||
D_var_o(int, def, 2) = id = spirv_id (ctx);
|
||||
D_var_o(int, def, 3) = uid;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -603,15 +629,48 @@ spirv_expr (const expr_t *e, spirvctx_t *ctx)
|
|||
unsigned bid2 = spirv_emit_expr (e->expr.e2, ctx);
|
||||
|
||||
unsigned tid = type_id (get_type (e), ctx);
|
||||
auto def = spirv_new_insn (spv_op->op, 5, ctx->types);
|
||||
unsigned id;
|
||||
D_var_o(int, def, 1) = tid;
|
||||
D_var_o(int, def, 2) = id = spirv_id (ctx);
|
||||
D_var_o(int, def, 3) = bid1;
|
||||
D_var_o(int, def, 4) = bid2;
|
||||
if (e->expr.constant) {
|
||||
auto def = spirv_new_insn (SpvOpSpecConstantOp, 6, ctx->types);
|
||||
D_var_o(int, def, 1) = tid;
|
||||
D_var_o(int, def, 2) = id = spirv_id (ctx);
|
||||
D_var_o(int, def, 3) = spv_op->op;
|
||||
D_var_o(int, def, 4) = bid1;
|
||||
D_var_o(int, def, 5) = bid2;
|
||||
} else {
|
||||
auto def = spirv_new_insn (spv_op->op, 5, ctx->types);
|
||||
D_var_o(int, def, 1) = tid;
|
||||
D_var_o(int, def, 2) = id = spirv_id (ctx);
|
||||
D_var_o(int, def, 3) = bid1;
|
||||
D_var_o(int, def, 4) = bid2;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
spirv_symbol (const expr_t *e, spirvctx_t *ctx)
|
||||
{
|
||||
auto sym = e->symbol;
|
||||
if (sym->id) {
|
||||
return sym->id;
|
||||
}
|
||||
if (sym->sy_type == sy_expr) {
|
||||
sym->id = spirv_emit_expr (sym->expr, ctx);
|
||||
spirv_Name (sym->id, sym->name, ctx);
|
||||
for (auto attr = sym->attributes; attr; attr = attr->next) {
|
||||
if (strcmp (attr->name, "constant_id") == 0) {
|
||||
int specid = expr_integral (attr->params);
|
||||
spirv_Decorate (sym->id, SpvDecorationSpecId,
|
||||
&specid, ev_int, ctx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
internal_error (e, "unexpected symbol type: %s for %s",
|
||||
symtype_str (sym->sy_type), sym->name);
|
||||
}
|
||||
return sym->id;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
spirv_value (const expr_t *e, spirvctx_t *ctx)
|
||||
{
|
||||
|
@ -635,14 +694,23 @@ spirv_value (const expr_t *e, spirvctx_t *ctx)
|
|||
internal_error (e, "not implemented");
|
||||
}
|
||||
}
|
||||
auto def = spirv_new_insn (op, 3 + val_size, ctx->types);
|
||||
D_var_o(int, def, 1) = tid;
|
||||
D_var_o(int, def, 2) = value->id = spirv_id (ctx);
|
||||
if (val_size > 0) {
|
||||
D_var_o(int, def, 3) = val;
|
||||
if (value->is_constexpr) {
|
||||
op += SpvOpSpecConstantTrue - SpvOpConstantTrue;
|
||||
}
|
||||
if (val_size > 1) {
|
||||
D_var_o(int, def, 4) = val >> 32;
|
||||
if (op == SpvOpConstant && !val) {
|
||||
auto def = spirv_new_insn (SpvOpConstantNull, 3, ctx->types);
|
||||
D_var_o(int, def, 1) = tid;
|
||||
D_var_o(int, def, 2) = value->id = spirv_id (ctx);
|
||||
} else {
|
||||
auto def = spirv_new_insn (op, 3 + val_size, ctx->types);
|
||||
D_var_o(int, def, 1) = tid;
|
||||
D_var_o(int, def, 2) = value->id = spirv_id (ctx);
|
||||
if (val_size > 0) {
|
||||
D_var_o(int, def, 3) = val;
|
||||
}
|
||||
if (val_size > 1) {
|
||||
D_var_o(int, def, 4) = val >> 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value->id;
|
||||
|
@ -654,6 +722,7 @@ spirv_emit_expr (const expr_t *e, spirvctx_t *ctx)
|
|||
static spirv_expr_f funcs[ex_count] = {
|
||||
[ex_expr] = spirv_expr,
|
||||
[ex_uexpr] = spirv_uexpr,
|
||||
[ex_symbol] = spirv_symbol,
|
||||
[ex_value] = spirv_value,
|
||||
};
|
||||
|
||||
|
@ -681,6 +750,7 @@ spirv_write (struct pr_info_s *pr, const char *filename)
|
|||
.linkage = defspace_new (ds_backed),
|
||||
.strings = defspace_new (ds_backed),
|
||||
.names = defspace_new (ds_backed),
|
||||
.annotations = defspace_new (ds_backed),
|
||||
.types = defspace_new (ds_backed),
|
||||
.code = defspace_new (ds_backed),
|
||||
.type_ids = DARRAY_STATIC_INIT (64),
|
||||
|
@ -733,6 +803,7 @@ spirv_write (struct pr_info_s *pr, const char *filename)
|
|||
defspace_add_data (ctx.space, ctx.linkage->data, ctx.linkage->size);
|
||||
defspace_add_data (ctx.space, ctx.strings->data, ctx.strings->size);
|
||||
defspace_add_data (ctx.space, ctx.names->data, ctx.names->size);
|
||||
defspace_add_data (ctx.space, ctx.annotations->data, ctx.annotations->size);
|
||||
defspace_add_data (ctx.space, ctx.types->data, ctx.types->size);
|
||||
defspace_add_data (ctx.space, ctx.code->data, ctx.code->size);
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ value_compare (const void *_val1, const void *_val2, void *unused)
|
|||
return memcmp (&val1->raw_value, &val2->raw_value, value_size) == 0;
|
||||
}
|
||||
|
||||
static ex_value_t *
|
||||
ex_value_t *
|
||||
new_value (void)
|
||||
{
|
||||
ex_value_t *value;
|
||||
|
|
Loading…
Reference in a new issue