Commit: 20d5e5e023e84511118aaac8102fb9b2214fc725
Parent: 65a33a6c5d05a3ea4b5b4df1fc9e3e651d9df3a1
Author: Randy Palamar
Date: Thu, 2 Oct 2025 19:22:06 -0600
meta: add @Table, @Expand, and @Emit directives
this provides a more general interface for generating C code
without modifying the build tool. For now it is being used to
generate the acquisition kinds which were one of the few complex
remaining X macro lists.
Diffstat:
10 files changed, 563 insertions(+), 125 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -420,18 +420,18 @@ das_voxel_transform_matrix(BeamformerParameters *bp)
m4 R;
switch (bp->das_shader_id) {
- case BeamformerDASKind_FORCES:
- case BeamformerDASKind_UFORCES:
- case BeamformerDASKind_Flash:
+ case BeamformerAcquisitionKind_FORCES:
+ case BeamformerAcquisitionKind_UFORCES:
+ case BeamformerAcquisitionKind_Flash:
{
R = m4_identity();
S.c[1].E[1] = 0;
T2.c[3].E[1] = 0;
}break;
- case BeamformerDASKind_HERCULES:
- case BeamformerDASKind_UHERCULES:
- case BeamformerDASKind_RCA_TPW:
- case BeamformerDASKind_RCA_VLS:
+ case BeamformerAcquisitionKind_HERCULES:
+ case BeamformerAcquisitionKind_UHERCULES:
+ case BeamformerAcquisitionKind_RCA_TPW:
+ case BeamformerAcquisitionKind_RCA_VLS:
{
R = m4_rotation_about_z(bp->beamform_plane ? 0.0f : 0.25f);
if (!(points.x > 1 && points.y > 1 && points.z > 1))
@@ -454,7 +454,7 @@ das_ubo_from_beamformer_parameters(BeamformerComputePlan *cp, BeamformerDASUBO *
cp->das_bake.speed_of_sound = bp->speed_of_sound;
cp->das_bake.time_offset = bp->time_offset;
cp->das_bake.f_number = bp->f_number;
- cp->das_bake.shader_kind = bp->das_shader_id;
+ cp->das_bake.acquisition_kind = bp->das_shader_id;
cp->das_bake.sample_count = bp->sample_count;
cp->das_bake.channel_count = bp->channel_count;
cp->das_bake.acquisition_count = bp->acquisition_count;
@@ -463,7 +463,7 @@ das_ubo_from_beamformer_parameters(BeamformerComputePlan *cp, BeamformerDASUBO *
if (bp->coherency_weighting) cp->das_bake.shader_flags |= BeamformerShaderDASFlags_CoherencyWeighting;
else cp->das_bake.shader_flags |= BeamformerShaderDASFlags_Fast;
- if (bp->das_shader_id == BeamformerDASKind_UFORCES || bp->das_shader_id == BeamformerDASKind_UHERCULES)
+ if (bp->das_shader_id == BeamformerAcquisitionKind_UFORCES || bp->das_shader_id == BeamformerAcquisitionKind_UHERCULES)
cp->das_bake.shader_flags |= BeamformerShaderDASFlags_Sparse;
if (bp->interpolate)
cp->das_bake.shader_flags |= BeamformerShaderDASFlags_Interpolate;
@@ -690,10 +690,6 @@ stream_push_shader_header(Stream *s, BeamformerShaderKind shader_kind, s8 header
"layout(location = " str(DAS_CYCLE_T_UNIFORM_LOC) ") uniform uint u_cycle_t;\n"
"layout(location = " str(DAS_FAST_CHANNEL_UNIFORM_LOC) ") uniform int u_channel;\n\n"
));
-
- #define X(k, id, ...) "#define ShaderKind_" #k " " #id "\n"
- stream_append_s8s(s, s8(DAS_SHADER_KIND_LIST), s8("\n"));
- #undef X
}break;
case BeamformerShaderKind_Decode:{
stream_append_s8s(s, s8(""
@@ -970,8 +966,8 @@ do_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, BeamformerFrame
if (fast) {
i32 loop_end;
- if (cp->das_bake.shader_kind == BeamformerDASKind_RCA_VLS ||
- cp->das_bake.shader_kind == BeamformerDASKind_RCA_TPW)
+ if (cp->das_bake.acquisition_kind == BeamformerAcquisitionKind_RCA_VLS ||
+ cp->das_bake.acquisition_kind == BeamformerAcquisitionKind_RCA_TPW)
{
/* NOTE(rnp): to avoid repeatedly sampling the whole focal vectors
* texture we loop over transmits for VLS/TPW */
@@ -1042,10 +1038,10 @@ do_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, BeamformerFrame
glProgramUniform1f(program, SUM_PRESCALE_UNIFORM_LOC, 1 / (f32)frame_count);
do_sum_shader(cc, in_textures, frame_count, aframe->texture, aframe->dim);
- aframe->min_coordinate = frame->min_coordinate;
- aframe->max_coordinate = frame->max_coordinate;
- aframe->compound_count = frame->compound_count;
- aframe->das_kind = frame->das_kind;
+ aframe->min_coordinate = frame->min_coordinate;
+ aframe->max_coordinate = frame->max_coordinate;
+ aframe->compound_count = frame->compound_count;
+ aframe->acquisition_kind = frame->acquisition_kind;
}break;
InvalidDefaultCase;
}
@@ -1197,10 +1193,10 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena, iptr gl_c
if (!beamformer_frame_compatible(frame, cp->output_points, gl_kind))
alloc_beamform_frame(&ctx->gl, frame, cp->output_points, gl_kind, s8("Beamformed_Data"), *arena);
- frame->min_coordinate = cp->min_coordinate;
- frame->max_coordinate = cp->max_coordinate;
- frame->das_kind = cp->das_bake.shader_kind;
- frame->compound_count = cp->das_bake.acquisition_count;
+ frame->min_coordinate = cp->min_coordinate;
+ frame->max_coordinate = cp->max_coordinate;
+ frame->acquisition_kind = cp->das_bake.acquisition_kind;
+ frame->compound_count = cp->das_bake.acquisition_count;
BeamformerComputeContext *cc = &ctx->compute_context;
BeamformerComputePipeline *pipeline = &cp->pipeline;
diff --git a/beamformer.h b/beamformer.h
@@ -273,11 +273,11 @@ struct BeamformerFrame {
v3 max_coordinate;
// metadata
- GLenum gl_kind;
- u32 id;
- u32 compound_count;
- BeamformerDASKind das_kind;
- BeamformerViewPlaneTag view_plane_tag;
+ GLenum gl_kind;
+ u32 id;
+ u32 compound_count;
+ BeamformerAcquisitionKind acquisition_kind;
+ BeamformerViewPlaneTag view_plane_tag;
BeamformerFrame *next;
};
diff --git a/beamformer.meta b/beamformer.meta
@@ -3,6 +3,40 @@
@Enumeration(RCAOrientation [Rows Columns])
@Enumeration(SamplingMode [2X 4X])
+@Table([name pretty_name fixed_transmits]) AcquisitionKind
+{
+ [FORCES FORCES 1]
+ [UFORCES UFORCES 0]
+ [HERCULES HERCULES 1]
+ [RCA_VLS VLS 0]
+ [RCA_TPW TPW 0]
+ [UHERCULES UHERCULES 0]
+ [RACES RACES 1]
+ [EPIC_FORCES EPIC-FORCES 1]
+ [EPIC_UFORCES EPIC-UFORCES 0]
+ [EPIC_UHERCULES EPIC-UHERCULES 0]
+ [Flash Flash 0]
+}
+
+@Expand(AcquisitionKind)
+{
+ @Enumeration(AcquisitionKind `$(name)`)
+}
+
+@Emit
+{
+ `read_only global u8 beamformer_acquisition_kind_has_fixed_transmits[] = {`
+ @Expand(AcquisitionKind) ` $(fixed_transmits),`
+ `};`
+}
+
+@Emit
+{
+ `read_only global s8 beamformer_acquisition_kind_strings[] = {`
+ @Expand(AcquisitionKind) ` s8_comp("$(pretty_name)"),`
+ `};`
+}
+
@ShaderGroup Compute
{
@Shader CudaDecode
@@ -57,6 +91,7 @@
@Shader(das.glsl) DAS
{
+ @Enumeration(AcquisitionKind)
@Enumeration(DataKind)
@Enumeration(RCAOrientation)
@Flags([Fast Sparse Interpolate CoherencyWeighting])
@@ -68,7 +103,7 @@
@BakeInt(DataKind data_kind )
@BakeInt(SampleCount sample_count )
@BakeInt(ShaderFlags shader_flags )
- @BakeInt(ShaderKind shader_kind )
+ @BakeInt(AcquisitionKind acquisition_kind )
@BakeFloat(DemodulationFrequency demodulation_frequency)
@BakeFloat(FNumber f_number )
@BakeFloat(SamplingFrequency sampling_frequency )
diff --git a/beamformer_parameters.h b/beamformer_parameters.h
@@ -42,27 +42,6 @@ typedef enum {
BeamformerViewPlaneTag_Count,
} BeamformerViewPlaneTag;
-/* X(type, id, pretty name, fixed transmits) */
-#define DAS_SHADER_KIND_LIST \
- X(FORCES, 0, "FORCES", 1) \
- X(UFORCES, 1, "UFORCES", 0) \
- X(HERCULES, 2, "HERCULES", 1) \
- X(RCA_VLS, 3, "VLS", 0) \
- X(RCA_TPW, 4, "TPW", 0) \
- X(UHERCULES, 5, "UHERCULES", 0) \
- X(RACES, 6, "RACES", 1) \
- X(EPIC_FORCES, 7, "EPIC-FORCES", 1) \
- X(EPIC_UFORCES, 8, "EPIC-UFORCES", 0) \
- X(EPIC_UHERCULES, 9, "EPIC-UHERCULES", 0) \
- X(Flash, 10, "Flash", 0)
-
-typedef enum {
- #define X(type, id, ...) BeamformerDASKind_##type = id,
- DAS_SHADER_KIND_LIST
- #undef X
- BeamformerDASKind_Count
-} BeamformerDASKind;
-
#define BEAMFORMER_CONSTANTS_LIST \
X(FilterSlots, 4) \
X(MaxChannelCount, 256) \
diff --git a/build.c b/build.c
@@ -2,6 +2,8 @@
/* NOTE: inspired by nob: https://github.com/tsoding/nob.h */
/* TODO(rnp):
+ * [ ]: refactor: merge pack_table and bake_parameters
+ * [ ]: refactor: allow @Expand to come before the table definition
* [ ]: refactor: helper for appending expanded shader flags
* [ ]: refactor: "base" shaders should only be reloadable shaders
* - internally when a shader with no file is encountered it should
@@ -775,8 +777,8 @@ meta_push_(MetaprogramContext *m, s8 *items, iz count)
#define meta_pad(m, b, n) stream_pad(&(m)->stream, (b), (n))
#define meta_indent(m) meta_pad((m), '\t', (m)->indentation_level)
#define meta_begin_line(m, ...) do { meta_indent(m); meta_push(m, __VA_ARGS__); } while(0)
-#define meta_end_line(m, ...) meta_push(m, __VA_ARGS__, s8("\n"))
-#define meta_push_line(m, ...) do { meta_indent(m); meta_push(m, __VA_ARGS__, s8("\n")); } while(0)
+#define meta_end_line(m, ...) meta_push(m, ##__VA_ARGS__, s8("\n"))
+#define meta_push_line(m, ...) do { meta_indent(m); meta_push(m, ##__VA_ARGS__, s8("\n")); } while(0)
#define meta_begin_scope(m, ...) do { meta_push_line(m, __VA_ARGS__); (m)->indentation_level++; } while(0)
#define meta_end_scope(m, ...) do { (m)->indentation_level--; meta_push_line(m, __VA_ARGS__); } while(0)
#define meta_push_u64(m, n) stream_append_u64(&(m)->stream, (n))
@@ -820,16 +822,21 @@ meta_end_and_write_matlab(MetaprogramContext *m, char *path)
#define META_ENTRY_KIND_LIST \
X(Invalid) \
+ X(Array) \
X(Bake) \
X(BakeInt) \
X(BakeFloat) \
X(BeginScope) \
+ X(Emit) \
X(EndScope) \
X(Enumeration) \
+ X(Expand) \
X(Flags) \
+ X(String) \
X(Shader) \
X(ShaderGroup) \
- X(SubShader)
+ X(SubShader) \
+ X(Table)
typedef enum {
#define X(k, ...) MetaEntryKind_## k,
@@ -882,6 +889,7 @@ typedef struct {
#define META_PARSE_TOKEN_LIST \
X('@', Entry) \
+ X('`', RawString) \
X('(', BeginArgs) \
X(')', EndArgs) \
X('[', BeginArray) \
@@ -1032,6 +1040,25 @@ meta_parser_trim(MetaParser *p)
}
function s8
+meta_parser_extract_raw_string(MetaParser *p)
+{
+ s8 result = {.data = p->p.s.data};
+ for (; result.len < p->p.s.len; result.len++) {
+ u8 byte = p->p.s.data[result.len];
+ p->p.location.column++;
+ if (byte == '`') {
+ break;
+ } else if (byte == '\n') {
+ p->p.location.column = 0;
+ p->p.location.line++;
+ }
+ }
+ p->p.s.data += (result.len + 1);
+ p->p.s.len -= (result.len + 1);
+ return result;
+}
+
+function s8
meta_parser_extract_string(MetaParser *p)
{
s8 result = {.data = p->p.s.data};
@@ -1066,8 +1093,9 @@ meta_parser_token_name(MetaParser *p, MetaParseToken t)
META_PARSE_TOKEN_LIST
#undef X
};
- if (t >= 0 && t < countof(names)) result = names[t];
- if (t == MetaParseToken_String) result = p->u.string;
+ if (t >= 0 && t < countof(names)) result = names[t];
+ if (t == MetaParseToken_String) result = p->u.string;
+ if (t == MetaParseToken_RawString) result = (s8){.data = p->u.string.data - 1, .len = p->u.string.len + 1};
return result;
}
@@ -1086,14 +1114,18 @@ meta_parser_token(MetaParser *p)
}
if (chop) { s8_chop(&p->p.s, 1); p->p.location.column++; }
- meta_parser_trim(p);
+ if (result != MetaParseToken_RawString) meta_parser_trim(p);
switch (result) {
- case MetaParseToken_String:{ p->u.string = meta_parser_extract_string(p); }break;
+ case MetaParseToken_RawString:{ p->u.string = meta_parser_extract_raw_string(p); }break;
+ case MetaParseToken_String:{ p->u.string = meta_parser_extract_string(p); }break;
/* NOTE(rnp): '{' and '}' are shorthand for @BeginScope and @EndScope */
case MetaParseToken_BeginScope:{ p->u.kind = MetaEntryKind_BeginScope; }break;
case MetaParseToken_EndScope:{ p->u.kind = MetaEntryKind_EndScope; }break;
+ /* NOTE(rnp): loose '[' implies implicit @Array() */
+ case MetaParseToken_BeginArray:{ p->u.kind = MetaEntryKind_Array; }break;
+
case MetaParseToken_Entry:{
s8 kind = meta_parser_extract_string(p);
p->u.kind = meta_entry_kind_from_string(kind);
@@ -1126,42 +1158,51 @@ meta_parser_unexpected_token(MetaParser *p, MetaParseToken t)
}
function void
+meta_parser_fill_argument_array(MetaParser *p, MetaEntryArgument *array, Arena *arena)
+{
+ array->kind = MetaEntryArgumentKind_Array;
+ array->strings = arena_aligned_start(*arena, alignof(s8));
+ array->location = p->p.location;
+ for (MetaParseToken token = meta_parser_token(p);
+ token != MetaParseToken_EndArray;
+ token = meta_parser_token(p))
+ {
+ switch (token) {
+ case MetaParseToken_RawString:
+ case MetaParseToken_String:
+ {
+ assert((u8 *)(array->strings + array->count) == arena->beg);
+ *push_struct(arena, s8) = p->u.string;
+ array->count++;
+ }break;
+ default:{ meta_parser_unexpected_token(p, token); }break;
+ }
+ }
+}
+
+function void
meta_parser_arguments(MetaParser *p, MetaEntry *e, Arena *arena)
{
if (meta_parser_peek_token(p) == MetaParseToken_BeginArgs) {
meta_parser_commit(p);
- MetaEntryArgument *arg = e->arguments = push_struct(arena, MetaEntryArgument);
- b32 array = 0;
+ e->arguments = arena_aligned_start(*arena, alignof(MetaEntryArgument));
for (MetaParseToken token = meta_parser_token(p);
token != MetaParseToken_EndArgs;
token = meta_parser_token(p))
{
- if (!arg) arg = push_struct(arena, MetaEntryArgument);
+ e->argument_count++;
+ MetaEntryArgument *arg = push_struct(arena, MetaEntryArgument);
switch (token) {
- case MetaParseToken_String:{
- if (array) {
- assert((u8 *)(arg->strings + arg->count) == arena->beg);
- *push_struct(arena, s8) = p->u.string;
- arg->count++;
- } else {
- e->argument_count++;
- arg->kind = MetaEntryArgumentKind_String;
- arg->string = p->u.string;
- arg->location = p->p.location;
- arg = 0;
- }
- }break;
- case MetaParseToken_BeginArray:{
- arg->kind = MetaEntryArgumentKind_Array;
- arg->strings = (s8 *)arena_aligned_start(*arena, alignof(s8));
+ case MetaParseToken_RawString:
+ case MetaParseToken_String:
+ {
+ arg->kind = MetaEntryArgumentKind_String;
+ arg->string = p->u.string;
arg->location = p->p.location;
- array = 1;
}break;
- case MetaParseToken_EndArray:{
- e->argument_count++;
- array = 0;
- arg = 0;
+ case MetaParseToken_BeginArray:{
+ meta_parser_fill_argument_array(p, arg, arena);
}break;
default:{ meta_parser_unexpected_token(p, token); }break;
}
@@ -1169,15 +1210,21 @@ meta_parser_arguments(MetaParser *p, MetaEntry *e, Arena *arena)
}
}
-function iz
+typedef struct {
+ MetaEntry *start;
+ MetaEntry *one_past_last;
+ iz consumed;
+} MetaEntryScope;
+
+function MetaEntryScope
meta_entry_extract_scope(MetaEntry *base, iz entry_count)
{
assert(base->kind != MetaEntryKind_BeginScope || base->kind != MetaEntryKind_EndScope);
assert(entry_count > 0);
- MetaEntry *e = base + 1;
- iz result, sub_scope = 0;
- for (result = 1; result < entry_count; result++, e++) {
+ MetaEntryScope result = {.start = base + 1, .consumed = 1};
+ iz sub_scope = 0;
+ for (MetaEntry *e = result.start; result.consumed < entry_count; result.consumed++, e++) {
switch (e->kind) {
case MetaEntryKind_BeginScope:{ sub_scope++; }break;
case MetaEntryKind_EndScope:{ sub_scope--; }break;
@@ -1189,6 +1236,10 @@ meta_entry_extract_scope(MetaEntry *base, iz entry_count)
if (sub_scope != 0)
meta_entry_error(base, "unclosed scope for entry\n");
+ result.one_past_last = base + result.consumed;
+ if (result.start->kind == MetaEntryKind_BeginScope) result.start++;
+ if (result.one_past_last == result.start) result.one_past_last++;
+
return result;
}
@@ -1208,6 +1259,12 @@ meta_entry_stack_from_file(Arena *arena, Arena scratch, char *file)
{
MetaEntry *e = da_push(arena, &result);
switch (token) {
+ case MetaParseToken_RawString:{
+ e->kind = MetaEntryKind_String;
+ e->location = parser.save_point.location;
+ e->name = parser.u.string;
+ }break;
+ case MetaParseToken_BeginArray:
case MetaParseToken_BeginScope:
case MetaParseToken_EndScope:
case MetaParseToken_Entry:
@@ -1218,6 +1275,12 @@ meta_entry_stack_from_file(Arena *arena, Arena scratch, char *file)
if (token == MetaParseToken_Entry)
meta_parser_arguments(&parser, e, arena);
+ if (token == MetaParseToken_BeginArray) {
+ MetaEntryArgument *a = e->arguments = push_struct(arena, MetaEntryArgument);
+ e->argument_count = 1;
+ meta_parser_fill_argument_array(&parser, a, arena);
+ }
+
if (meta_parser_peek_token(&parser) == MetaParseToken_String) {
meta_parser_commit(&parser);
e->name = parser.u.string;
@@ -1319,12 +1382,63 @@ typedef struct {
DA_STRUCT(MetaShaderGroup, MetaShaderGroup);
typedef struct {
+ s8 *fields;
+ s8 **entries;
+ u32 field_count;
+ u32 entry_count;
+ u32 table_name_id;
+} MetaTable;
+DA_STRUCT(MetaTable, MetaTable);
+
+typedef enum {
+ MetaExpansionPartKind_Reference,
+ MetaExpansionPartKind_String,
+} MetaExpansionPartKind;
+
+typedef struct {
+ s8 *strings;
+ MetaExpansionPartKind kind;
+} MetaExpansionPart;
+DA_STRUCT(MetaExpansionPart, MetaExpansionPart);
+
+typedef enum {
+ MetaEmitOperationKind_String,
+ MetaEmitOperationKind_Expand,
+} MetaEmitOperationKind;
+
+typedef struct {
+ MetaExpansionPart *parts;
+ u32 part_count;
+ u32 table_id;
+} MetaEmitOperationExpansion;
+
+typedef struct {
+ union {
+ s8 string;
+ MetaEmitOperationExpansion expansion_operation;
+ };
+ MetaEmitOperationKind kind;
+} MetaEmitOperation;
+DA_STRUCT(MetaEmitOperation, MetaEmitOperation);
+
+typedef struct {
+ MetaEmitOperationList *data;
+ iz count;
+ iz capacity;
+} MetaEmitOperationListSet;
+
+typedef struct {
Arena *arena, scratch;
- s8_list enumeration_kinds;
- s8_list_table enumeration_members;
+ s8_list enumeration_kinds;
+ s8_list_table enumeration_members;
+
+ s8_list_table flags_for_shader;
+
+ s8_list table_names;
+ MetaTableList tables;
- s8_list_table flags_for_shader;
+ MetaEmitOperationListSet emit_sets;
MetaShaderBakeParametersList shader_bake_parameters;
MetaShaderGroupList shader_groups;
@@ -1387,7 +1501,6 @@ function iz
meta_pack_shader_bake_parameters(MetaContext *ctx, MetaEntry *e, iz entry_count, u32 shader_id, u32 *table_id)
{
assert(e->kind == MetaEntryKind_Bake);
- iz result = meta_entry_extract_scope(e, entry_count);
MetaShaderBakeParameters *bp = da_push(ctx->arena, &ctx->shader_bake_parameters);
bp->shader_id = shader_id;
@@ -1395,12 +1508,9 @@ meta_pack_shader_bake_parameters(MetaContext *ctx, MetaEntry *e, iz entry_count,
if (e->argument_count) meta_entry_argument_expected(e);
- if (result > 1) {
- MetaEntry *last = e + result;
- assert(e[1].kind == MetaEntryKind_BeginScope);
- assert(last->kind == MetaEntryKind_EndScope);
-
- for (MetaEntry *row = e + 2; row != last; row++) {
+ MetaEntryScope scope = meta_entry_extract_scope(e, entry_count);
+ if (scope.consumed > 1) {
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) {
if (row->kind != MetaEntryKind_BakeInt && row->kind != MetaEntryKind_BakeFloat)
meta_entry_nesting_error(row, MetaEntryKind_Bake);
meta_entry_argument_expected(row, s8("name"), s8("name_lower"));
@@ -1412,14 +1522,14 @@ meta_pack_shader_bake_parameters(MetaContext *ctx, MetaEntry *e, iz entry_count,
bp->floating_point = push_array(ctx->arena, u8, bp->entry_count);
u32 row_index = 0;
- for (MetaEntry *row = e + 2; row != last; row++, row_index++) {
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++, row_index++) {
bp->names_upper[row_index] = row->arguments[0].string;
bp->names_lower[row_index] = row->arguments[1].string;
bp->floating_point[row_index] = row->kind == MetaEntryKind_BakeFloat;
}
}
- return result;
+ return scope.consumed;
}
function iz
@@ -1433,6 +1543,16 @@ meta_enumeration_id(MetaContext *ctx, s8 kind)
return result;
}
+function void
+meta_extend_enumeration(MetaContext *ctx, s8 kind, s8 *variations, uz count)
+{
+ iz kidx = meta_enumeration_id(ctx, kind);
+ /* NOTE(rnp): may overcommit if duplicates exist in variations */
+ da_reserve(ctx->arena, ctx->enumeration_members.data + kidx, (iz)count);
+ for (uz i = 0; i < count; i++)
+ meta_intern_string(ctx, ctx->enumeration_members.data + kidx, variations[i]);
+}
+
function MetaEnumeration
meta_commit_enumeration(MetaContext *ctx, s8 kind, s8 variation)
{
@@ -1557,6 +1677,225 @@ meta_pack_shader(MetaContext *ctx, MetaShaderGroup *sg, Arena scratch, MetaEntry
}
function void
+meta_expansion_string_split(s8 string, s8 *left, s8 *inner, s8 *remainder, MetaLocation loc)
+{
+ b32 found = 0;
+ for (u8 *s = string.data, *e = s + string.len; (s + 1) != e; s++) {
+ u32 val = (u32)'$' << 8u | (u32)'(';
+ u32 test = (u32)s[0] << 8u | s[1];
+ if (test == val) {
+ if (left) {
+ left->data = string.data;
+ left->len = s - string.data;
+ }
+
+ u8 *start = s + 2;
+ while (s != e && *s != ')') s++;
+ if (s == e) {
+ meta_compiler_error_message(loc, "unterminated expansion in raw string:\n %.*s\n",
+ (i32)string.len, string.data);
+ fprintf(stderr, " %.*s^\n", (i32)(start - string.data), "");
+ meta_error();
+ }
+
+ if (inner) {
+ inner->data = start;
+ inner->len = s - start;
+ }
+
+ if (remainder) {
+ remainder->data = s + 1;
+ remainder->len = string.len - (remainder->data - string.data);
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ if (left) *left = string;
+ if (inner) *inner = (s8){0};
+ if (remainder) *remainder = (s8){0};
+ }
+}
+
+function MetaExpansionPart *
+meta_push_expansion_part(MetaContext *ctx, Arena *arena, MetaExpansionPartList *parts,
+ MetaExpansionPartKind kind, s8 string, MetaTable *t, MetaLocation loc)
+{
+ MetaExpansionPart *result = da_push(arena, parts);
+ result->kind = kind;
+ if (kind == MetaExpansionPartKind_String) {
+ result->strings = push_struct(arena, s8);
+ result->strings[0] = string;
+ } else {
+ iz index = -1;
+ for (u32 field = 0; field < t->field_count; field++) {
+ if (s8_equal(string, t->fields[field])) {
+ index = (iz)field;
+ break;
+ }
+ }
+ result->strings = t->entries[index];
+ if (index < 0) {
+ /* TODO(rnp): fix this location to point directly at the field in the string */
+ s8 table_name = ctx->table_names.data[t->table_name_id];
+ meta_compiler_error(loc, "table \"%.*s\" does not contain member: %.*s\n",
+ (i32)table_name.len, table_name.data, (i32)string.len, string.data);
+ }
+ }
+ return result;
+}
+
+function MetaExpansionPartList
+meta_generate_expansion_set(MetaContext *ctx, Arena *arena, s8 expansion_string, MetaTable *t, MetaLocation loc)
+{
+ MetaExpansionPartList result = {0};
+ s8 left = {0}, inner, remainder = expansion_string;
+ do {
+ meta_expansion_string_split(remainder, &left, &inner, &remainder, loc);
+ if (left.len) meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, left, t, loc);
+ if (inner.len) meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Reference, inner, t, loc);
+ } while (remainder.len);
+ return result;
+}
+
+function iz
+meta_expand(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count, MetaEmitOperationList *ops)
+{
+ assert(e->kind == MetaEntryKind_Expand);
+
+ /* TODO(rnp): for now this requires that the @Table came first */
+ meta_entry_argument_expected(e, s8("table_name"));
+ s8 table_name = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string;
+
+ MetaTable *t = ctx->tables.data + meta_lookup_string_slow(&ctx->table_names, table_name);
+ if (t < ctx->tables.data)
+ meta_entry_error(e, "undefined table %.*s\n", (i32)table_name.len, table_name.data);
+
+ MetaEntryScope scope = meta_entry_extract_scope(e, entry_count);
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) {
+ switch (row->kind) {
+ case MetaEntryKind_String:{
+ if (!ops) goto error;
+
+ MetaExpansionPartList parts = meta_generate_expansion_set(ctx, ctx->arena, row->name, t, row->location);
+
+ MetaEmitOperation *op = da_push(ctx->arena, ops);
+ op->kind = MetaEmitOperationKind_Expand;
+ op->expansion_operation.parts = parts.data;
+ op->expansion_operation.part_count = (u32)parts.count;
+ op->expansion_operation.table_id = (u32)da_index(t, &ctx->tables);
+ }break;
+ case MetaEntryKind_Enumeration:{
+ if (ops) meta_entry_nesting_error(row, MetaEntryKind_Emit);
+
+ meta_entry_argument_expected(row, s8("kind"), s8("`raw_string`"));
+ s8 kind = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_String).string;
+ s8 expand = meta_entry_argument_expect(row, 1, MetaEntryArgumentKind_String).string;
+
+ MetaExpansionPartList parts = meta_generate_expansion_set(ctx, &scratch, expand, t, row->location);
+ s8 *variations = push_array(&scratch, s8, t->entry_count);
+ for (u32 expansion = 0; expansion < t->entry_count; expansion++) {
+ Stream sb = arena_stream(*ctx->arena);
+ for (iz part = 0; part < parts.count; part++) {
+ MetaExpansionPart *p = parts.data + part;
+ u32 index = 0;
+ if (p->kind == MetaExpansionPartKind_Reference) index = expansion;
+ stream_append_s8(&sb, p->strings[index]);
+ }
+ variations[expansion] = arena_stream_commit(ctx->arena, &sb);
+ }
+ meta_extend_enumeration(ctx, kind, variations, t->entry_count);
+ }break;
+ error:
+ default:
+ {
+ meta_entry_nesting_error(row, MetaEntryKind_Expand);
+ }break;
+ }
+ }
+ return scope.consumed;
+}
+
+function iz
+meta_pack_emit(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count)
+{
+ assert(e->kind == MetaEntryKind_Emit);
+
+ MetaEmitOperationList *ops = da_push(ctx->arena, &ctx->emit_sets);
+ MetaEntryScope scope = meta_entry_extract_scope(e, entry_count);
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) {
+ switch (row->kind) {
+ case MetaEntryKind_String:{
+ MetaEmitOperation *op = da_push(ctx->arena, ops);
+ op->kind = MetaEmitOperationKind_String;
+ op->string = row->name;
+ }break;
+ case MetaEntryKind_Expand:{
+ row += meta_expand(ctx, scratch, row, entry_count - (row - e), ops);
+ }break;
+ default:{ meta_entry_nesting_error(row, MetaEntryKind_Emit); }break;
+ }
+ }
+ return scope.consumed;
+}
+
+function iz
+meta_pack_table(MetaContext *ctx, MetaEntry *e, iz entry_count)
+{
+ assert(e->kind == MetaEntryKind_Table);
+
+ MetaTable *t = da_push(ctx->arena, &ctx->tables);
+ iz table_name_id = meta_lookup_string_slow(&ctx->table_names, e->name);
+ if (table_name_id >= 0) meta_entry_error(e, "table redifined\n");
+
+ s8 *t_name = da_push(ctx->arena, &ctx->table_names);
+ t->table_name_id = (u32)da_index(t_name, &ctx->table_names);
+ *t_name = e->name;
+
+ meta_entry_argument_expected(e, s8("[field ...]"));
+ MetaEntryArgument fields = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_Array);
+ t->fields = fields.strings;
+ t->field_count = (u32)fields.count;
+
+ MetaEntryScope scope = meta_entry_extract_scope(e, entry_count);
+ if (scope.consumed > 1) {
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) {
+ if (row->kind != MetaEntryKind_Array)
+ meta_entry_nesting_error(row, MetaEntryKind_Table);
+
+ MetaEntryArgument entries = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_Array);
+ if (entries.count != t->field_count) {
+ meta_compiler_error_message(row->location, "incorrect field count for @%s entry got: %lu expected: %u\n",
+ meta_entry_kind_strings[MetaEntryKind_Table],
+ entries.count, t->field_count);
+ fprintf(stderr, " fields: [");
+ for (uz i = 0; i < t->field_count; i++) {
+ if (i != 0) fprintf(stderr, ", ");
+ fprintf(stderr, "%.*s", (i32)t->fields[i].len, t->fields[i].data);
+ }
+ fprintf(stderr, "]\n");
+ meta_error();
+ }
+ t->entry_count++;
+ }
+
+ t->entries = push_array(ctx->arena, s8 *, t->field_count);
+ for (u32 field = 0; field < t->field_count; field++)
+ t->entries[field] = push_array(ctx->arena, s8, t->entry_count);
+
+ u32 row_index = 0;
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++, row_index++) {
+ s8 *fs = row->arguments->strings;
+ for (u32 field = 0; field < t->field_count; field++)
+ t->entries[field][row_index] = fs[field];
+ }
+ }
+
+ return scope.consumed;
+}
+
+function void
metagen_push_table(MetaprogramContext *m, Arena scratch, s8 row_start, s8 row_end,
s8 **column_strings, uz rows, uz columns)
{
@@ -1912,6 +2251,33 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena)
}
meta_end_scope(m, s8("};\n"));
+ ///////////////////////////////
+ // NOTE(rnp): @Emit directives
+ for (iz set = 0; set < ctx->emit_sets.count; set++) {
+ MetaEmitOperationList *ops = ctx->emit_sets.data + set;
+ for (iz opcode = 0; opcode < ops->count; opcode++) {
+ MetaEmitOperation *op = ops->data + opcode;
+ switch (op->kind) {
+ case MetaEmitOperationKind_String:{ meta_push_line(m, op->string); }break;
+ case MetaEmitOperationKind_Expand:{
+ MetaEmitOperationExpansion *eop = &op->expansion_operation;
+ MetaTable *t = ctx->tables.data + eop->table_id;
+ for (u32 entry = 0; entry < t->entry_count; entry++) {
+ meta_indent(m);
+ for (u32 part = 0; part < eop->part_count; part++) {
+ MetaExpansionPart *p = eop->parts + part;
+ u32 index = p->kind == MetaExpansionPartKind_Reference ? entry : 0;
+ meta_push(m, p->strings[index]);
+ }
+ meta_end_line(m);
+ }
+ }break;
+ InvalidDefaultCase;
+ }
+ }
+ meta_end_line(m);
+ }
+
//fprintf(stderr, "%.*s\n", (i32)m.stream.widx, m.stream.data);
result = meta_write_and_reset(m, out);
@@ -2151,6 +2517,9 @@ metagen_load_context(Arena *arena)
default:{}break;
}
}break;
+ case MetaEntryKind_Emit:{
+ i += meta_pack_emit(ctx, scratch, e, entries.count - i);
+ }break;
case MetaEntryKind_Enumeration:{
meta_entry_argument_expected(e, s8("kind"), s8("[id ...]"));
s8 kind = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string;
@@ -2158,6 +2527,9 @@ metagen_load_context(Arena *arena)
for (u32 id = 0; id < ids.count; id++)
meta_commit_enumeration(ctx, kind, ids.strings[id]);
}break;
+ case MetaEntryKind_Expand:{
+ i += meta_expand(ctx, scratch, e, entries.count - i, 0);
+ }break;
case MetaEntryKind_ShaderGroup:{
MetaShaderGroup *sg = da_push(ctx->arena, &ctx->shader_groups);
sg->name = e->name;
@@ -2167,6 +2539,9 @@ metagen_load_context(Arena *arena)
if (!current_shader_group) goto error;
i += meta_pack_shader(ctx, current_shader_group, scratch, e, entries.count - i);
}break;
+ case MetaEntryKind_Table:{
+ i += meta_pack_table(ctx, e, entries.count - i);
+ }break;
error:
default:
diff --git a/generated/beamformer.meta.c b/generated/beamformer.meta.c
@@ -29,6 +29,21 @@ typedef enum {
} BeamformerSamplingMode;
typedef enum {
+ BeamformerAcquisitionKind_FORCES = 0,
+ BeamformerAcquisitionKind_UFORCES = 1,
+ BeamformerAcquisitionKind_HERCULES = 2,
+ BeamformerAcquisitionKind_RCA_VLS = 3,
+ BeamformerAcquisitionKind_RCA_TPW = 4,
+ BeamformerAcquisitionKind_UHERCULES = 5,
+ BeamformerAcquisitionKind_RACES = 6,
+ BeamformerAcquisitionKind_EPIC_FORCES = 7,
+ BeamformerAcquisitionKind_EPIC_UFORCES = 8,
+ BeamformerAcquisitionKind_EPIC_UHERCULES = 9,
+ BeamformerAcquisitionKind_Flash = 10,
+ BeamformerAcquisitionKind_Count,
+} BeamformerAcquisitionKind;
+
+typedef enum {
BeamformerShaderDecodeFlags_DilateOutput = (1 << 0),
} BeamformerShaderDecodeFlags;
@@ -107,7 +122,7 @@ typedef union {
u32 data_kind;
u32 sample_count;
u32 shader_flags;
- u32 shader_kind;
+ u32 acquisition_kind;
f32 demodulation_frequency;
f32 f_number;
f32 sampling_frequency;
@@ -190,6 +205,19 @@ read_only global s8 beamformer_shader_global_header_strings[] = {
"#define SamplingMode_2X 0\n"
"#define SamplingMode_4X 1\n"
"\n"),
+ s8_comp(""
+ "#define AcquisitionKind_FORCES 0\n"
+ "#define AcquisitionKind_UFORCES 1\n"
+ "#define AcquisitionKind_HERCULES 2\n"
+ "#define AcquisitionKind_RCA_VLS 3\n"
+ "#define AcquisitionKind_RCA_TPW 4\n"
+ "#define AcquisitionKind_UHERCULES 5\n"
+ "#define AcquisitionKind_RACES 6\n"
+ "#define AcquisitionKind_EPIC_FORCES 7\n"
+ "#define AcquisitionKind_EPIC_UFORCES 8\n"
+ "#define AcquisitionKind_EPIC_UHERCULES 9\n"
+ "#define AcquisitionKind_Flash 10\n"
+ "\n"),
};
read_only global s8 beamformer_shader_local_header_strings[] = {
@@ -215,7 +243,7 @@ read_only global s8 beamformer_shader_local_header_strings[] = {
read_only global i32 *beamformer_shader_header_vectors[] = {
(i32 []){0, 1},
(i32 []){0, 3},
- (i32 []){0, 2},
+ (i32 []){4, 0, 2},
0,
0,
0,
@@ -224,7 +252,7 @@ read_only global i32 *beamformer_shader_header_vectors[] = {
read_only global i32 beamformer_shader_header_vector_lengths[] = {
2,
2,
- 2,
+ 3,
0,
0,
0,
@@ -264,7 +292,7 @@ read_only global s8 *beamformer_shader_bake_parameter_names[] = {
s8_comp("DataKind"),
s8_comp("SampleCount"),
s8_comp("ShaderFlags"),
- s8_comp("ShaderKind"),
+ s8_comp("AcquisitionKind"),
s8_comp("DemodulationFrequency"),
s8_comp("FNumber"),
s8_comp("SamplingFrequency"),
@@ -294,3 +322,31 @@ read_only global i32 beamformer_shader_bake_parameter_counts[] = {
0,
};
+read_only global u8 beamformer_acquisition_kind_has_fixed_transmits[] = {
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+};
+
+read_only global s8 beamformer_acquisition_kind_strings[] = {
+ s8_comp("FORCES"),
+ s8_comp("UFORCES"),
+ s8_comp("HERCULES"),
+ s8_comp("VLS"),
+ s8_comp("TPW"),
+ s8_comp("UHERCULES"),
+ s8_comp("RACES"),
+ s8_comp("EPIC-FORCES"),
+ s8_comp("EPIC-UFORCES"),
+ s8_comp("EPIC-UHERCULES"),
+ s8_comp("Flash"),
+};
+
diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c
@@ -505,7 +505,7 @@ beamformer_push_simple_parameters_at(BeamformerSimpleParameters *bp, u32 block)
result &= beamformer_push_transmit_receive_orientations_at(bp->transmit_receive_orientations,
bp->acquisition_count, block);
- if (bp->das_shader_id == BeamformerDASKind_UFORCES || bp->das_shader_id == BeamformerDASKind_UHERCULES)
+ if (bp->das_shader_id == BeamformerAcquisitionKind_UFORCES || bp->das_shader_id == BeamformerAcquisitionKind_UHERCULES)
result &= beamformer_push_sparse_elements_at(bp->sparse_elements, bp->acquisition_count, block);
for (u32 stage = 0; stage < bp->compute_stages_count; stage++)
diff --git a/shaders/das.glsl b/shaders/das.glsl
@@ -265,20 +265,20 @@ void main()
vec3 world_point = (voxel_transform * vec4(out_voxel, 1)).xyz;
- switch (ShaderKind) {
- case ShaderKind_FORCES:
- case ShaderKind_UFORCES:
+ switch (AcquisitionKind) {
+ case AcquisitionKind_FORCES:
+ case AcquisitionKind_UFORCES:
{
sum += FORCES(world_point);
}break;
- case ShaderKind_HERCULES:
- case ShaderKind_UHERCULES:
+ case AcquisitionKind_HERCULES:
+ case AcquisitionKind_UHERCULES:
{
sum += HERCULES(world_point);
}break;
- case ShaderKind_Flash:
- case ShaderKind_RCA_TPW:
- case ShaderKind_RCA_VLS:
+ case AcquisitionKind_Flash:
+ case AcquisitionKind_RCA_TPW:
+ case AcquisitionKind_RCA_VLS:
{
sum += RCA(world_point);
}break;
diff --git a/ui.c b/ui.c
@@ -657,20 +657,17 @@ stream_append_variable_group(Stream *s, Variable *var)
}
function s8
-push_das_shader_kind(Stream *s, BeamformerDASKind shader, u32 transmit_count)
+push_acquisition_kind(Stream *s, BeamformerAcquisitionKind kind, u32 transmit_count)
{
- #define X(__1, __2, pretty, ...) s8_comp(pretty),
- read_only local_persist s8 pretty_names[BeamformerDASKind_Count + 1] = {
- DAS_SHADER_KIND_LIST
- s8_comp("Invalid")
- };
- #undef X
- #define X(__1, __2, __3, fixed_tx) fixed_tx,
- read_only local_persist u8 fixed_transmits[BeamformerDASKind_Count + 1] = {DAS_SHADER_KIND_LIST};
- #undef X
+ s8 name = beamformer_acquisition_kind_strings[kind];
+ b32 fixed_transmits = beamformer_acquisition_kind_has_fixed_transmits[kind];
+ if (kind >= BeamformerAcquisitionKind_Count || kind < 0) {
+ fixed_transmits = 0;
+ name = s8("Invalid");
+ }
- stream_append_s8(s, pretty_names[MIN(shader, BeamformerDASKind_Count)]);
- if (!fixed_transmits[MIN(shader, BeamformerDASKind_Count)]) {
+ stream_append_s8(s, name);
+ if (!fixed_transmits) {
stream_append_byte(s, '-');
stream_append_u64(s, transmit_count);
}
@@ -2570,7 +2567,7 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa
{
Stream buf = arena_stream(a);
- s8 shader = push_das_shader_kind(&buf, frame->das_kind, frame->compound_count);
+ s8 shader = push_acquisition_kind(&buf, frame->acquisition_kind, frame->compound_count);
text_spec.font = &ui->font;
text_spec.limits.size.w -= 16;
v2 txt_s = measure_text(*text_spec.font, shader);
diff --git a/util.c b/util.c
@@ -22,7 +22,7 @@ mem_move(u8 *dest, u8 *src, uz n)
else while (n) { n--; dest[n] = src[n]; }
}
-function u8 *
+function void *
arena_aligned_start(Arena a, uz alignment)
{
uz padding = -(uintptr_t)a.beg & (alignment - 1);
@@ -34,7 +34,7 @@ arena_aligned_start(Arena a, uz alignment)
function iz
arena_capacity_(Arena *a, iz size, uz alignment)
{
- iz available = a->end - arena_aligned_start(*a, alignment);
+ iz available = a->end - (u8 *)arena_aligned_start(*a, alignment);
iz result = available / size;
return result;
}