[qfcc] Handle execution modes for spir-v/glsl

This means that `layout(triangles)` etc now work, though there are
issues with frag shaders missing functions (since getting function calls
working) and compute shaders silently failing.
This commit is contained in:
Bill Currie 2025-01-21 10:42:56 +09:00
parent 105edc5126
commit fb7025dbd3
15 changed files with 381 additions and 172 deletions

View file

@ -115,6 +115,7 @@ extern type_t type_glsl_sampled_image;
typedef struct glsl_sublang_s {
const char *name;
const char **interface_default_names;
const char *model_name;
} glsl_sublang_t;
extern glsl_sublang_t glsl_sublang;
extern glsl_sublang_t glsl_comp_sublanguage;

View file

@ -36,6 +36,7 @@
#include "tools/qfcc/include/expr.h"
typedef struct symbol_s symbol_t;
typedef struct expr_s expr_t;
typedef struct entrypoint_s {
struct entrypoint_s *next;
@ -45,12 +46,22 @@ typedef struct entrypoint_s {
ex_list_t interface; ///< list of symbols forming interface
struct DARRAY_TYPE (symbol_t *) interface_syms;
struct function_s *func;
const expr_t *invocations;
const expr_t *local_size[3];
const expr_t *primitive_in;
const expr_t *primitive_out;
const expr_t *max_vertices;
const expr_t *spacing;
const expr_t *order;
const expr_t *frag_depth;
bool point_mode;
bool early_fragment_tests;
} entrypoint_t;
typedef struct module_s {
ex_list_t capabilities;
ex_list_t extensions;
SpvExecutionModel default_model;
symtab_t *extinst_imports;
const expr_t *addressing_model;
const expr_t *memory_model;

View file

@ -100,5 +100,6 @@ const plitem_t *spirv_operand_kind (const char *set, const char *kind);
uint32_t spirv_instruction_opcode (const char *set, const expr_t *opcode);
bool spirv_setup_intrinsic_symtab (symtab_t *symtab);
uint32_t spirv_execution_model (const char *model);
#endif//__spirv_grammar_h

View file

@ -44,6 +44,8 @@ typedef struct {
symtab_t *symtab, expr_t *block);
void (*vararg_int) (const expr_t *e);
bool (*create_entry_point) (const char *name, const char *model_name);
const expr_t *(*initialized_temp) (const type_t *type, const expr_t *src);
const expr_t *(*assign_vector) (const expr_t *dst, const expr_t *src);
const expr_t *(*proc_switch) (const expr_t *expr, rua_ctx_t *ctx);

View file

@ -42,6 +42,7 @@
#include "tools/qfcc/include/rua-lang.h"
#include "tools/qfcc/include/spirv.h"
#include "tools/qfcc/include/struct.h"
#include "tools/qfcc/include/target.h"
#include "tools/qfcc/include/type.h"
glsl_sublang_t glsl_sublang;
@ -1364,6 +1365,13 @@ glsl_init_common (rua_ctx_t *ctx)
static module_t module; //FIXME probably not what I want
pr.module = &module;
spirv_set_addressing_model (pr.module, SpvAddressingModelLogical);
spirv_set_memory_model (pr.module, SpvMemoryModelGLSL450);
glsl_sublang = *(glsl_sublang_t *) ctx->language->sublanguage;
current_target.create_entry_point ("main", glsl_sublang.model_name);
make_structure ("@image", 's', glsl_image_struct, &type_glsl_image);
make_structure ("@sampled_image", 's', glsl_sampled_image_struct,
&type_glsl_sampled_image);
@ -1374,10 +1382,6 @@ glsl_init_common (rua_ctx_t *ctx)
DARRAY_RESIZE (&glsl_imageset, 0);
spirv_set_addressing_model (pr.module, SpvAddressingModelLogical);
spirv_set_memory_model (pr.module, SpvMemoryModelGLSL450);
glsl_sublang = *(glsl_sublang_t *) ctx->language->sublanguage;
ctx->language->initialized = true;
glsl_block_clear ();
rua_ctx_t rua_ctx = { .language = &lang_ruamoko };
@ -1410,8 +1414,6 @@ glsl_init_vert (rua_ctx_t *ctx)
glsl_parse_vars (glsl_Vulkan_vertex_vars, ctx);
rua_ctx_t rua_ctx = { .language = &lang_ruamoko };
qc_parse_string (glsl_other_texture_functions, &rua_ctx);
pr.module->default_model = SpvExecutionModelVertex;
}
void
@ -1423,7 +1425,6 @@ glsl_init_tesc (rua_ctx_t *ctx)
qc_parse_string (glsl_other_texture_functions, &rua_ctx);
spirv_add_capability (pr.module, SpvCapabilityTessellation);
pr.module->default_model = SpvExecutionModelTessellationControl;
}
void
@ -1435,7 +1436,6 @@ glsl_init_tese (rua_ctx_t *ctx)
qc_parse_string (glsl_other_texture_functions, &rua_ctx);
spirv_add_capability (pr.module, SpvCapabilityTessellation);
pr.module->default_model = SpvExecutionModelTessellationEvaluation;
}
void
@ -1448,7 +1448,6 @@ glsl_init_geom (rua_ctx_t *ctx)
qc_parse_string (glsl_other_texture_functions, &rua_ctx);
spirv_add_capability (pr.module, SpvCapabilityGeometry);
pr.module->default_model = SpvExecutionModelGeometry;
}
void
@ -1459,6 +1458,4 @@ glsl_init_frag (rua_ctx_t *ctx)
rua_ctx_t rua_ctx = { .language = &lang_ruamoko };
qc_parse_string (glsl_fragment_functions, &rua_ctx);
qc_parse_string (glsl_frag_texture_functions, &rua_ctx);
pr.module->default_model = SpvExecutionModelFragment;
}

