ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | README | LICENSE

Commit: ffe7d0f89e0b7c0ed51eef32b3f84dd735625aac
Parent: 3bfa4af7007e3b867c302c2a88fa128cf86bd626
Author: Randy Palamar
Date:   Mon,  4 May 2026 10:27:07 -0600

meta: add support for push constants

This is vulkan terminology but it is more descriptive than UBO.
This is not particularly useful in this OpenGL code but it will
make it easier to pull back other changes to the meta code.

Diffstat:
Mbeamformer.meta | 11+++++++++--
Mbeamformer_core.c | 24++++++++++++------------
Mbeamformer_internal.h | 16+---------------
Mbuild.c | 577++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mgenerated/beamformer.meta.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Mutil.h | 21+++++++++------------
6 files changed, 433 insertions(+), 266 deletions(-)

diff --git a/beamformer.meta b/beamformer.meta @@ -261,6 +261,8 @@ @Enumeration(DataKind) @Flags([ComplexFilter OutputFloats]) + @ShaderAlias Demodulate + @Bake { @BakeInt(DecimationRate decimation_rate ) @@ -275,8 +277,6 @@ @BakeFloat(DemodulationFrequency demodulation_frequency) @BakeFloat(SamplingFrequency sampling_frequency ) } - - @SubShader Demodulate } @Shader(das.glsl) DAS @@ -304,6 +304,13 @@ @BakeFloat(TimeOffset time_offset ) @BakeFloat(TransmitAngle transmit_angle ) } + + @PushConstants + { + [mat4 M4 xdc_transform ] + [mat4 M4 voxel_transform ] + [vec2 V2 xdc_element_pitch] + } } @Shader(min_max.glsl) MinMax diff --git a/beamformer_core.c b/beamformer_core.c @@ -546,7 +546,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) sd->bake.data_kind = BeamformerDataKind_Float32Complex; BeamformerShaderDASBakeParameters *db = &sd->bake.DAS; - BeamformerDASUBO *du = &cp->das_ubo_data; + BeamformerShaderDASPushConstants *du = &cp->das_ubo_data; du->xdc_element_pitch = pb->parameters.xdc_element_pitch; db->sampling_frequency = sampling_frequency; db->demodulation_frequency = pb->parameters.demodulation_frequency; @@ -659,16 +659,6 @@ stream_push_shader_header(Stream *s, BeamformerShaderKind shader_kind, s8 header function void load_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, u32 shader_slot, Arena arena) { - read_only local_persist s8 compute_headers[BeamformerShaderKind_ComputeCount] = { - /* X(name, type, gltype) */ - #define X(name, t, gltype) "\t" #gltype " " #name ";\n" - [BeamformerShaderKind_DAS] = s8_comp("layout(std140, binding = 0) uniform parameters {\n" - BEAMFORMER_DAS_UBO_PARAM_LIST - "};\n\n" - ), - #undef X - }; - BeamformerShaderKind shader = cp->pipeline.shaders[shader_slot]; u32 program = 0; @@ -681,7 +671,7 @@ load_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, u32 shader_sl beamformer_reloadable_shader_files[reloadable_index]); Stream shader_stream = arena_stream(arena); - stream_push_shader_header(&shader_stream, base_shader, compute_headers[base_shader]); + stream_push_shader_header(&shader_stream, base_shader, s8("")); i32 header_vector_length = beamformer_shader_header_vector_lengths[reloadable_index]; i32 *header_vector = beamformer_shader_header_vectors[reloadable_index]; @@ -724,6 +714,16 @@ load_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, u32 shader_sl (flags & (1 << bit))? s8(" 1") : s8(" 0"), s8("\n")); } + u32 pc_count = beamformer_shader_push_constant_counts[reloadable_index]; + s8 *pc_names = beamformer_shader_push_constant_names[reloadable_index]; + s8 *pc_types = beamformer_shader_push_constant_glsl_types[reloadable_index]; + if (pc_count) { + stream_append_s8s(&shader_stream, s8("\n\nlayout(std140, binding = 0) uniform PushConstants {\n")); + for (u32 it = 0; it < pc_count; it++) + stream_append_s8s(&shader_stream, s8("\t"), pc_types[it], s8(" "), pc_names[it],s8(";\n")); + stream_append_s8s(&shader_stream, s8("};")); + } + if (!renderdoc_attached()) stream_append_s8(&shader_stream, s8("\n#line 1\n")); diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -99,23 +99,9 @@ typedef struct { u32 ssbo; } BeamformerFilter; -/* X(name, type, gltype) */ -#define BEAMFORMER_DAS_UBO_PARAM_LIST \ - X(xdc_transform, m4, mat4) \ - X(voxel_transform, m4, mat4) \ - X(xdc_element_pitch, v2, vec2) - -typedef alignas(16) struct { - #define X(name, type, ...) type name; - BEAMFORMER_DAS_UBO_PARAM_LIST - #undef X - float _pad[2]; -} BeamformerDASUBO; -static_assert((sizeof(BeamformerDASUBO) & 15) == 0, "UBO size must be a multiple of 16"); - /* TODO(rnp): need 1 UBO per filter slot */ #define BEAMFORMER_COMPUTE_UBO_LIST \ - X(DAS, BeamformerDASUBO, das) + X(DAS, BeamformerShaderDASPushConstants, das) #define X(k, ...) BeamformerComputeUBOKind_##k, typedef enum {BEAMFORMER_COMPUTE_UBO_LIST BeamformerComputeUBOKind_Count} BeamformerComputeUBOKind; diff --git a/build.c b/build.c @@ -971,24 +971,25 @@ 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(Embed) \ - X(EndScope) \ - X(Enumeration) \ - X(Expand) \ - X(Flags) \ - X(MUnion) \ - X(String) \ - X(Shader) \ - X(ShaderGroup) \ - X(SubShader) \ - X(Table) + X(Invalid) \ + X(Array) \ + X(Bake) \ + X(BakeInt) \ + X(BakeFloat) \ + X(BeginScope) \ + X(Emit) \ + X(Embed) \ + X(EndScope) \ + X(Enumeration) \ + X(Expand) \ + X(Flags) \ + X(MUnion) \ + X(PushConstants) \ + X(String) \ + X(Shader) \ + X(ShaderAlias) \ + X(ShaderGroup) \ + X(Table) \ typedef enum { #define X(k, ...) MetaEntryKind_## k, @@ -1071,6 +1072,7 @@ read_only global s8 meta_kind_c_types[] = { #undef X }; +#define META_CURRENT_LOCATION (MetaLocation){__LINE__, 0} typedef struct { u32 line, column; } MetaLocation; #define META_ENTRY_ARGUMENT_KIND_LIST \ @@ -1593,18 +1595,17 @@ typedef struct { } MetaIDList; typedef struct { - MetaIDList global_flag_ids; - MetaIDList shader_enumeration_ids; MetaShaderBakeParameters *bake_parameters; u32 name_id; - u32 flag_list_id; i32 base_shader_id; + u32 push_constants_id; + u32 flag_list_id; + MetaIDList shader_enumeration_ids; } MetaShader; DA_STRUCT(MetaShader, MetaShader); typedef struct { MetaShader *shader; - MetaIDList sub_shaders; s8 file; } MetaBaseShader; DA_STRUCT(MetaBaseShader, MetaBaseShader); @@ -1730,6 +1731,8 @@ typedef struct { s8_list table_names; MetaTableList tables; + MetaTableList push_constant_tables; + s8_list munion_namespaces; MetaMUnionList munions; @@ -1866,110 +1869,183 @@ meta_commit_shader_flag(MetaContext *ctx, u32 flag_list_id, s8 flag, MetaEntry * } function iz -meta_pack_shader(MetaContext *ctx, MetaShaderGroup *sg, Arena scratch, MetaEntry *entries, iz entry_count) +meta_fill_table(MetaContext *ctx, MetaEntry *e, iz entry_count, MetaTable *t) +{ + 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, e->kind); + + 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: %zu expected: %u\n", + meta_entry_kind_strings[e->kind], + 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 iz +meta_pack_shader_common(MetaContext *ctx, MetaShader *s, MetaEntry *e, iz entry_count, MetaEntryKind base_kind) +{ + iz result = 0; + switch(e->kind) { + + case MetaEntryKind_Enumeration:{ + meta_entry_argument_expected(e, s8("kind")); + s8 kind = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; + iz kid = meta_enumeration_id(ctx, kind); + meta_intern_id(ctx, &s->shader_enumeration_ids, + (u32)meta_intern_id(ctx, &ctx->shader_enumerations, (u32)kid)); + }break; + + case MetaEntryKind_PushConstants:{ + if (s->push_constants_id != (u32)-1) { + meta_entry_error(e, "invalid @%s in @%s: only one @%s allowed per @%s\n", + meta_entry_kind_strings[e->kind], meta_entry_kind_strings[base_kind], + meta_entry_kind_strings[e->kind], meta_entry_kind_strings[base_kind]); + } + + read_only local_persist s8 push_constant_fields[] = { + s8_comp("glsl_type"), + s8_comp("type"), + s8_comp("name"), + }; + + MetaTable *t = da_push(ctx->arena, &ctx->push_constant_tables); + t->fields = push_constant_fields; + t->field_count = countof(push_constant_fields); + + s->push_constants_id = (u32)da_index(t, &ctx->push_constant_tables); + + result = meta_fill_table(ctx, e, entry_count, t); + + if (t->entry_count > 32) + meta_entry_error(e, "maximum push constant parameters exceeded: limit: 32\n"); + }break; + + default:{ meta_entry_nesting_error(e, base_kind); }break; + } + + return result; +} + +function iz +meta_pack_compute_shader(MetaContext *ctx, MetaEntry *entries, iz entry_count, MetaShaderGroup *sg) { assert(entries[0].kind == MetaEntryKind_Shader); MetaShader *s = da_push(ctx->arena, &ctx->shaders); - *da_push(ctx->arena, &sg->shaders) = (u32)da_index(s, &ctx->shaders); { s8_list *flag_list = da_push(ctx->arena, &ctx->flags_for_shader); - s->flag_list_id = (u32)da_index(flag_list, &ctx->flags_for_shader); + s->flag_list_id = (u32)da_index(flag_list, &ctx->flags_for_shader); } - s->name_id = meta_pack_shader_name(ctx, entries->name, entries->location); - s->base_shader_id = -1; + s->name_id = meta_pack_shader_name(ctx, entries->name, entries->location); + s->push_constants_id = -1; + s->base_shader_id = -1; + + *da_push(ctx->arena, &sg->shaders) = (u32)da_index(s, &ctx->shaders); - MetaBaseShader *base_shader = 0; if (entries->argument_count > 1) { meta_entry_argument_expected(entries, s8("[file_name]")); } else if (entries->argument_count == 1) { - base_shader = da_push(ctx->arena, &ctx->base_shaders); - base_shader->file = meta_entry_argument_expect(entries, 0, MetaEntryArgumentKind_String).string; - base_shader->shader = s; - s->base_shader_id = (i32)da_index(base_shader, &ctx->base_shaders); + MetaBaseShader *bs = da_push(ctx->arena, &ctx->base_shaders); + bs->file = meta_entry_argument_expect(entries, 0, MetaEntryArgumentKind_String).string; + bs->shader = s; + s->base_shader_id = (u32)da_index(bs, &ctx->base_shaders); } - i32 stack_items[32]; - struct { i32 *data; iz capacity; iz count; } stack = {stack_items, countof(stack_items), 0}; + MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count); + if (scope.consumed > 1) { + for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) { + switch (e->kind) { + + case MetaEntryKind_ShaderAlias:{ + MetaShader *sa = da_push(ctx->arena, &ctx->shaders); + sa->base_shader_id = s->base_shader_id; + sa->name_id = meta_pack_shader_name(ctx, e->name, e->location); + sa->push_constants_id = -1; + *da_push(ctx->arena, &sg->shaders) = (u32)da_index(sa, &ctx->shaders); + meta_commit_shader_flag(ctx, s->flag_list_id, e->name, e); + }break; - iz result; - b32 in_sub_shader = 0; - for (result = 0; result < entry_count; result++) { - MetaEntry *e = entries + result; - switch (e->kind) { - case MetaEntryKind_BeginScope:{}break; - case MetaEntryKind_SubShader:{ - if (in_sub_shader) goto error; - in_sub_shader = 1; - } /* FALLTHROUGH */ - case MetaEntryKind_Shader: - { - *da_push(&scratch, &stack) = (i32)result; - if ((result + 1 < entry_count) && entries[result + 1].kind == MetaEntryKind_BeginScope) - break; - } /* FALLTHROUGH */ - case MetaEntryKind_EndScope:{ - i32 index = stack.data[--stack.count]; - MetaEntry *ended = entries + index; - if (index != 0) { - if (stack.count > 0 && entries[stack.data[stack.count - 1]].kind == MetaEntryKind_Shader) { - if (ended->kind == MetaEntryKind_SubShader) { - if (!base_shader) { - meta_entry_error(ended, "invalid nesting: @%s in @%s\n" - "@%s only allowed in base shaders (shaders with a backing file)\n", - meta_entry_kind_strings[ended->kind], - meta_entry_kind_strings[MetaEntryKind_Shader], - meta_entry_kind_strings[ended->kind]); - } - MetaShader *ss = da_push(ctx->arena, &ctx->shaders); - u32 sid = (u32)da_index(ss, &ctx->shaders); - *da_push(ctx->arena, &sg->shaders) = sid; - *da_push(ctx->arena, &base_shader->sub_shaders) = sid; - - ss->flag_list_id = s->flag_list_id; - ss->base_shader_id = s->base_shader_id; - ss->name_id = meta_pack_shader_name(ctx, ended->name, ended->location); - meta_commit_shader_flag(ctx, s->flag_list_id, ended->name, ended); - in_sub_shader = 0; - } + case MetaEntryKind_Flags:{ + meta_entry_argument_expected(e, s8("[flag ...]")); + MetaEntryArgument flags = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_Array); + for (u32 index = 0; index < flags.count; index++) + meta_commit_shader_flag(ctx, s->flag_list_id, flags.strings[index], e); + }break; + + case MetaEntryKind_Bake:{ + if (s->bake_parameters) { + meta_entry_error(e, "invalid @%s in @%s: only one @%s allowed per @%s\n", + meta_entry_kind_strings[e->kind], meta_entry_kind_strings[MetaEntryKind_Shader], + meta_entry_kind_strings[e->kind], meta_entry_kind_strings[MetaEntryKind_Shader]); } - } - }break; - case MetaEntryKind_Enumeration:{ - meta_entry_argument_expected(e, s8("kind")); - s8 kind = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; - iz kid = meta_enumeration_id(ctx, kind); - meta_intern_id(ctx, &s->shader_enumeration_ids, - (u32)meta_intern_id(ctx, &ctx->shader_enumerations, (u32)kid)); - }break; - case MetaEntryKind_Flags:{ - meta_entry_argument_expected(e, s8("[flag ...]")); - MetaEntryArgument flags = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_Array); - for (u32 index = 0; index < flags.count; index++) - meta_commit_shader_flag(ctx, s->flag_list_id, flags.strings[index], e); - }break; - case MetaEntryKind_Bake:{ - if (s->bake_parameters) { - meta_entry_error(e, "invalid @%s in @%s: only one @%s allowed per @%s\n", - meta_entry_kind_strings[e->kind], meta_entry_kind_strings[MetaEntryKind_Shader], - meta_entry_kind_strings[e->kind], meta_entry_kind_strings[MetaEntryKind_Shader]); - } - u32 table_id; - result += meta_pack_shader_bake_parameters(ctx, e, entry_count - result, (u32)da_index(s, &ctx->shaders), &table_id); - s->bake_parameters = ctx->shader_bake_parameters.data + table_id; - }break; + u32 table_id; + e += meta_pack_shader_bake_parameters(ctx, e, scope.one_past_last - e, + (u32)da_index(s, &ctx->shaders), &table_id); + s->bake_parameters = ctx->shader_bake_parameters.data + table_id; + }break; - default: - error: - { - meta_entry_nesting_error(e, MetaEntryKind_Shader); - }break; + default:{ + e += meta_pack_shader_common(ctx, s, e, scope.one_past_last - e, MetaEntryKind_Shader); + }break; + } } - if (stack.count == 0) - break; + } else { + assert(scope.consumed == 1); + // TODO(rnp): some functions (@Expand) expect no scope and that the next entry + // is treated as in scope; here we do not want that behaviour. + scope.consumed = 0; } + return scope.consumed; +} - return result; +function iz +meta_pack_shader_group(MetaContext *ctx, MetaEntry *entries, iz entry_count) +{ + assert(entries->kind == MetaEntryKind_ShaderGroup); + + MetaShaderGroup *sg = da_push(ctx->arena, &ctx->shader_groups); + sg->name = entries->name; + + MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count); + if (scope.consumed > 1) { + for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) { + switch (e->kind) { + case MetaEntryKind_Shader:{ + e += meta_pack_compute_shader(ctx, e, scope.one_past_last - e, sg); + }break; + default:{meta_entry_nesting_error(e, MetaEntryKind_ShaderGroup);}break; + } + } + } + return scope.consumed; } function void @@ -2503,41 +2579,7 @@ meta_pack_table(MetaContext *ctx, MetaEntry *e, iz entry_count) 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: %zu 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; + return meta_fill_table(ctx, e, entry_count, t); } function CommandList @@ -2652,7 +2694,7 @@ meta_expansion_part_conditional(MetaExpansionPart *p, u32 entry, s8 table_name, function void metagen_run_emit(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationList *ops, - s8 *evaluation_table) + MetaTableList *tables, s8 *evaluation_table) { for (iz opcode = 0; opcode < ops->count; opcode++) { MetaEmitOperation *op = ops->data + opcode; @@ -2670,8 +2712,10 @@ metagen_run_emit(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationList Arena scratch = m->scratch; MetaEmitOperationExpansion *eop = &op->expansion_operation; - MetaTable *t = ctx->tables.data + eop->table_id; - s8 table_name = ctx->table_names.data[t->table_name_id]; + MetaTable *t = tables->data + eop->table_id; + // TODO(rnp): table_names should be stored with the in the table list + s8 table_name = eop->table_id < ctx->table_names.count ? ctx->table_names.data[t->table_name_id] + : s8("(Unamed Table)"); u32 alignment_count = 1; u32 evaluation_count = 0; @@ -2754,7 +2798,7 @@ metagen_run_emit_set(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationL { for (iz set = 0; set < emit_set->count; set++) { MetaEmitOperationList *ops = emit_set->data + set; - metagen_run_emit(m, ctx, ops, evaluation_table); + metagen_run_emit(m, ctx, ops, &ctx->tables, evaluation_table); } } @@ -2806,8 +2850,9 @@ meta_push_shader_reload_info(MetaprogramContext *m, MetaContext *ctx) meta_end_scope(m, s8("};\n")); meta_begin_scope(m, s8("read_only global s8 beamformer_reloadable_shader_files[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) + for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { meta_push_line(m, s8("s8_comp(\""), ctx->base_shaders.data[shader].file, s8("\"),")); + } meta_end_scope(m, s8("};\n")); { @@ -2824,9 +2869,12 @@ meta_push_shader_reload_info(MetaprogramContext *m, MetaContext *ctx) u32 info_index = 0; for (iz group = 0; group < ctx->shader_groups.count; group++) { MetaShaderGroup *sg = ctx->shader_groups.data + group; - meta_begin_line(m, s8("read_only global i32 beamformer_reloadable_")); - for (iz i = 0; i < sg->name.len; i++) - stream_append_byte(&m->stream, TOLOWER(sg->name.data[i])); + meta_begin_line(m, s8("read_only global i32 beamformer_reloadable")); + for (iz i = 0; i < sg->name.len; i++) { + if IsUpper(sg->name.data[i]) + stream_append_byte(&m->stream, '_'); + stream_append_byte(&m->stream, ToLower(sg->name.data[i])); + } meta_begin_scope(m, s8("_shader_info_indices[] = {")); for (iz shader = 0; shader < sg->shaders.count; shader++) { @@ -2879,11 +2927,11 @@ meta_push_shader_reload_info(MetaprogramContext *m, MetaContext *ctx) meta_begin_scope(m, s8("read_only global u8 beamformer_shader_flag_strings_count[] = {")); for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - s8_list *flag_list = ctx->flags_for_shader.data + s->flag_list_id; + MetaShader *s = ctx->base_shaders.data[shader].shader; + u64 count = (u64)ctx->flags_for_shader.data[s->flag_list_id].count; meta_indent(m); - meta_push_u64(m, (u64)flag_list->count); + meta_push_u64(m, count); meta_end_line(m, s8(",")); } meta_end_scope(m, s8("};\n")); @@ -2893,52 +2941,56 @@ function void meta_push_shader_bake(MetaprogramContext *m, MetaContext *ctx) { for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; + MetaBaseShader *bs = ctx->base_shaders.data + shader; + MetaShader *s = bs->shader; + s8 shader_name = ctx->shader_names.data[s->name_id]; + meta_begin_line(m, s8("read_only global u8 beamformer_shader_")); for (iz i = 0; i < shader_name.len; i++) - stream_append_byte(&m->stream, TOLOWER(shader_name.data[i])); + stream_append_byte(&m->stream, ToLower(shader_name.data[i])); + meta_begin_scope(m, s8("_bytes[] = {")); { Arena scratch = m->scratch; - s8 filename = push_s8_from_parts(&scratch, s8(OS_PATH_SEPARATOR), s8("shaders"), - ctx->base_shaders.data[shader].file); - s8 file = read_entire_file((c8 *)filename.data, &scratch); + s8 filename = push_s8_from_parts(&scratch, s8(OS_PATH_SEPARATOR), s8("shaders"), bs->file); + s8 file = read_entire_file((c8 *)filename.data, &scratch); metagen_push_byte_array(m, file); } meta_end_scope(m, s8("};\n")); } meta_begin_scope(m, s8("read_only global s8 beamformer_shader_data[] = {")); { - Arena scratch = m->scratch; - s8 *columns[2]; - columns[0] = push_array(&m->scratch, s8, ctx->base_shaders.count); - columns[1] = push_array(&m->scratch, s8, ctx->base_shaders.count); for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; + MetaBaseShader *bs = ctx->base_shaders.data + shader; + MetaShader *s = bs->shader; + s8 shader_name = ctx->shader_names.data[s->name_id]; - Stream sb = arena_stream(m->scratch); + meta_begin_line(m, s8("{.data = beamformer_shader_")); for (iz i = 0; i < shader_name.len; i++) - stream_append_byte(&sb, TOLOWER(shader_name.data[i])); - stream_append_s8(&sb, s8("_bytes,")); - columns[0][shader] = arena_stream_commit_and_reset(&m->scratch, &sb); + stream_append_byte(&m->stream, ToLower(shader_name.data[i])); - stream_append_s8(&sb, s8(".len = countof(beamformer_shader_")); + meta_push(m, s8("_bytes, .len = countof(beamformer_shader_")); for (iz i = 0; i < shader_name.len; i++) - stream_append_byte(&sb, TOLOWER(shader_name.data[i])); - columns[1][shader] = arena_stream_commit(&m->scratch, &sb); + stream_append_byte(&m->stream, ToLower(shader_name.data[i])); + meta_end_line(m, s8("_bytes)},")); } - metagen_push_table(m, m->scratch, s8("{.data = beamformer_shader_"), s8("_bytes)},"), columns, - (uz)ctx->base_shaders.count, 2); - m->scratch = scratch; } meta_end_scope(m, s8("};\n")); } +function void +metagen_emit_c_s8_list(MetaprogramContext *m, s8 *strs, u32 count) +{ + meta_begin_scope(m, s8("(s8 []){")); + for (u32 index = 0; index < count; index++) + meta_push_line(m, s8("s8_comp(\""), strs[index], s8("\"),")); + meta_end_scope(m, s8("},")); +} + function b32 metagen_emit_c_code(MetaContext *ctx, Arena arena) { os_make_directory("generated"); char *out_meta = "generated" OS_PATH_SEPARATOR "beamformer.meta.c"; - char *out_shaders = "generated" OS_PATH_SEPARATOR "beamformer_shaders.c"; MetaprogramContext m[1] = {{.stream = arena_stream(arena), .scratch = ctx->scratch}}; @@ -2951,12 +3003,14 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) //////////////////////////// // NOTE(rnp): shader baking { - char **deps = push_array(&m->scratch, char *, ctx->base_shaders.count); + char *out_shaders = "generated" OS_PATH_SEPARATOR "beamformer_shaders.c"; + char **deps = push_array(&m->scratch, char *, 2 * ctx->base_shaders.count); + u32 dep_count = 0; for (iz i = 0; i < ctx->base_shaders.count; i++) { MetaBaseShader *b = ctx->base_shaders.data + i; - deps[i] = (c8 *)push_s8_from_parts(&m->scratch, s8(OS_PATH_SEPARATOR), s8("shaders"), b->file).data; + deps[dep_count++] = (c8 *)push_s8_from_parts(&m->scratch, s8(OS_PATH_SEPARATOR), s8("shaders"), b->file).data; } - if (needs_rebuild_(out_shaders, deps, ctx->base_shaders.count)) { + if (needs_rebuild_(out_shaders, deps, dep_count)) { build_log_generate("Bake Shaders"); meta_push(m, c_file_header); meta_push_shader_bake(m, ctx); @@ -2973,7 +3027,7 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) meta_push(m, c_file_header); ///////////////////////// - // NOTE(rnp): enumarents + // NOTE(rnp): enumerants for (iz kind = 0; kind < ctx->enumeration_kinds.count; kind++) { s8 enum_name = push_s8_from_parts(&m->scratch, s8(""), s8("Beamformer"), ctx->enumeration_kinds.data[kind]); metagen_push_c_enum(m, m->scratch, enum_name, ctx->enumeration_members.data[kind].data, @@ -2983,11 +3037,11 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { MetaShader *s = ctx->base_shaders.data[shader].shader; - s8_list flag_list = ctx->flags_for_shader.data[s->flag_list_id]; - if (flag_list.count) { + s8_list *flag_list = ctx->flags_for_shader.data + s->flag_list_id; + if (flag_list->count) { s8 enum_name = push_s8_from_parts(&m->scratch, s8(""), s8("BeamformerShader"), ctx->shader_names.data[s->name_id], s8("Flags")); - metagen_push_c_flag_enum(m, m->scratch, enum_name, flag_list.data, flag_list.count); + metagen_push_c_flag_enum(m, m->scratch, enum_name, flag_list->data, flag_list->count); m->scratch = ctx->scratch; } } @@ -3004,25 +3058,30 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) columns[0] = push_array(&m->scratch, s8, ctx->shader_groups.count * 3); columns[1] = push_array(&m->scratch, s8, ctx->shader_groups.count * 3); + u32 rows = 0; for (iz group = 0; group < ctx->shader_groups.count; group++) { MetaShaderGroup *sg = ctx->shader_groups.data + group; - s8 first_name = ctx->shader_names.data[ctx->shaders.data[sg->shaders.data[0]].name_id]; - s8 last_name = ctx->shader_names.data[ctx->shaders.data[sg->shaders.data[sg->shaders.count - 1]].name_id]; + if (sg->shaders.count > 0) { + s8 first_name = ctx->shader_names.data[ctx->shaders.data[sg->shaders.data[0]].name_id]; + s8 last_name = ctx->shader_names.data[ctx->shaders.data[sg->shaders.data[sg->shaders.count - 1]].name_id]; - columns[0][3 * group + 0] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), sg->name, s8("First")); - columns[1][3 * group + 0] = push_s8_from_parts(&m->scratch, s8(""), s8("= "), kind, s8("_"), first_name); + columns[0][3 * group + 0] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), sg->name, s8("First")); + columns[1][3 * group + 0] = push_s8_from_parts(&m->scratch, s8(""), s8("= "), kind, s8("_"), first_name); - columns[0][3 * group + 1] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), sg->name, s8("Last")); - columns[1][3 * group + 1] = push_s8_from_parts(&m->scratch, s8(""),s8("= "), kind, s8("_"), last_name); + columns[0][3 * group + 1] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), sg->name, s8("Last")); + columns[1][3 * group + 1] = push_s8_from_parts(&m->scratch, s8(""),s8("= "), kind, s8("_"), last_name); - columns[0][3 * group + 2] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), sg->name, s8("Count")); - Stream sb = arena_stream(m->scratch); - stream_append_s8(&sb, s8("= ")); - stream_append_u64(&sb, (u64)sg->shaders.count); - columns[1][3 * group + 2] = arena_stream_commit(&m->scratch, &sb); + columns[0][3 * group + 2] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), sg->name, s8("Count")); + Stream sb = arena_stream(m->scratch); + stream_append_s8(&sb, s8("= ")); + stream_append_u64(&sb, (u64)sg->shaders.count); + columns[1][3 * group + 2] = arena_stream_commit(&m->scratch, &sb); + + rows += 3; + } } - metagen_push_table(m, m->scratch, s8(""), s8(","), columns, (uz)ctx->shader_groups.count * 3, 2); + metagen_push_table(m, m->scratch, s8(""), s8(","), columns, rows, 2); meta_end_scope(m, s8("} "), kind, s8(";\n")); m->scratch = ctx->scratch; @@ -3032,6 +3091,8 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) // NOTE(rnp): structs for (u32 bake = 0; bake < ctx->shader_bake_parameters.count; bake++) { Arena tmp = m->scratch; + + // NOTE: Bake Parameters MetaShaderBakeParameters *b = ctx->shader_bake_parameters.data + bake; MetaShader *s = ctx->shaders.data + b->shader_id; s8 name = push_s8_from_parts(&m->scratch, s8(""), s8("BeamformerShader"), @@ -3045,6 +3106,40 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) m->scratch = tmp; } + + for (iz base_shader = 0; base_shader < ctx->base_shaders.count; base_shader++) { + Arena tmp = m->scratch; + + // NOTE: Push Constants + MetaShader *s = ctx->base_shaders.data[base_shader].shader; + if (s->push_constants_id != (u32)-1) { + MetaEmitOperationList ops[1] = {0}; + MetaTable *pc = ctx->push_constant_tables.data + s->push_constants_id; + + MetaEmitOperation *op = da_push(&m->scratch, ops); + op->kind = MetaEmitOperationKind_String; + op->string = s8("typedef struct {"); + + s8 expr = s8(" $(%type)$(|)$(name);"); + + MetaExpansionPartList parts = meta_generate_expansion_set(ctx, &m->scratch, expr, pc, META_CURRENT_LOCATION); + op = da_push(&m->scratch, ops); + op->kind = MetaEmitOperationKind_Expand; + op->expansion_operation.parts = parts.data; + op->expansion_operation.part_count = (u32)parts.count; + op->expansion_operation.table_id = s->push_constants_id; + + op = da_push(&m->scratch, ops); + op->kind = MetaEmitOperationKind_String; + op->string = push_s8_from_parts(&m->scratch, s8(""), s8("} BeamformerShader"), + ctx->shader_names.data[s->name_id], s8("PushConstants;")); + + metagen_run_emit(m, ctx, ops, &ctx->push_constant_tables, meta_kind_c_types); + } + + m->scratch = tmp; + } + // shader bake parameter struct meta_begin_scope(m, s8("typedef struct {")); { @@ -3084,14 +3179,10 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) meta_begin_scope(m, s8("read_only global i32 *beamformer_shader_header_vectors[] = {")); for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { MetaShader *s = ctx->base_shaders.data[shader].shader; - if (s->global_flag_ids.count || s->shader_enumeration_ids.count) { + if (s->shader_enumeration_ids.count) { meta_begin_line(m, s8("(i32 []){")); - for (iz id = 0; id < s->global_flag_ids.count; id++) { - if (id != 0) meta_push(m, s8(", ")); - meta_push_u64(m, s->global_flag_ids.data[id]); - } for (iz id = 0; id < s->shader_enumeration_ids.count; id++) { - if (id != 0 || s->global_flag_ids.count) meta_push(m, s8(", ")); + if (id != 0) meta_push(m, s8(", ")); meta_push_u64(m, s->shader_enumeration_ids.data[id]); } meta_end_line(m, s8("},")); @@ -3105,7 +3196,7 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { MetaShader *s = ctx->base_shaders.data[shader].shader; meta_indent(m); - meta_push_u64(m, (u64)(s->global_flag_ids.count + s->shader_enumeration_ids.count)); + meta_push_u64(m, (u64)s->shader_enumeration_ids.count); meta_end_line(m, s8(",")); } meta_end_scope(m, s8("};\n")); @@ -3114,10 +3205,7 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { MetaShader *s = ctx->base_shaders.data[shader].shader; if (s->bake_parameters) { - meta_begin_scope(m, s8("(s8 []){")); - for (u32 index = 0; index < s->bake_parameters->entry_count; index++) - meta_push_line(m, s8("s8_comp(\""), s->bake_parameters->names_upper[index], s8("\"),")); - meta_end_scope(m, s8("},")); + metagen_emit_c_s8_list(m, s->bake_parameters->names_upper, s->bake_parameters->entry_count); } else { meta_push_line(m, s8("0,")); } @@ -3127,8 +3215,11 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) meta_begin_scope(m, s8("read_only global u32 beamformer_shader_bake_parameter_float_bits[] = {")); for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { MetaShader *s = ctx->base_shaders.data[shader].shader; + u32 hex = 0; + if (s->bake_parameters) + hex = s->bake_parameters->floating_point; meta_begin_line(m, s8("0x")); - meta_push_u64_hex_width(m, s->bake_parameters? s->bake_parameters->floating_point : 0, 8); + meta_push_u64_hex_width(m, hex, 8); meta_end_line(m, s8("UL,")); } meta_end_scope(m, s8("};\n")); @@ -3146,6 +3237,57 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) } meta_end_scope(m, s8("};\n")); + meta_begin_scope(m, s8("read_only global s8 *beamformer_shader_push_constant_glsl_types[] = {")); + for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { + MetaShader *s = ctx->base_shaders.data[shader].shader; + if (s->push_constants_id != (u32)-1) { + MetaTable *pc = ctx->push_constant_tables.data + s->push_constants_id; + iz field = meta_lookup_string_slow(pc->fields, pc->field_count, s8("glsl_type")); + metagen_emit_c_s8_list(m, pc->entries[field], pc->entry_count); + } else { + meta_push_line(m, s8("0,")); + } + } + meta_end_scope(m, s8("};\n")); + + meta_begin_scope(m, s8("read_only global s8 *beamformer_shader_push_constant_names[] = {")); + for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { + MetaShader *s = ctx->base_shaders.data[shader].shader; + if (s->push_constants_id != (u32)-1) { + MetaTable *pc = ctx->push_constant_tables.data + s->push_constants_id; + iz field = meta_lookup_string_slow(pc->fields, pc->field_count, s8("name")); + metagen_emit_c_s8_list(m, pc->entries[field], pc->entry_count); + } else { + meta_push_line(m, s8("0,")); + } + } + meta_end_scope(m, s8("};\n")); + + meta_begin_scope(m, s8("read_only global u8 beamformer_shader_push_constant_counts[] = {")); + for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { + MetaShader *s = ctx->base_shaders.data[shader].shader; + if (s->push_constants_id != (u32)-1) { + meta_indent(m); + meta_push_u64(m, ctx->push_constant_tables.data[s->push_constants_id].entry_count); + meta_end_line(m, s8(",")); + } else { + meta_push_line(m, s8("0,")); + } + } + meta_end_scope(m, s8("};\n")); + + meta_begin_scope(m, s8("read_only global u8 beamformer_shader_push_constant_sizes[] = {")); + for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { + MetaShader *s = ctx->base_shaders.data[shader].shader; + if (s->push_constants_id != (u32)-1) { + meta_push_line(m, s8("sizeof(BeamformerShader"), ctx->shader_names.data[s->name_id], + s8("PushConstants),")); + } else { + meta_push_line(m, s8("0,")); + } + } + meta_end_scope(m, s8("};\n")); + //fprintf(stderr, "%.*s\n", (i32)m.stream.widx, m.stream.data); result = meta_write_and_reset(m, out_meta); @@ -3337,7 +3479,7 @@ metagen_emit_matlab_code(MetaContext *ctx, Arena arena) meta_begin_scope(m, s8("classdef OGLBeamformer"), name, s8(" < int32")); meta_begin_scope(m, s8("enumeration")); s8 prefix = s8(""); - if (kinds->count > 0 && ISDIGIT(kinds->data[0].data[0])) prefix = s8("m"); + if (kinds->count > 0 && IsDigit(kinds->data[0].data[0])) prefix = s8("m"); metagen_push_counted_enum_body(m, s8(""), prefix, s8("("), s8(")"), kinds->data, kinds->count); result &= meta_end_and_write_matlab(m, (c8 *)output.data); } @@ -3353,7 +3495,7 @@ metagen_emit_matlab_code(MetaContext *ctx, Arena arena) s8(OUTPUT("matlab") OS_PATH_SEPARATOR "OGLBeamformer"), ops->filename, s8(".m")); meta_push_line(m, s8("% GENERATED CODE")); - metagen_run_emit(m, ctx, ops, meta_kind_matlab_types); + metagen_run_emit(m, ctx, ops, &ctx->tables, meta_kind_matlab_types); result &= meta_write_and_reset(m, (c8 *)output.data); m->scratch = scratch; } @@ -3487,7 +3629,6 @@ metagen_load_context(Arena *arena, char *filename) i32 stack_items[32]; struct { i32 *data; iz capacity; iz count; } stack = {stack_items, countof(stack_items), 0}; - MetaShaderGroup *current_shader_group = 0; for (iz i = 0; i < entries.count; i++) { MetaEntry *e = entries.data + i; //if (e->kind == MetaEntryKind_EndScope) depth--; @@ -3496,15 +3637,8 @@ metagen_load_context(Arena *arena, char *filename) //continue; switch (e->kind) { - case MetaEntryKind_BeginScope:{ *da_push(&scratch, &stack) = (i32)(i - 1); }break; - case MetaEntryKind_EndScope:{ - i32 index = stack.data[--stack.count]; - MetaEntry *ended = entries.data + index; - switch (ended->kind) { - case MetaEntryKind_ShaderGroup:{ current_shader_group = 0; }break; - default:{}break; - } - }break; + case MetaEntryKind_BeginScope:{ *da_push(&scratch, &stack) = (i32)i; }break; + case MetaEntryKind_EndScope:{ --stack.count; }break; case MetaEntryKind_Emit:{ i += meta_pack_emit(ctx, scratch, e, entries.count - i); }break; @@ -3525,19 +3659,12 @@ metagen_load_context(Arena *arena, char *filename) meta_pack_munion(ctx, e, entries.count - i); }break; case MetaEntryKind_ShaderGroup:{ - MetaShaderGroup *sg = da_push(ctx->arena, &ctx->shader_groups); - sg->name = e->name; - current_shader_group = sg; - }break; - case MetaEntryKind_Shader:{ - if (!current_shader_group) goto error; - i += meta_pack_shader(ctx, current_shader_group, scratch, e, entries.count - i); + i += meta_pack_shader_group(ctx, e, entries.count - i); }break; case MetaEntryKind_Table:{ i += meta_pack_table(ctx, e, entries.count - i); }break; - error: default: { meta_entry_error(e, "invalid @%s() in global scope\n", meta_entry_kind_strings[e->kind]); diff --git a/generated/beamformer.meta.c b/generated/beamformer.meta.c @@ -154,6 +154,12 @@ typedef struct { } BeamformerShaderDASBakeParameters; typedef struct { + m4 xdc_transform; + m4 voxel_transform; + v2 xdc_element_pitch; +} BeamformerShaderDASPushConstants; + +typedef struct { union { BeamformerShaderDecodeBakeParameters Decode; BeamformerShaderFilterBakeParameters Filter; @@ -582,3 +588,47 @@ read_only global i32 beamformer_shader_bake_parameter_counts[] = { 0, }; +read_only global s8 *beamformer_shader_push_constant_glsl_types[] = { + 0, + 0, + (s8 []){ + s8_comp("mat4"), + s8_comp("mat4"), + s8_comp("vec2"), + }, + 0, + 0, + 0, +}; + +read_only global s8 *beamformer_shader_push_constant_names[] = { + 0, + 0, + (s8 []){ + s8_comp("xdc_transform"), + s8_comp("voxel_transform"), + s8_comp("xdc_element_pitch"), + }, + 0, + 0, + 0, +}; + +read_only global u8 beamformer_shader_push_constant_counts[] = { + 0, + 0, + 3, + 0, + 0, + 0, +}; + +read_only global u8 beamformer_shader_push_constant_sizes[] = { + 0, + 0, + sizeof(BeamformerShaderDASPushConstants), + 0, + 0, + 0, +}; + diff --git a/util.h b/util.h @@ -52,18 +52,14 @@ typedef u64 uptr; #ifdef _DEBUG #define DEBUG_EXPORT EXPORT - #if OS_WINDOWS - #ifdef _BEAMFORMER_DLL + #ifdef _BEAMFORMER_DLL + #if OS_WINDOWS #define DEBUG_IMPORT __declspec(dllimport) #else - #define DEBUG_IMPORT __declspec(dllexport) - #endif - #else - #ifdef _BEAMFORMER_DLL #define DEBUG_IMPORT extern - #else - #define DEBUG_IMPORT #endif + #else + #define DEBUG_IMPORT DEBUG_EXPORT #endif #define DEBUG_DECL(a) a #define assert(c) do { if (!(c)) debugbreak(); } while (0) @@ -125,14 +121,15 @@ typedef u64 uptr; #define Sign(a) ((a) < 0 ? -1 : 1) #define Between(x, a, b) ((x) >= (a) && (x) <= (b)) #define Clamp(x, a, b) ((x) < (a) ? (a) : (x) > (b) ? (b) : (x)) +#define Clamp01(x) Clamp(x, 0, 1) #define Min(a, b) ((a) < (b) ? (a) : (b)) #define Max(a, b) ((a) > (b) ? (a) : (b)) #define IsPowerOfTwo(a) (((a) & ((a) - 1)) == 0) -#define ISDIGIT(c) (BETWEEN((c), '0', '9')) -#define ISUPPER(c) (((c) & 0x20u) == 0) -#define TOLOWER(c) (((c) | 0x20u)) -#define TOUPPER(c) (((c) & ~(0x20u))) +#define IsDigit(c) (Between((c), '0', '9')) +#define IsUpper(c) (((c) & 0x20u) == 0) +#define ToLower(c) (((c) | 0x20u)) +#define ToUpper(c) (((c) & ~(0x20u))) #define f32_equal(x, y) (Abs((x) - (y)) <= F32_EPSILON * Max(1.0f, Max(Abs(x), Abs(y))))