View file

@ -39,21 +39,57 @@
#include "tools/qfcc/include/def.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/spirv.h"
#include "tools/qfcc/include/strpool.h"
#include "tools/qfcc/include/symtab.h"
#include "tools/qfcc/include/type.h"
#include "tools/qfcc/include/value.h"
typedef enum {
decl_var = 1 << 0,
decl_qual = 1 << 1,
decl_block = 1 << 2,
decl_member = 1 << 3,
} glsl_obj_t;
typedef enum {
var_any,
var_opaque,
var_atomic,
var_subpass,
var_scalar,
var_image,
var_gl_FragCoord,
var_gl_FragDepth,
} glsl_var_t;
typedef struct layout_qual_s layout_qual_t;
typedef struct layout_qual_s {
const char *name;
void (*apply) (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name);
void (*apply_expr) (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name, const expr_t *val);
unsigned obj_mask;
glsl_var_t var_type;
unsigned if_mask;
const char **stage_filter;
int val;
const char *accessor;
} layout_qual_t;
static void
glsl_layout_invalid_A (specifier_t spec, const expr_t *qual_name)
glsl_layout_invalid_A (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name)
{
error (qual_name, "not allowed for vulkan");
}
static void
glsl_layout_invalid_E (specifier_t spec, const expr_t *qual_name,
const expr_t *val)
glsl_layout_invalid_E (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name, const expr_t *val)
{
error (qual_name, "not allowed for vulkan");
}
@ -73,26 +109,22 @@ set_attribute (attribute_t **attributes, const char *name, const expr_t *val)
}
static void
glsl_layout_packing (specifier_t spec, const expr_t *qual_name)
glsl_layout_packing (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name)
{
}
static void
glsl_layout_location (specifier_t spec, const expr_t *qual_name,
const expr_t *val)
glsl_layout_location (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name, const expr_t *val)
{
const char *name = expr_string (qual_name);
set_attribute (&spec.sym->attributes, name, val);
}
static void
glsl_layout_geom_in_primitive (specifier_t spec, const expr_t *qual_name)
{
}
static void
glsl_layout_constant_id (specifier_t spec, const expr_t *qual_name,
const expr_t *val)
glsl_layout_constant_id (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name, const expr_t *val)
{
if (spec.sym->sy_type == sy_const) {
auto expr = new_value_expr (spec.sym->value, false);
@ -115,96 +147,107 @@ glsl_layout_constant_id (specifier_t spec, const expr_t *qual_name,
}
static void
glsl_layout_binding (specifier_t spec, const expr_t *qual_name,
const expr_t *val)
glsl_layout_binding (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name, const expr_t *val)
{
const char *name = expr_string (qual_name);
set_attribute (&spec.sym->attributes, name, val);
}
static void
glsl_layout_offset (specifier_t spec, const expr_t *qual_name,
const expr_t *val)
glsl_layout_offset (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name, const expr_t *val)
{
}
static void
glsl_layout_set (specifier_t spec, const expr_t *qual_name,
const expr_t *val)
glsl_layout_set (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name, const expr_t *val)
{
const char *name = expr_string (qual_name);
set_attribute (&spec.sym->attributes, name, val);
}
static void
glsl_layout_set_property (specifier_t spec, const expr_t *qual_name,
const expr_t *val)
{
//auto interface = glsl_iftype_from_sc (spec.storage);
//notice (qual_name, "%s %s %s", glsl_interface_names[interface],
// expr_string (qual_name), get_value_string (val->value));
}
static void
glsl_layout_geom_out_primitive (specifier_t spec, const expr_t *qual_name)
glsl_layout_format (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name)
{
}
static void
glsl_layout_geom_out_max_vertices (specifier_t spec, const expr_t *qual_name,
const expr_t *val)
glsl_layout_push_constant (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name)
{
}
static void
glsl_layout_format (specifier_t spec, const expr_t *qual_name)
glsl_layout_input_attachment_index (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name, const expr_t *val)
{
}
static void
glsl_layout_push_constant (specifier_t spec, const expr_t *qual_name)
{
}
static void
glsl_layout_input_attachment_index (specifier_t spec, const expr_t *qual_name,
const expr_t *val)
{
}
static void
glsl_layout_execution_mode (specifier_t spec, const expr_t *qual_name)
{
}
typedef enum {
decl_var = 1 << 0,
decl_qual = 1 << 1,
decl_block = 1 << 2,
decl_member = 1 << 3,
} glsl_obj_t;
typedef enum {
var_any,
var_opaque,
var_atomic,
var_subpass,
var_scalar,
var_image,
var_gl_FragCoord,
var_gl_FragDepth,
} glsl_var_t;
typedef struct layout_qual_s {
#define EP(n) {.name = #n, .offset = offsetof (entrypoint_t, n)}
#define EPF(n) {.name = #n, .offset = offsetof (entrypoint_t, n), .flag = true}
static struct {
const char *name;
void (*apply) (specifier_t spec, const expr_t *qual_name);
void (*apply_expr) (specifier_t spec, const expr_t *qual_name,
const expr_t *val);
unsigned obj_mask;
glsl_var_t var_type;
unsigned if_mask;
const char **stage_filter;
} layout_qual_t;
int offset;
bool flag;
} entrypoint_fields[] = {
EP (invocations),
EP (local_size[0]),
EP (local_size[1]),
EP (local_size[2]),
EP (primitive_in),
EP (primitive_out),
EP (max_vertices),
EP (spacing),
EP (order),
EP (frag_depth),
EPF (point_mode),
EPF (early_fragment_tests),
{}
};
#undef EP
static void
glsl_layout_exec_mode_param (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name, const expr_t *val)
{
auto entry_point = pr.module->entry_points;
if (!entry_point) {
internal_error (0, "no entry point");
}
for (auto ep = entrypoint_fields; ep->name; ep++) {
if (strcmp (ep->name, qual->accessor) == 0) {
auto val_ptr = ((byte *) entry_point + ep->offset);
if (ep->flag) {
auto flag = (bool *) val_ptr;
*flag = true;
} else {
auto expr = (const expr_t **) val_ptr;
*expr = val;
}
return;
}
}
internal_error (0, "invalid accessor: %s", qual->accessor);
}
static void
glsl_layout_exec_mode (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name)
{
auto val = new_int_expr (qual->val, false);
glsl_layout_exec_mode_param (qual, spec, qual_name, val);
}
static void
glsl_layout_ignore (const layout_qual_t *qual, specifier_t spec,
const expr_t *qual_name)
{
const char *name = expr_string (qual_name);
debug (qual_name, "ignoring %s", name);
}
#define A(a) a, nullptr
#define E(e) nullptr, e
@ -314,100 +357,130 @@ static layout_qual_t layout_qualifiers[] = {
},
{ .name = "triangles",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "tessellation evaluation", nullptr },
.val = SpvExecutionModeTriangles,
.accessor = "primitive_out",
},
{ .name = "quads",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "tessellation evaluation", nullptr },
.val = SpvExecutionModeQuads,
.accessor = "primitive_out",
},
{ .name = "isolines",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "tessellation evaluation", nullptr },
.val = SpvExecutionModeIsolines,
.accessor = "primitive_out",
},
{ .name = "equal_spacing",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "tessellation evaluation", nullptr },
.val = SpvExecutionModeSpacingEqual,
.accessor = "spacing",
},
{ .name = "fractional_even_spacing",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "tessellation evaluation", nullptr },
.val = SpvExecutionModeSpacingFractionalEven,
.accessor = "spacing",
},
{ .name = "fractional_odd_spacing",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "tessellation evaluation", nullptr },
.val = SpvExecutionModeSpacingFractionalOdd,
.accessor = "spacing",
},
{ .name = "cw",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "tessellation evaluation", nullptr },
.val = SpvExecutionModeVertexOrderCw,
.accessor = "order",
},
{ .name = "ccw",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "tessellation evaluation", nullptr },
.val = SpvExecutionModeVertexOrderCcw,
.accessor = "order",
},
{ .name = "point_mode",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "tessellation evaluation", nullptr },
.val = true,
.accessor = "point_mode",
},
{ .name = "points",
.apply = A(glsl_layout_geom_in_primitive),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in)|I(out),
.if_mask = I(in),
.stage_filter = C { "geometry", nullptr },
.val = SpvExecutionModeInputPoints,
.accessor = "primitive_in",
},
{ .name = "lines",
.apply = A(glsl_layout_geom_in_primitive),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "geometry", nullptr },
.val = SpvExecutionModeInputLines,
.accessor = "primitive_in",
},
{ .name = "lines_adjacency",
.apply = A(glsl_layout_geom_in_primitive),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "geometry", nullptr },
.val = SpvExecutionModeInputLinesAdjacency,
.accessor = "primitive_in",
},
{ .name = "triangles",
.apply = A(glsl_layout_geom_in_primitive),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "geometry", nullptr },
.val = SpvExecutionModeTriangles,
.accessor = "primitive_in",
},
{ .name = "triangles_adjacency",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "geometry", nullptr },
.val = SpvExecutionModeInputTrianglesAdjacency,
.accessor = "primitive_in",
},
{ .name = "invocations",
.apply = E(nullptr),
.apply = E(glsl_layout_exec_mode_param),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "geometry", nullptr },
.accessor = "invocations",
},
{ .name = "origin_upper_left",
.apply = A(nullptr),
.apply = A(glsl_layout_ignore),
.obj_mask = D(qual),
.var_type = V(gl_FragCoord),
.if_mask = I(in),
.stage_filter = C { "fragment", nullptr },
},
@ -418,47 +491,55 @@ static layout_qual_t layout_qualifiers[] = {
.stage_filter = C { "fragment", nullptr },
},
{ .name = "early_fragment_tests",
.apply = A(glsl_layout_execution_mode),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "fragment", nullptr },
.val = true,
.accessor = "early_fragment_tests",
},
{ .name = "local_size_x",
.apply = E(glsl_layout_set_property),
.apply = E(glsl_layout_exec_mode_param),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "compute", nullptr },
.accessor = "local_size[0]",
},
{ .name = "local_size_y",
.apply = E(glsl_layout_set_property),
.apply = E(glsl_layout_exec_mode_param),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "compute", nullptr },
.accessor = "local_size[1]",
},
{ .name = "local_size_z",
.apply = E(glsl_layout_set_property),
.apply = E(glsl_layout_exec_mode_param),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "compute", nullptr },
.accessor = "local_size[2]",
},
{ .name = "local_size_x_id",
.apply = E(glsl_layout_set_property),
.apply = E(glsl_layout_exec_mode_param),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "compute", nullptr },
.accessor = "local_size[0]",
},
{ .name = "local_size_y_id",
.apply = E(glsl_layout_set_property),
.apply = E(glsl_layout_exec_mode_param),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "compute", nullptr },
.accessor = "local_size[1]",
},
{ .name = "local_size_z_id",
.apply = E(glsl_layout_set_property),
.apply = E(glsl_layout_exec_mode_param),
.obj_mask = D(qual),
.if_mask = I(in),
.stage_filter = C { "compute", nullptr },
.accessor = "local_size[2]",
},
{ .name = "xfb_buffer",
@ -502,35 +583,43 @@ static layout_qual_t layout_qualifiers[] = {
},
{ .name = "vertices",
.apply = E(nullptr),
.apply = E(glsl_layout_exec_mode_param),
.obj_mask = D(qual),
.if_mask = I(out),
.stage_filter = C { "tessellation control", nullptr },
.accessor = "max_vertices",
},
{ .name = "points",
.apply = A(glsl_layout_geom_out_primitive),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(out),
.stage_filter = C { "geometry", nullptr },
.val = SpvExecutionModeOutputPoints,
.accessor = "primitive_out",
},
{ .name = "line_strip",
.apply = A(glsl_layout_geom_out_primitive),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(out),
.stage_filter = C { "geometry", nullptr },
.val = SpvExecutionModeOutputLineStrip,
.accessor = "primitive_out",
},
{ .name = "triangle_strip",
.apply = A(glsl_layout_geom_out_primitive),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(qual),
.if_mask = I(out),
.stage_filter = C { "geometry", nullptr },
.val = SpvExecutionModeOutputTriangleStrip,
.accessor = "primitive_out",
},
{ .name = "max_vertices",
.apply = E(glsl_layout_geom_out_max_vertices),
.apply = E(glsl_layout_exec_mode_param),
.obj_mask = D(qual),
.if_mask = I(out),
.stage_filter = C { "geometry", nullptr },
.accessor = "max_vertices",
},
{ .name = "stream",
.apply = E(nullptr),
@ -541,32 +630,40 @@ static layout_qual_t layout_qualifiers[] = {
},
{ .name = "depth_any",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(var),
.var_type = V(any),
.var_type = V(gl_FragDepth),
.if_mask = I(out),
.stage_filter = C { "fragment", nullptr },
.val = SpvExecutionModeDepthReplacing,
.accessor = "frag_depth",
},
{ .name = "depth_greater",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(var),
.var_type = V(any),
.var_type = V(gl_FragDepth),
.if_mask = I(out),
.stage_filter = C { "fragment", nullptr },
.val = SpvExecutionModeDepthGreater,
.accessor = "frag_depth",
},
{ .name = "depth_less",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(var),
.var_type = V(any),
.var_type = V(gl_FragDepth),
.if_mask = I(out),
.stage_filter = C { "fragment", nullptr },
.val = SpvExecutionModeDepthLess,
.accessor = "frag_depth",
},
{ .name = "depth_unchanged",
.apply = A(nullptr),
.apply = A(glsl_layout_exec_mode),
.obj_mask = D(var),
.var_type = V(any),
.var_type = V(gl_FragDepth),
.if_mask = I(out),
.stage_filter = C { "fragment", nullptr },
.val = SpvExecutionModeDepthUnchanged,
.accessor = "frag_depth",
},
{ .name = "constant_id",
@ -953,14 +1050,14 @@ layout_apply_qualifier (const expr_t *qualifier, specifier_t spec)
if (!val) {
error (qualifier, "%s requires a value", key.name);
} else {
qual->apply_expr (spec, qualifier->expr.e1, val);
qual->apply_expr (qual, spec, qualifier->expr.e1, val);
}
return;
} else if (qual->apply) {
if (val) {
error (qualifier, "%s does not take a value", key.name);
} else {
qual->apply (spec, qualifier->expr.e1);
qual->apply (qual, spec, qualifier->expr.e1);
}
return;
} else {

View file

@ -50,4 +50,5 @@ static const char *glsl_comp_interface_default_names[glsl_num_interfaces] = {
glsl_sublang_t glsl_comp_sublanguage = {
.name = "compute",
.interface_default_names = glsl_comp_interface_default_names,
.model_name = "GLCompute",
};

View file

@ -48,4 +48,5 @@ static const char *glsl_frag_interface_default_names[glsl_num_interfaces] = {
glsl_sublang_t glsl_frag_sublanguage = {
.name = "fragment",
.interface_default_names = glsl_frag_interface_default_names,
.model_name = "Fragment",
};

View file

@ -52,4 +52,5 @@ static const char *glsl_geom_interface_default_names[glsl_num_interfaces] = {
glsl_sublang_t glsl_geom_sublanguage = {
.name = "geometry",
.interface_default_names = glsl_geom_interface_default_names,
.model_name = "Geometry",
};

View file

@ -50,4 +50,5 @@ static const char *glsl_tesc_interface_default_names[glsl_num_interfaces] = {
glsl_sublang_t glsl_tesc_sublanguage = {
.name = "tessellation control",
.interface_default_names = glsl_tesc_interface_default_names,
.model_name = "TessellationControl",
};

View file

@ -50,4 +50,5 @@ static const char *glsl_tese_interface_default_names[glsl_num_interfaces] = {
glsl_sublang_t glsl_tese_sublanguage = {
.name = "tessellation evaluation",
.interface_default_names = glsl_tese_interface_default_names,
.model_name = "TessellationEvaluation",
};

View file

@ -50,4 +50,5 @@ static const char *glsl_vert_interface_default_names[glsl_num_interfaces] = {
glsl_sublang_t glsl_vert_sublanguage = {
.name = "vertex",
.interface_default_names = glsl_vert_interface_default_names,
.model_name = "Vertex",
};

View file

@ -3274,7 +3274,7 @@ static void
rua_init (rua_ctx_t *ctx)
{
ctx->language->initialized = true;
if (options.code.spirv) {
if (options.code.spirv && !pr.module) {
static module_t module; //FIXME probably not what I want
pr.module = &module;

View file

@ -424,31 +424,14 @@ build_grammars (void)
}
}
const plitem_t *
spirv_operand_kind (const char *set, const char *kind)
{
if (!built) {
build_grammars ();
built = true;
}
return nullptr;
}
const uint32_t
spirv_instruction_opcode (const char *set, const expr_t *opcode)
static spirv_grammar_t *
find_grammar (const char *set)
{
if (!built) {
build_grammars ();
built = true;
}
if (is_integral_val (opcode)) {
return expr_integral (opcode);
}
if (opcode->type != ex_symbol) {
error (opcode, "not a an integer constant or symbol");
return 0;
}
spirv_grammar_t *grammar = nullptr;
for (int i = 0; builtin_json[i].name; i++) {
if (strcmp (builtin_json[i].name, set) == 0) {
@ -456,6 +439,28 @@ spirv_instruction_opcode (const char *set, const expr_t *opcode)
break;
}
}
return grammar;
}
const plitem_t *
spirv_operand_kind (const char *set, const char *kind)
{
find_grammar (set);
return nullptr;
}
uint32_t
spirv_instruction_opcode (const char *set, const expr_t *opcode)
{
if (is_integral_val (opcode)) {
return expr_integral (opcode);
}
if (opcode->type != ex_symbol) {
error (opcode, "not a an integer constant or symbol");
return 0;
}
auto grammar = find_grammar (set);
if (!grammar) {
error (opcode, "unrecognized grammar set %s", set);
return 0;
@ -518,18 +523,8 @@ spirv_intrinsic_symbol (const char *name, symtab_t *symtab)
bool
spirv_setup_intrinsic_symtab (symtab_t *symtab)
{
if (!built) {
build_grammars ();
built = true;
}
const char *set = "core";
spirv_grammar_t *grammar = nullptr;
for (int i = 0; builtin_json[i].name; i++) {
if (strcmp (builtin_json[i].name, set) == 0) {
grammar = builtin_json[i].grammar;
break;
}
}
auto grammar = find_grammar (set);
if (!grammar) {
error (0, "unrecognized grammar set %s", set);
return false;
@ -538,3 +533,26 @@ spirv_setup_intrinsic_symtab (symtab_t *symtab)
symtab->procsymbol_data = grammar;
return true;
}
uint32_t
spirv_execution_model (const char *model)
{
const char *set = "core";
auto grammar = find_grammar (set);
if (!grammar) {
error (0, "unrecognized grammar set %s", set);
return false;
}
symtab_t symtab = { .procsymbol_data = grammar };
auto model_enum = spirv_intrinsic_symbol ("ExecutionModel", &symtab);
if (!model_enum) {
error (0, "ExecutionModel not found");
return 0;
}
auto model_val = symtab_lookup (model_enum->namespace, model);
if (!model_val) {
error (0, "Execution model %s not found", model);
return 0;
}
return model_val->value->uint_val;
}

View file

@ -837,6 +837,63 @@ spirv_EntryPoint (entrypoint_t *entrypoint, spirvctx_t *ctx)
}
auto exec_modes = ctx->module->exec_modes;
if (entrypoint->invocations) {
insn = spirv_new_insn (SpvOpExecutionMode, 4, exec_modes);
INSN (insn, 1) = func_id;
INSN (insn, 2) = SpvExecutionModeInvocations;
INSN (insn, 3) = expr_integral (entrypoint->invocations);
}
// assume that if 1 is set, all are set
if (entrypoint->local_size[0]) {
insn = spirv_new_insn (SpvOpExecutionMode, 6, exec_modes);
INSN (insn, 1) = func_id;
//FIXME LocalSizeId
INSN (insn, 2) = SpvExecutionModeLocalSize;
INSN (insn, 3) = expr_integral (entrypoint->local_size[0]);
INSN (insn, 4) = expr_integral (entrypoint->local_size[1]);
INSN (insn, 5) = expr_integral (entrypoint->local_size[2]);
}
if (entrypoint->primitive_in) {
insn = spirv_new_insn (SpvOpExecutionMode, 3, exec_modes);
INSN (insn, 1) = func_id;
INSN (insn, 2) = expr_integral (entrypoint->primitive_in);
}
if (entrypoint->primitive_out) {
insn = spirv_new_insn (SpvOpExecutionMode, 3, exec_modes);
INSN (insn, 1) = func_id;
INSN (insn, 2) = expr_integral (entrypoint->primitive_out);
}
if (entrypoint->max_vertices) {
insn = spirv_new_insn (SpvOpExecutionMode, 4, exec_modes);
INSN (insn, 1) = func_id;
INSN (insn, 2) = SpvExecutionModeOutputVertices;
INSN (insn, 3) = expr_integral (entrypoint->max_vertices);
}
if (entrypoint->spacing) {
insn = spirv_new_insn (SpvOpExecutionMode, 3, exec_modes);
INSN (insn, 1) = func_id;
INSN (insn, 2) = expr_integral (entrypoint->spacing);
}
if (entrypoint->order) {
insn = spirv_new_insn (SpvOpExecutionMode, 3, exec_modes);
INSN (insn, 1) = func_id;
INSN (insn, 2) = expr_integral (entrypoint->order);
}
if (entrypoint->frag_depth) {
insn = spirv_new_insn (SpvOpExecutionMode, 3, exec_modes);
INSN (insn, 1) = func_id;
INSN (insn, 2) = expr_integral (entrypoint->frag_depth);
}
if (entrypoint->point_mode) {
insn = spirv_new_insn (SpvOpExecutionMode, 3, exec_modes);
INSN (insn, 1) = func_id;
INSN (insn, 2) = SpvExecutionModePointMode;
}
if (entrypoint->early_fragment_tests) {
insn = spirv_new_insn (SpvOpExecutionMode, 3, exec_modes);
INSN (insn, 1) = func_id;
INSN (insn, 2) = SpvExecutionModeEarlyFragmentTests;
}
for (auto m = entrypoint->modes; m; m = m->next) {
insn = spirv_new_insn (SpvOpExecutionMode, 3, exec_modes);
INSN (insn, 1) = func_id;
@ -2069,22 +2126,13 @@ static void
spirv_build_code (function_t *func, const expr_t *statements)
{
func->exprs = statements;
if (strcmp ("main", func->o_name) == 0) {
attribute_t *mode = nullptr;
if (pr.module->default_model == SpvExecutionModelFragment) {
mode = new_attribute ("mode",
new_int_expr (SpvExecutionModeOriginUpperLeft, false));
for (auto ep = pr.module->entry_points; ep; ep = ep->next) {
if (strcmp (ep->name, func->o_name) == 0) {
if (ep->func && ep->func != func) {
error (statements, "entry point %s redefined", ep->name);
}
ep->func = func;
}
entrypoint_t *ep = malloc (sizeof (entrypoint_t));
*(ep) = (entrypoint_t) {
.next = pr.module->entry_points,
.model = pr.module->default_model,
.name = "main",
.modes = mode,
.interface_syms = DARRAY_STATIC_INIT (16),
.func = func,
};
pr.module->entry_points = ep;
}
}
@ -2123,6 +2171,33 @@ spirv_declare_sym (specifier_t spec, const expr_t *init, symtab_t *symtab,
}
}
static bool
spirv_create_entry_point (const char *name, const char *model_name)
{
for (auto ep = pr.module->entry_points; ep; ep = ep->next) {
if (strcmp (ep->name, name) == 0) {
error (0, "entry point %s already exists", name);
return false;
}
}
attribute_t *mode = nullptr;
unsigned model = spirv_execution_model (model_name);
if (model == SpvExecutionModelFragment) {
mode = new_attribute ("mode",
new_int_expr (SpvExecutionModeOriginUpperLeft, false));
}
entrypoint_t *ep = malloc (sizeof (entrypoint_t));
*(ep) = (entrypoint_t) {
.next = pr.module->entry_points,
.model = model,
.name = save_string (name),
.modes = mode,
.interface_syms = DARRAY_STATIC_INIT (16),
};
pr.module->entry_points = ep;
return true;
}
static const expr_t *
spirv_build_element_chain (element_chain_t *element_chain, const type_t *type,
const expr_t *eles)
@ -2274,6 +2349,7 @@ target_t spirv_target = {
.build_scope = spirv_build_scope,
.build_code = spirv_build_code,
.declare_sym = spirv_declare_sym,
.create_entry_point = spirv_create_entry_point,
.initialized_temp = spirv_initialized_temp,
.assign_vector = spirv_assign_vector,
.setup_intrinsic_symtab = spirv_setup_intrinsic_symtab,