ogl_beamforming

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

Commit: 9ef733de1af57e348cb63627f44b1fea0e135f9f
Parent: 07cbb9cf1e7d8ec3cd21e094e03c790c53bebd58
Author: Randy Palamar
Date:   Thu,  7 May 2026 13:11:23 -0600

meta: refactor meta code for providing true C interface while being MATLAB compatible

Diffstat:
Mbeamformer.meta | 268+++++++++++++++++++++++++------------------------------------------------------
Mbeamformer_shared_memory.c | 2+-
Mbuild.c | 1308+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mgenerated/beamformer.meta.c | 308+++++++++++++++++++++++++++++++++++--------------------------------------------
Mlib/ogl_beamformer_lib.c | 44++++++++++++++------------------------------
Mlib/ogl_beamformer_lib_base.h | 4+---
Mtests/throughput.c | 27++++++++++-----------------
Mutil.h | 13++++++++++---
8 files changed, 1238 insertions(+), 736 deletions(-)

diff --git a/beamformer.meta b/beamformer.meta @@ -1,7 +1,7 @@ @Constant(4) FilterSlots @Constant(16) MaxBacklogFrames @Constant(256) MaxChannelCount -@Constant(256) MaxEmmissionsCount +@Constant(256) MaxEmissionsCount @Constant(16) MaxComputeShaderStages @Constant(16) MaxParameterBlocks @Constant(3) MaxRawDataFramesInFlight @@ -61,6 +61,7 @@ [cycles F32] [frequency F32] } +@Library @Struct SineParameters @Struct ChirpParameters { @@ -68,15 +69,28 @@ [min_frequency F32] [max_frequency F32] } +@Library @Struct ChirpParameters -@MUnion(EmissionKind [ - SineParameters - ChirpParameters -]) Emission +@Table([type c_member m_member]) EmissionParametersTable +{ + [SineParameters sine Sine ] + [ChirpParameters chirp Chirp] +} +@Expand(EmissionParametersTable) @Union([`$(c_member)` `$(type)`]) EmissionParametersUnion +@Expand(EmissionParametersTable) @Union([`$(m_member)` `$(type)`]) EmissionParametersUnionMATLAB +@MATLAB(EmissionParameters) @Union EmissionParametersUnionMATLAB + +@Struct EmissionParameters +{ + [kind EmissionKind ] + [`` EmissionParametersUnion] +} +@Library @Struct EmissionParameters +@MATLAB(Emission) @Struct EmissionParameters @Table([name name_lower]) FilterKindTable { - [Kaiser kaiser] + [Kaiser kaiser ] [MatchedChirp matched_chirp] } @Expand(FilterKindTable) @Enumeration(`$(name)`) FilterKind @@ -87,18 +101,34 @@ [beta F32] [length U32] } +@Library @Struct KaiserFilterParameters -@Struct ChirpFilterParameters +@Struct MatchedChirpFilterParameters { [duration F32] [min_frequency F32] [max_frequency F32] } +@Library @Struct MatchedChirpFilterParameters -@MUnion(FilterKind [ - KaiserFilterParameters - ChirpFilterParameters -]) Filter +@Table([type c_member m_member]) FilterParametersTable +{ + [KaiserFilterParameters kaiser Kaiser ] + [MatchedChirpFilterParameters matched_chirp MatchedChirp] +} +@Expand(FilterParametersTable) @Union([`$(c_member)` `$(type)`]) FilterParametersUnion +@Expand(FilterParametersTable) @Union([`$(m_member)` `$(type)`]) FilterParametersUnionMATLAB +@MATLAB(FilterParameters) @Union FilterParametersUnionMATLAB + +@Struct FilterParameters +{ + [kind FilterKind ] + [sampling_frequency F32 ] + [complex B32 ] + [`` FilterParametersUnion] +} +@Library @Struct FilterParameters +@MATLAB(Filter) @Struct FilterParameters @Table([name pretty_name fixed_transmits]) AcquisitionKindTable { @@ -119,103 +149,69 @@ @Struct ParametersHead { - [das_voxel_transform M4] - [xdc_transform M4] - [xdc_element_pitch V2] - [raw_data_dimensions UV2] - [focal_vector V2] - [transmit_receive_orientation U32] - [sample_count U32] - [channel_count U32] - [acquisition_count U32] - [acquisition_kind U32] - [time_offset F32] - [single_focus U8] - [single_orientation U8] - [decode_mode U8] - [sampling_mode U8] + [das_voxel_transform M4 ] + [xdc_transform M4 ] + [xdc_element_pitch V2 ] + [raw_data_dimensions UV2 ] + [focal_vector V2 ] + [transmit_receive_orientation U32 ] + [sample_count U32 ] + [channel_count U32 ] + [acquisition_count U32 ] + [acquisition_kind AcquisitionKind] + [decode_mode DecodeMode ] + [sampling_mode SamplingMode ] + [time_offset F32 ] + [single_focus B32 ] + [single_orientation B32 ] } -@Struct ParametersUI +@Struct UIParameters { [output_points SV4] [sampling_frequency F32] [demodulation_frequency F32] [speed_of_sound F32] [f_number F32] - [interpolation_mode U32] - [coherency_weighting U32] + [interpolation_mode InterpolationMode] + [coherency_weighting B32] [decimation_rate U32] } -@Table([name c_type m_type m_size]) ParametersExtra +@Struct ExtraParameters { - [contrast_mode BeamformerContrastMode uint32 1] - [emission_kind BeamformerEmissionKind uint32 1] - [emission_parameters BeamformerEmissionParameters uint8 12] + [contrast_mode ContrastMode ] + [emission_parameters EmissionParameters] } -// TODO(rnp): allow emit statements to reference Constants -@Struct ParametersSimple +@Struct Parameters { - [channel_mapping S16 256] - [sparse_elements S16 256] - [transmit_receive_orientations U8 256] - [steering_angles F32 256] - [focal_depths F32 256] - [compute_stages S32 16] - [compute_stage_parameters S32 16] - [compute_stages_count U32 1] - [data_kind S32 1] + [`` ParametersHead ] + [`` UIParameters ] + [`` ExtraParameters] } +@Library @Struct Parameters +@MATLAB @Struct Parameters +@Struct SimpleParameters +{ + + [`` Parameters 1 ] + [channel_mapping S16 MaxChannelCount ] + [sparse_elements S16 MaxEmissionsCount ] + [transmit_receive_orientations U8 MaxEmissionsCount ] + [steering_angles F32 MaxEmissionsCount ] + [focal_depths F32 MaxEmissionsCount ] + [compute_stages S32 MaxComputeShaderStages] + [compute_stage_parameters S32 MaxComputeShaderStages] + [compute_stages_count U32 1 ] + [data_kind DataKind 1 ] +} +@Library @Struct SimpleParameters +@MATLAB @Struct SimpleParameters @Emit { - `typedef union {` - ` struct {` - @Expand(SineParameters) ` $(%type)$(|)$(name);` - ` } sine;` - ` struct {` - @Expand(ChirpParameters) ` $(%type)$(|)$(name);` - ` } chirp;` - `} BeamformerEmissionParameters;` - `` - `typedef struct {` - @Expand(ParametersHead) ` $(%type)$(|)$(name);` - @Expand(ParametersUI) ` $(%type)$(|)$(name);` - @Expand(ParametersExtra) ` $(c_type)$(|)$(name);` - `} BeamformerParameters;` - `` - `typedef struct {` - @Expand(ParametersUI) ` $(%type)$(|)$(name);` - `} BeamformerUIParameters;` - `` - `typedef struct {` - @Expand(ParametersExtra) ` $(c_type)$(|)$(name);` - `} BeamformerParametersExtra;` - `` - `typedef struct {` - @Expand(ParametersHead) ` $(%type)$(|)$(name);` - @Expand(ParametersUI) ` $(%type)$(|)$(name);` - @Expand(ParametersExtra) ` $(c_type)$(|)$(name);` - @Expand(ParametersSimple) ` $(%type)$(|)$(name)$(elements > 1 -> "[" elements "]");` - `} BeamformerSimpleParameters;` - `` - `typedef struct {` - ` BeamformerFilterKind kind;` - ` union {` - ` struct {` - @Expand(KaiserFilterParameters) ` $(%type)$(|)$(name);` - ` } kaiser;` - ` struct {` - @Expand(ChirpFilterParameters) ` $(%type)$(|)$(name);` - ` } matched_chirp;` - ` };` - ` f32 sampling_frequency;` - ` b16 complex;` - `} BeamformerFilterParameters;` - `` `read_only global u8 beamformer_data_kind_element_size[] = {` @Expand(DataKindTable) ` $(size),` `};` @@ -354,99 +350,3 @@ { @Shader(render_3d.frag.glsl) Render3D } - -///////////////// -// NOTE: Library - -@Emit(CLibrary) -{ - `typedef union {` - ` struct {` - @Expand(SineParameters) ` $(%type)$(|)$(name);` - ` } sine;` - ` struct {` - @Expand(ChirpParameters) ` $(%type)$(|)$(name);` - ` } chirp;` - `} BeamformerEmissionParameters;` - `` - `typedef struct {` - ` BeamformerFilterKind kind;` - ` union {` - ` struct {` - @Expand(KaiserFilterParameters) ` $(%type)$(|)$(name);` - ` } kaiser;` - ` struct {` - @Expand(ChirpFilterParameters) ` $(%type)$(|)$(name);` - ` } matched_chirp;` - ` };` - ` float sampling_frequency;` - ` uint16_t complex;` - `} BeamformerFilterParameters;` - `` - `typedef struct {` - @Expand(ParametersHead) ` $(%type)$(|)$(name)$(#type > 1 -> "[" #type "]");` - @Expand(ParametersUI) ` $(%type)$(|)$(name)$(#type > 1 -> "[" #type "]");` - @Expand(ParametersExtra) ` $(c_type)$(|)$(name);` - @Expand(ParametersSimple) ` $(%type)$(|)$(name)$(elements > 1 -> "[" elements "]");` - `} BeamformerSimpleParameters;` - `` - `typedef struct {` - @Expand(ParametersUI) ` $(%type)$(|)$(name)$(#type > 1 -> "[" #type "]");` - `} BeamformerUIParameters;` - `` - `typedef struct {` - @Expand(ParametersHead) ` $(%type)$(|)$(name)$(#type > 1 -> "[" #type "]");` - `} BeamformerParametersHead;` - `` - `typedef struct {` - @Expand(ParametersHead) ` $(%type)$(|)$(name)$(#type > 1 -> "[" #type "]");` - @Expand(ParametersUI) ` $(%type)$(|)$(name)$(#type > 1 -> "[" #type "]");` - @Expand(ParametersExtra) ` $(c_type)$(|)$(name);` - `} BeamformerParameters;` - `` -} - -//////////////// -// NOTE: MATLAB - -@Emit(MATLAB) Parameters -{ - `classdef OGLBeamformerParameters` - ` properties` - @Expand(ParametersHead) ` $(name)(1,$(#type))$(|)$(%type)` - ` % UI Parameters` - @Expand(ParametersUI) ` $(name)(1,$(#type))$(|)$(%type)` - @Expand(ParametersExtra) ` $(name)(1,$(m_size))$(|)$(m_type)` - ` end` - `end` -} - -@Emit(MATLAB) ParametersHead -{ - `classdef OGLBeamformerParametersHead` - ` properties` - @Expand(ParametersHead) ` $(name)(1,$(#type))$(|)$(%type)` - ` end` - `end` -} - -@Emit(MATLAB) ParametersUI -{ - `classdef OGLBeamformerParametersUI` - ` properties` - @Expand(ParametersUI) ` $(name)(1,$(#type))$(|)$(%type)` - ` end` - `end` -} - -@Emit(MATLAB) SimpleParameters -{ - `classdef OGLBeamformerSimpleParameters` - ` properties` - @Expand(ParametersHead) ` $(name)(1,$(#type)) $(%type)` - @Expand(ParametersUI) ` $(name)(1,$(#type)) $(%type)` - @Expand(ParametersExtra) ` $(name)(1,$(m_size)) $(m_type)` - @Expand(ParametersSimple) ` $(name)(1,$(elements)) $(%type)` - ` end` - `end` -} diff --git a/beamformer_shared_memory.c b/beamformer_shared_memory.c @@ -117,7 +117,7 @@ typedef struct { struct { BeamformerParametersHead parameters_head; BeamformerUIParameters parameters_ui; - BeamformerParametersExtra parameters_extra; + BeamformerExtraParameters parameters_extra; }; }; diff --git a/build.c b/build.c @@ -2,7 +2,12 @@ /* NOTE: inspired by nob: https://github.com/tsoding/nob.h */ /* TODO(rnp): - * [ ]: refactor: merge pack_table and bake_parameters + * [ ]: refactor: unify struct type paths + * - struct printing can do a stack traversal for sub types + * but it should not have other branching + * - basically we should flatten structs into a base type + * similar to ornot where we know the size of everything + * and all names are fully resolved * [ ]: refactor: allow @Expand to come before the table definition * [ ]: cross compile/override baked compiler * [ ]: msvc build doesn't detect out of date files correctly @@ -35,7 +40,7 @@ global char *g_argv0; #define COMMON_FLAGS "-std=c11", "-pipe", "-Wall" #define DEBUG_FLAGS "-O0", "-D_DEBUG", "-Wno-unused-function" #define OPTIMIZED_FLAGS "-O3" - #define EXTRA_FLAGS_BASE "-Werror", "-Wextra", "-Wshadow", "-Wno-unused-parameter", \ + #define EXTRA_FLAGS_BASE "-Werror", "-Wextra", "-Wno-unused-parameter", \ "-Wno-error=unused-function", "-fno-builtin" #if COMPILER_GCC #define EXTRA_FLAGS EXTRA_FLAGS_BASE, "-Wno-unused-variable" @@ -948,6 +953,8 @@ meta_push_(MetaprogramContext *m, s8 *items, iz count) #define meta_push_u64_hex(m, n) stream_append_hex_u64(&(m)->stream, (n)) #define meta_push_u64_hex_width(m, n, w) stream_append_hex_u64_width(&(m)->stream, (n), (w)) +#define MATLAB_NAMESPACE "OGL" + #define meta_begin_matlab_class_cracker(_1, _2, FN, ...) FN #define meta_begin_matlab_class_1(m, name) meta_begin_scope(m, s8("classdef " name)) #define meta_begin_matlab_class_2(m, name, type) \ @@ -985,7 +992,8 @@ meta_end_and_write_matlab(MetaprogramContext *m, char *path) X(EndScope) \ X(Enumeration) \ X(Expand) \ - X(MUnion) \ + X(Library) \ + X(MATLAB) \ X(PushConstants) \ X(Shader) \ X(ShaderAlias) \ @@ -993,6 +1001,7 @@ meta_end_and_write_matlab(MetaprogramContext *m, char *path) X(String) \ X(Struct) \ X(Table) \ + X(Union) \ typedef enum { #define X(k, ...) MetaEntryKind_## k, @@ -1057,32 +1066,32 @@ read_only global u8 meta_kind_elements[] = { #undef X }; -read_only global s8 meta_kind_meta_types[] = { - #define X(k, ...) s8_comp(#k), +read_only global str8 meta_kind_meta_types[] = { + #define X(k, ...) str8_comp(#k), META_KIND_LIST #undef X }; -read_only global s8 meta_kind_matlab_types[] = { - #define X(_k, _c, _g, _b, m, ...) s8_comp(#m), +read_only global str8 meta_kind_matlab_types[] = { + #define X(_k, _c, _g, _b, m, ...) str8_comp(#m), META_KIND_LIST #undef X }; -read_only global s8 meta_kind_base_c_types[] = { - #define X(_k, _c, _g, base, ...) s8_comp(#base), +read_only global str8 meta_kind_base_c_types[] = { + #define X(_k, _c, _g, base, ...) str8_comp(#base), META_KIND_LIST #undef X }; -read_only global s8 meta_kind_glsl_types[] = { - #define X(_k, _c, glsl, ...) s8_comp(#glsl), +read_only global str8 meta_kind_glsl_types[] = { + #define X(_k, _c, glsl, ...) str8_comp(#glsl), META_KIND_LIST #undef X }; -read_only global s8 meta_kind_c_types[] = { - #define X(_k, c, ...) s8_comp(#c), +read_only global str8 meta_kind_c_types[] = { + #define X(_k, c, ...) str8_comp(#c), META_KIND_LIST #undef X }; @@ -1594,22 +1603,14 @@ meta_entry_argument_expect(MetaEntry *e, u32 index, MetaEntryArgumentKind kind) return result; } +typedef struct { da_count value; } MetaEntityID; + typedef struct { da_count *data; da_count count; da_count capacity; } MetaIDList; -typedef struct { - s8 enumeration_name; - s8 *sub_table_names; - u32 sub_table_count; - u32 namespace_id; - - MetaLocation location; -} MetaMUnion; -DA_STRUCT(MetaMUnion, MetaMUnion); - typedef enum { MetaExpansionPartKind_Alignment, MetaExpansionPartKind_Conditional, @@ -1692,8 +1693,6 @@ typedef struct { da_count capacity; } MetaEmitOperationListSet; -typedef struct { da_count value; } MetaEntityID; - typedef enum { MetaShaderKind_Alias, MetaShaderKind_Compute, @@ -1731,7 +1730,7 @@ typedef struct { u32 field_count; u32 entry_count; union { - i32 *struct_type_ids; + i32 struct_info_id; }; } MetaTable; @@ -1754,35 +1753,38 @@ typedef struct { s8 reference_name; MetaEntityID resolved_id; da_count reference_count; + + // NOTE: only used for namespacing MATLAB unions + s8 scope_name; } MetaEntityReference; -#define META_ENTITY_KINDS \ - X(Nil, 0) \ - X(BakeParameters, 1) \ - X(Constant, 0) \ - X(Enumeration, 1) \ - X(PushConstants, 1) \ - X(Reference, 0) \ - X(Shader, 0) \ - X(ShaderGroup, 0) \ - X(Struct, 1) \ - X(Table, 1) \ - -read_only global s8 meta_entity_kind_names[] = { - #define X(name, ...) s8_comp(#name), - META_ENTITY_KINDS - #undef X -}; +// X(name, is_table, is_struct, struct_reference_target) +#define META_ENTITY_KIND_LIST \ + X(Nil, 0, 0, 0) \ + X(List, 0, 0, 0) \ + X(BakeParameters, 1, 1, 0) \ + X(Constant, 0, 0, 0) \ + X(Enumeration, 1, 0, 1) \ + X(PushConstants, 1, 1, 0) \ + X(Reference, 0, 0, 0) \ + X(ReferenceReference, 0, 0, 0) \ + X(Shader, 0, 0, 0) \ + X(ShaderGroup, 0, 0, 0) \ + X(Struct, 1, 1, 1) \ + X(Table, 1, 0, 0) \ + X(Union, 1, 1, 1) \ + +// X(EntityKind, TypeField, ElementsField, NameField, AllowReferences, Emit) +#define META_STRUCT_MAP_LIST \ + X(BakeParameters, MetaBakeField_Type, -1, MetaBakeField_NameLower, 0, 1) \ + X(PushConstants, MetaStructField_Type, MetaStructField_Elements, MetaStructField_Name, 0, 1) \ + X(Struct, MetaStructField_Type, MetaStructField_Elements, MetaStructField_Name, 1, 1) \ + X(Union, MetaStructField_Type, MetaStructField_Elements, MetaStructField_Name, 1, 0) \ -read_only global b8 meta_entity_kind_is_table[] = { - #define X(_n, table, ...) table, - META_ENTITY_KINDS - #undef X -}; typedef enum { #define X(name, ...) MetaEntityKind_ ##name, - META_ENTITY_KINDS + META_ENTITY_KIND_LIST #undef X MetaEntityKind_Count, } MetaEntityKind; @@ -1803,14 +1805,74 @@ typedef struct { } MetaEntity; DA_STRUCT(MetaEntity, MetaEntity); +#define X(name, ...) s8_comp(#name), +read_only global s8 meta_entity_kind_names[] = {META_ENTITY_KIND_LIST}; +#undef X +#define X(_n, table, ...) table, +read_only global b8 meta_entity_kind_is_table[] = {META_ENTITY_KIND_LIST}; +#undef X +#define X(_n, _t, s, ...) s, +read_only global b8 meta_entity_kind_is_struct[] = {META_ENTITY_KIND_LIST}; +#undef X +#define X(_n, _t, _s, srt, ...) srt, +read_only global b8 meta_entity_kind_struct_reference_target[] = {META_ENTITY_KIND_LIST}; +#undef X + +#define X(k, ...) MetaEntityKind_##k, +read_only global MetaEntityKind meta_struct_entity_kinds[] = {META_STRUCT_MAP_LIST}; +#undef X +#define X(_k, t, ...) t, +read_only global i32 meta_struct_type_field[] = {META_STRUCT_MAP_LIST}; +#undef X +#define X(_k, _t, e, ...) e, +read_only global i32 meta_struct_element_field[] = {META_STRUCT_MAP_LIST}; +#undef X +#define X(_k, _t, _e, n, ...) n, +read_only global i32 meta_struct_name_field[] = {META_STRUCT_MAP_LIST}; +#undef X +#define X(_k, _t, _e, _n, allow, ...) allow, +read_only global b8 meta_struct_allow_references[] = {META_STRUCT_MAP_LIST}; +#undef X +#define X(_k, _t, _e, _n, _a, emit, ...) emit, +read_only global b8 meta_struct_emit[] = {META_STRUCT_MAP_LIST}; +#undef X + +typedef enum { + MetaStructFlag_Union = 1 << 0, + MetaStructFlag_ContainsUnion = 1 << 1, +} MetaStructFlags; + +typedef enum { + MetaStructMemberFlag_ReferenceType = 1 << 0, + MetaStructMemberFlag_ReferenceElements = 1 << 1, +} MetaStructMemberFlags; + +typedef struct { + str8 name; + + str8 *members; + i32 *type_ids; + i32 *elements; + + MetaStructMemberFlags *member_flags; + + u32 member_count; + u32 byte_size; + + MetaStructFlags flags; + + MetaEntityID entity; + MetaLocation location; +} MetaStruct; + typedef struct { Arena *arena, scratch; s8 filename; s8 directory; - s8_list munion_namespaces; - MetaMUnionList munions; + MetaEntityID library_entity; + MetaEntityID matlab_entity; // NOTE(rnp): arrays of entity ids sorted by kind and counted by entity_kind_counts da_count *entity_kind_ids[MetaEntityKind_Count]; @@ -1822,6 +1884,10 @@ typedef struct { // NOTE(rnp): list of all entities referenced by shaders. needed for header string baking MetaIDList shader_entity_references; + // NOTE(rnp): fully resolved structs + MetaStruct *struct_infos; + u32 struct_infos_count; + // NOTE(rnp): dumb jank to support treating CudaHilbert/CudaDecode as shaders and // allowing shader names to alias. da_count base_shader_count; @@ -1829,6 +1895,7 @@ typedef struct { // NOTE(rnp): map index in the entity_kind_ids[MetaEntityKind_Shader] to base_shader_ids index da_count *base_shader_id_map; + MetaEmitOperationListSet emit_sets[MetaEmitLang_Count]; } MetaContext; @@ -1882,6 +1949,24 @@ meta_entity_children_count(MetaContext *ctx, MetaEntityID entity_id) return result; } +function da_count * +meta_entity_extract_children(MetaContext *ctx, MetaEntityID entity_id, da_count *children_count, Arena *arena) +{ + *children_count = meta_entity_children_count(ctx, entity_id); + da_count *result = push_array_no_zero(arena, da_count, *children_count); + + // NOTE(rnp): children are pushed in LIFO order + MetaEntity *e = ctx->entities.data + entity_id.value; + da_count index = 0; + MetaEntityID child = e->first_child; + do { + child = ctx->entities.data[child.value].previous_sibling; + result[index++] = child.value; + } while (child.value != e->first_child.value); + + return result; +} + function MetaEntity * meta_entity(MetaContext *ctx, MetaEntityID id) { @@ -1954,8 +2039,8 @@ meta_entity_reference(MetaContext *ctx, s8 name, MetaLocation location) Arena scratch; DeferLoop(scratch = ctx->scratch, ctx->scratch = scratch) { s8 ref_name = push_s8_from_parts(&ctx->scratch, s8(""), s8("R"), name); - result = meta_intern_entity(ctx, ref_name, MetaEntityKind_Reference, meta_root_entity_id(ctx), - location, 1); + result = meta_intern_entity(ctx, ref_name, MetaEntityKind_Reference, + meta_root_entity_id(ctx), location, 1); MetaEntity *r = meta_entity(ctx, result); if (r->reference.reference_count == 0) ctx->entity_names.data[result.value] = push_s8(ctx->arena, ref_name); @@ -1966,11 +2051,35 @@ meta_entity_reference(MetaContext *ctx, s8 name, MetaLocation location) } function MetaEntityID +meta_entity_reference_reference(MetaContext *ctx, s8 name, s8 scope_name, MetaLocation location, MetaEntityID parent, s8 prefix) +{ + MetaEntityID result = {0}; + // NOTE(rnp): base reference + MetaEntityID ref_id = meta_entity_reference(ctx, name, location); + + Arena scratch; + DeferLoop(scratch = ctx->scratch, ctx->scratch = scratch) { + s8 refref_name = push_s8_from_parts(&ctx->scratch, s8(""), prefix, s8("RR"), name); + result = meta_intern_entity(ctx, refref_name, MetaEntityKind_ReferenceReference, + parent, location, 1); + + MetaEntity *rr = meta_entity(ctx, result); + if (rr->reference.reference_count == 0) + ctx->entity_names.data[result.value] = push_s8(ctx->arena, refref_name); + rr->reference.reference_count++; + rr->reference.reference_name = name; + rr->reference.resolved_id = ref_id; + rr->reference.scope_name = scope_name; + } + return result; +} + +function MetaEntityID meta_entity_first_child_of_kind(MetaContext *ctx, MetaEntity *e, MetaEntityKind kind) { MetaEntityID result = {0}; MetaEntityID child = e->first_child; - do { + if (child.value) do { if (ctx->entities.data[child.value].kind == kind) { result = child; break; @@ -2003,6 +2112,7 @@ meta_pack_table_begin(MetaEntry *e, MetaTable *t) case MetaEntryKind_PushConstants: case MetaEntryKind_Struct: + case MetaEntryKind_Union: { meta_entry_argument_expected_(e, 0, 0); #define X(_i, name, ...) s8_comp(#name), @@ -2023,20 +2133,6 @@ meta_pack_table_begin(MetaEntry *e, MetaTable *t) } } -function void -meta_direct_enumeration(MetaContext *ctx, s8 name, s8 *variations, u64 count, MetaLocation location) -{ - MetaEntityID entity_id = meta_intern_entity(ctx, name, MetaEntityKind_Enumeration, - meta_root_entity_id(ctx), location, 0); - MetaEntry entry = {.kind = MetaEntryKind_Enumeration}; - MetaEntity *e = ctx->entities.data + entity_id.value; - meta_pack_table_begin(&entry, &e->table); - e->table.entries = push_array(ctx->arena, s8 *, 1); - e->table.entries[0] = push_array(ctx->arena, s8, count); - e->table.entry_count = count; - mem_copy(e->table.entries[0], variations, count * sizeof(*variations)); -} - function i64 meta_pack_table_entity(MetaContext *ctx, MetaEntry *e, i64 entry_count, s8 name, MetaEntityID parent) { @@ -2047,6 +2143,7 @@ meta_pack_table_entity(MetaContext *ctx, MetaEntry *e, i64 entry_count, s8 name, case MetaEntryKind_PushConstants:{entity_kind = MetaEntityKind_PushConstants; }break; case MetaEntryKind_Struct:{ entity_kind = MetaEntityKind_Struct; }break; case MetaEntryKind_Table:{ entity_kind = MetaEntityKind_Table; }break; + case MetaEntryKind_Union:{ entity_kind = MetaEntityKind_Union; }break; InvalidDefaultCase; } @@ -2055,7 +2152,9 @@ meta_pack_table_entity(MetaContext *ctx, MetaEntry *e, i64 entry_count, s8 name, MetaTable table = {0}, *t = &table; meta_pack_table_begin(e, t); - b32 structure = (e->kind == MetaEntryKind_Struct || e->kind == MetaEntryKind_PushConstants); + b32 structure = e->kind == MetaEntryKind_Struct || + e->kind == MetaEntryKind_PushConstants || + e->kind == MetaEntryKind_Union; MetaEntryScope scope = meta_entry_extract_scope(e, entry_count); if (scope.consumed > 1) { @@ -2076,7 +2175,7 @@ meta_pack_table_entity(MetaContext *ctx, MetaEntry *e, i64 entry_count, s8 name, meta_entry_kind_strings[e->kind], (size_t)entries.count, t->field_count); fprintf(stderr, " fields: ["); for (u64 i = 0; i < t->field_count; i++) { - if (i != 0) fprintf(stderr, ", "); + if (i != 0) fprintf(stderr, " "); fprintf(stderr, "%.*s", (i32)t->fields[i].len, t->fields[i].data); } fprintf(stderr, "]\n"); @@ -2113,10 +2212,7 @@ meta_pack_table_entity(MetaContext *ctx, MetaEntry *e, i64 entry_count, s8 name, case MetaEntryKind_Bake: case MetaEntryKind_PushConstants: case MetaEntryKind_Struct: - { - entity->table.struct_type_ids = push_array_no_zero(ctx->arena, i32, t->entry_count); - }break; - + case MetaEntryKind_Union: case MetaEntryKind_Enumeration: case MetaEntryKind_Table: {}break; @@ -2160,7 +2256,7 @@ meta_pack_shader_common(MetaContext *ctx, MetaEntityID shader_id, MetaEntry *e, { meta_entry_argument_expected(e); // TODO(rnp): MetaIDList.data should be of type MetaEntityID - MetaEntityID ref_id = meta_entity_reference(ctx, e->name, e->location); + MetaEntityID ref_id = meta_entity_reference(ctx, e->name, e->location); meta_intern_id(ctx, &meta_entity(ctx, shader_id)->shader.entity_reference_ids, ref_id.value); }break; @@ -2221,6 +2317,23 @@ meta_pack_shader_group(MetaContext *ctx, MetaEntry *entries, i64 entry_count) return scope.consumed; } +function i64 +meta_pack_references(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID parent, s8 scope_name, s8 prefix) +{ + MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count); + for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) { + switch (e->kind) { + case MetaEntryKind_Struct: + case MetaEntryKind_Union: + { + meta_entity_reference_reference(ctx, e->name, scope_name, e->location, parent, prefix); + }break; + default:{meta_entry_nesting_error(e, entries->kind);}break; + } + } + return scope.consumed; +} + function void meta_expansion_string_split(s8 string, s8 *left, s8 *inner, s8 *remainder, MetaLocation loc) { @@ -2567,7 +2680,25 @@ meta_generate_expansion_set(MetaContext *ctx, Arena *arena, s8 expansion_string, return result; } -function iz +function s8 * +meta_expand_to_s8_array(MetaContext *ctx, Arena scratch, s8 expand, MetaEntity *table, MetaLocation location) +{ + MetaExpansionPartList parts = meta_generate_expansion_set(ctx, &scratch, expand, table, location); + s8 *result = push_array(ctx->arena, s8, table->table.entry_count); + for EachIndex(table->table.entry_count, expansion) { + Stream sb = arena_stream(*ctx->arena); + for EachIndex((u64)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]); + } + result[expansion] = arena_stream_commit(ctx->arena, &sb); + } + return result; +} + +function i64 meta_expand(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count, MetaEmitOperationList *ops) { assert(e->kind == MetaEntryKind_Expand); @@ -2606,26 +2737,53 @@ meta_expand(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count, MetaE op->expansion_operation.part_count = (u32)parts.count; op->expansion_operation.table_entity_id = da_index(table, &ctx->entities); }break; + case MetaEntryKind_Enumeration:{ if (ops) meta_entry_nesting_error(row, MetaEntryKind_Emit); meta_entry_argument_expected(row, s8("`raw_string`")); s8 expand = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_String).string; - MetaExpansionPartList parts = meta_generate_expansion_set(ctx, &scratch, expand, table, row->location); - s8 *variations = push_array(&scratch, s8, table->table.entry_count); - for (u32 expansion = 0; expansion < table->table.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); + MetaEntityID entity_id = meta_intern_entity(ctx, row->name, MetaEntityKind_Enumeration, + meta_root_entity_id(ctx), row->location, 0); + MetaEntry entry = {.kind = MetaEntryKind_Enumeration}; + MetaEntity *new = ctx->entities.data + entity_id.value; + meta_pack_table_begin(&entry, &new->table); + new->table.entries = push_array(ctx->arena, s8 *, new->table.field_count); + new->table.entry_count = table->table.entry_count; + new->table.entries[0] = meta_expand_to_s8_array(ctx, scratch, expand, table, row->location); + }break; + + case MetaEntryKind_Union:{ + if (ops) meta_entry_nesting_error(row, MetaEntryKind_Emit); + MetaEntryArgument fields = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_Array); + if (fields.count != 2 && fields.count != 3) { + meta_compiler_error(row->location, "Invalid arguments in table expansion: '%.*s'\n" + "Union expansion requires field names for member names, type names, " + "and optionally element counts.\n", (i32)table_name.len, table_name.data); + } + + MetaEntityID entity_id = meta_intern_entity(ctx, row->name, MetaEntityKind_Union, + meta_root_entity_id(ctx), row->location, 0); + MetaEntry entry = {.kind = MetaEntryKind_Union}; + MetaEntity *new = ctx->entities.data + entity_id.value; + meta_pack_table_begin(&entry, &new->table); + new->table.entries = push_array(ctx->arena, s8 *, new->table.field_count); + new->table.entry_count = table->table.entry_count; + new->table.entries[MetaStructField_Name] = meta_expand_to_s8_array(ctx, scratch, fields.strings[0], + table, row->location); + new->table.entries[MetaStructField_Type] = meta_expand_to_s8_array(ctx, scratch, fields.strings[1], + table, row->location); + if (fields.count == 3) { + new->table.entries[MetaStructField_Elements] = meta_expand_to_s8_array(ctx, scratch, fields.strings[2], + table, row->location); + } else { + new->table.entries[MetaStructField_Elements] = push_array(ctx->arena, s8, table->table.entry_count); + for EachIndex(new->table.entry_count, entry) + new->table.entries[MetaStructField_Elements][entry] = s8("1"); } - meta_direct_enumeration(ctx, row->name, variations, table->table.entry_count, e->location); }break; + error: default: { @@ -2664,7 +2822,7 @@ meta_embed(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count) function MetaKind meta_map_kind(s8 kind, s8 table_name, MetaLocation location) { - iz id = meta_lookup_string_slow(meta_kind_meta_types, MetaKind_Count, kind); + i64 id = meta_lookup_string_slow((s8 *)meta_kind_meta_types, MetaKind_Count, kind); if (id < 0) { meta_compiler_error(location, "Invalid Kind in '%.*s' table expansion: %.*s\n", (i32)table_name.len, table_name.data, (i32)kind.len, kind.data); @@ -2696,7 +2854,8 @@ meta_pack_constant(MetaContext *ctx, MetaEntry *e) { assert(e->kind == MetaEntryKind_Constant); - MetaEntityID entity_id = meta_intern_entity(ctx, e->name, MetaEntityKind_Constant, meta_root_entity_id(ctx), e->location, 0); + MetaEntityID entity_id = meta_intern_entity(ctx, e->name, MetaEntityKind_Constant, + meta_root_entity_id(ctx), e->location, 0); meta_entry_argument_expected(e, s8("value")); s8 value = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; @@ -2717,8 +2876,8 @@ meta_pack_constant(MetaContext *ctx, MetaEntry *e) } } -function iz -meta_pack_emit(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count) +function i64 +meta_pack_emit(MetaContext *ctx, Arena scratch, MetaEntry *e, i64 entry_count) { assert(e->kind == MetaEntryKind_Emit); @@ -2751,30 +2910,6 @@ meta_pack_emit(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count) return scope.consumed; } -function void -meta_pack_munion(MetaContext *ctx, MetaEntry *e, iz entry_count) -{ - assert(e->kind == MetaEntryKind_MUnion); - - MetaMUnion *mu = da_push(ctx->arena, &ctx->munions); - mu->location = e->location; - - iz namespace_id = meta_lookup_string_slow(ctx->munion_namespaces.data, - ctx->munion_namespaces.count, e->name); - if (namespace_id >= 0) meta_entry_error(e, "MUnion redefined\n"); - - s8 *m_name = da_push(ctx->arena, &ctx->munion_namespaces); - mu->namespace_id = (u32)da_index(m_name, &ctx->munion_namespaces); - *m_name = e->name; - - meta_entry_argument_expected(e, s8("enumeration_name"), s8("[parameter_table_name ...]")); - - MetaEntryArgument sub_tables = meta_entry_argument_expect(e, 1, MetaEntryArgumentKind_Array); - mu->enumeration_name = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; - mu->sub_table_names = sub_tables.strings; - mu->sub_table_count = (u32)sub_tables.count; -} - function CommandList meta_extract_emit_file_dependencies(MetaContext *ctx, Arena *arena) { @@ -2810,7 +2945,7 @@ metagen_push_byte_array(MetaprogramContext *m, s8 bytes) } function void -metagen_push_table(MetaprogramContext *m, Arena scratch, s8 row_start, s8 row_end, +metagen_push_table(MetaprogramContext *m, Arena scratch, str8 row_start, str8 row_end, s8 **column_strings, uz rows, uz columns) { u32 *column_widths = 0; @@ -2824,7 +2959,7 @@ metagen_push_table(MetaprogramContext *m, Arena scratch, s8 row_start, s8 row_en } for (uz row = 0; row < rows; row++) { - meta_begin_line(m, row_start); + meta_begin_line(m, s8_from_str8(row_start)); for (uz column = 0; column < columns; column++) { s8 text = column_strings[column][row]; meta_push(m, text); @@ -2833,7 +2968,7 @@ metagen_push_table(MetaprogramContext *m, Arena scratch, s8 row_start, s8 row_en pad += (i32)column_widths[column] - (i32)text.len; if (column < columns - 1) meta_pad(m, ' ', pad); } - meta_end_line(m, row_end); + meta_end_line(m, s8_from_str8(row_end)); } } @@ -2974,7 +3109,7 @@ metagen_run_emit(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationList columns[column][entry] = arena_stream_commit_and_reset(&scratch, &sb); } - metagen_push_table(m, scratch, s8(""), s8(""), columns, t->entry_count, alignment_count); + metagen_push_table(m, scratch, str8(""), str8(""), columns, t->entry_count, alignment_count); }break; InvalidDefaultCase; } @@ -2992,6 +3127,16 @@ metagen_run_emit_set(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationL } } +function i32 +meta_struct_member_elements(MetaContext *ctx, MetaStruct *s, u32 member) +{ + assert(member < s->member_count); + i32 result = s->elements[member]; + if (s->member_flags[member] & MetaStructMemberFlag_ReferenceElements) + result = (i32)meta_entity(ctx, (MetaEntityID){result})->constant.U64; + return result; +} + function void metagen_push_counted_enum_body(MetaprogramContext *m, s8 kind, s8 prefix, s8 mid, s8 suffix, s8 *ids, iz ids_count) { @@ -3035,32 +3180,240 @@ metagen_push_c_enum(MetaprogramContext *m, Arena scratch, s8 kind, s8 *ids, iz i meta_end_scope(m, s8("} "), kind, s8(";\n")); } -function void -metagen_push_struct_body(MetaprogramContext *m, MetaTable *s, s8 *types, s8 *members, s8 *elements, - s8 prefix, s8 suffix, s8 str_elements_prefix) +function u32 +meta_struct_flattened_member_count(Arena scratch, MetaContext *ctx, MetaStruct *meta_struct) { - i64 max_type_name_length = 0; - for (u32 member = 0; member < s->entry_count; member++) { - i32 id = s->struct_type_ids[member]; - max_type_name_length = Max(max_type_name_length, types[id].len); + struct stack_item {MetaStruct *s; u32 member_offset;} init[16]; + struct { + struct stack_item *data; + da_count count; + da_count capacity; + } stack = {init, 0, countof(init)}; + + u32 result = 0; + *da_push(&scratch, &stack) = (struct stack_item){meta_struct, 0}; + while (stack.count > 0) { + stack.count--; + MetaStruct *s = stack.data[stack.count].s; + u32 member = stack.data[stack.count].member_offset; + while (member < s->member_count) { + if (s->members[member].length == 0) { + assert(s->member_flags[member] & MetaStructMemberFlag_ReferenceType); + MetaStruct *ss = ctx->struct_infos + ctx->entities.data[s->type_ids[member]].table.struct_info_id; + if (ss->flags & MetaStructFlag_Union) { + member++; + result++; + } else { + *da_push(&scratch, &stack) = (struct stack_item){s, member + 1}; + *da_push(&scratch, &stack) = (struct stack_item){ss, 0}; + break; + } + } else { + member++; + result++; + } + } } + return result; +} + +typedef enum { + MetaPushStructStyle_C, + MetaPushStructStyle_MATLAB, + MetaPushStructStyle_Count, +} MetaPushStructStyle; + +typedef struct { + MetaPushStructStyle layout_style; + MetaPushStructStyle union_style; + MetaPushStructStyle element_count_style; + str8 *base_types; + str8 prefix; + str8 suffix; + str8 str_element_prefix; +} MetaPushStructParameters; + +function void +meta_push_struct_body(MetaContext *ctx, MetaprogramContext *m, MetaEntity *struct_entity, + MetaPushStructParameters p) +{ + MetaStruct *meta_struct = ctx->struct_infos + struct_entity->table.struct_info_id; + struct stack_item {MetaEntity *se; u32 member_offset;} init[16]; + struct { + struct stack_item *data; + da_count count; + da_count capacity; + } stack = {init, 0, countof(init)}; + + u32 flattened_member_count = meta_struct_flattened_member_count(m->scratch, ctx, meta_struct); + + s8 *columns[2]; + columns[0] = push_array(&m->scratch, s8, flattened_member_count); + columns[1] = push_array(&m->scratch, s8, flattened_member_count); + + u32 row = 0, scope = 0; + *da_push(&m->scratch, &stack) = (struct stack_item){struct_entity, 0}; + while (stack.count > 0) { + stack.count--; + MetaEntity *se = stack.data[stack.count].se; + MetaStruct *s = ctx->struct_infos + se->table.struct_info_id; + u32 member = stack.data[stack.count].member_offset; + + while (member < s->member_count) { + b32 type_reference = (s->member_flags[member] & MetaStructMemberFlag_ReferenceType) != 0; + i32 type_id = s->type_ids[member]; + s8 member_name = s8_from_str8(s->members[member]); + + assert(member_name.len != 0 || type_reference); + + if (s->members[member].length == 0 && + (p.union_style != MetaPushStructStyle_MATLAB || ctx->entities.data[type_id].kind != MetaEntityKind_Union)) + { + *da_push(&m->scratch, &stack) = (struct stack_item){se, member + 1}; + *da_push(&m->scratch, &stack) = (struct stack_item){ctx->entities.data + type_id, 0}; + + MetaStruct *ss = ctx->struct_infos + ctx->entities.data[type_id].table.struct_info_id; + if (p.layout_style == MetaPushStructStyle_C && ss->flags & MetaStructFlag_Union) { + metagen_push_table(m, m->scratch, p.prefix, p.suffix, columns, row, 2); + meta_begin_scope(m, s8("union {")); + row = 0; + scope++; + } + + break; + } else { + Stream sb = arena_stream(m->scratch); + + b32 elements_reference = (s->member_flags[member] & MetaStructMemberFlag_ReferenceElements) != 0; + + // NOTE(rnp): member name column + { + read_only local_persist str8 elements_count_open[MetaPushStructStyle_Count] = { + [MetaPushStructStyle_C] = str8_comp("["), + [MetaPushStructStyle_MATLAB] = str8_comp("("), + }; + read_only local_persist str8 elements_count_close[MetaPushStructStyle_Count] = { + [MetaPushStructStyle_C] = str8_comp("]"), + [MetaPushStructStyle_MATLAB] = str8_comp(")"), + }; + read_only local_persist i32 name_column[MetaPushStructStyle_Count] = { + [MetaPushStructStyle_C] = 1, + [MetaPushStructStyle_MATLAB] = 0, + }; + + u32 resolved_element_count = meta_struct_member_elements(ctx, s, member); + + if (p.union_style == MetaPushStructStyle_MATLAB) { + if (type_reference) { + MetaEntity *re = ctx->entities.data + type_id; + MetaStruct *rs = ctx->struct_infos + re->table.struct_info_id; + if (member_name.len == 0) { + assert(rs->flags & MetaStructFlag_Union); + member_name = s8("data"); + } + if (rs->flags & MetaStructFlag_Union) + resolved_element_count *= rs->byte_size; + } else { + resolved_element_count *= meta_kind_elements[type_id]; + } + } + + if (resolved_element_count > 1 || p.element_count_style == MetaPushStructStyle_MATLAB) { + stream_append_s8s(&sb, member_name, s8_from_str8(elements_count_open[p.layout_style])); + if (elements_reference && p.element_count_style != MetaPushStructStyle_MATLAB) { + stream_append_s8s(&sb, s8_from_str8(p.str_element_prefix), ctx->entity_names.data[s->elements[member]]); + } else { + if (p.element_count_style == MetaPushStructStyle_MATLAB) + stream_append_s8(&sb, s8("1, ")); + stream_append_u64(&sb, resolved_element_count); + } + stream_append_s8(&sb, s8_from_str8(elements_count_close[p.layout_style])); + columns[name_column[p.layout_style]][row] = arena_stream_commit_and_reset(&m->scratch, &sb); + } else { + columns[name_column[p.layout_style]][row] = member_name; + } + } + + // NOTE(rnp): type column + { + read_only local_persist i32 type_column[MetaPushStructStyle_Count] = { + [MetaPushStructStyle_C] = 0, + [MetaPushStructStyle_MATLAB] = 1, + }; + + if (type_reference) { + MetaEntity *re = ctx->entities.data + type_id; + MetaStruct *rs = 0; + + if (meta_entity_kind_is_struct[re->kind]) + rs = ctx->struct_infos + re->table.struct_info_id; + + if (rs && rs->flags & MetaStructFlag_Union && p.union_style == MetaPushStructStyle_MATLAB) { + stream_append_s8(&sb, s8_from_str8(p.base_types[MetaKind_U8])); + if (p.layout_style == MetaPushStructStyle_MATLAB) + stream_append_s8(&sb, s8(" % +")); + } else if (re->kind == MetaEntityKind_Enumeration && p.layout_style == MetaPushStructStyle_MATLAB) { + // NOTE(rnp): matlab enumerations are int32 if we make this uint32 + // MATLAB won't fuck up the type when the field is assigned + stream_append_s8(&sb, s8_from_str8(p.base_types[MetaKind_U32])); + if (p.layout_style == MetaPushStructStyle_MATLAB) + stream_append_s8(&sb, s8(" % ")); + } else { + if (p.layout_style == MetaPushStructStyle_MATLAB) { + // NOTE(rnp): matlab has really broken requirements around sub structures + // we can only use an opaque struct here + stream_append_s8(&sb, s8("struct % ")); + } else { + s8 name = rs ? s8_from_str8(rs->name) : ctx->entity_names.data[type_id]; + stream_append_s8s(&sb, s8_from_str8(p.str_element_prefix), name); + } + } + + if (p.layout_style == MetaPushStructStyle_MATLAB) { + stream_append_s8s(&sb, s8_from_str8(p.str_element_prefix), + rs ? s8_from_str8(rs->name) : ctx->entity_names.data[type_id]); + } + + columns[type_column[p.layout_style]][row] = arena_stream_commit_and_reset(&m->scratch, &sb); + } else { + columns[type_column[p.layout_style]][row] = s8_from_str8(p.base_types[type_id]); + } + } + + row++; + member++; + } + } - for (u32 member = 0; member < s->entry_count; member++) { - i32 id = s->struct_type_ids[member]; - s8 kind = types[id]; - i64 length = kind.len; - - meta_begin_line(m, prefix, kind); - meta_pad(m, ' ', 1 + (i32)(max_type_name_length - length)); - meta_push(m, members[member]); - if (elements && (elements[member].len > 1 || elements[member].data[0] != '1')) { - meta_push(m, s8("["), IsDigit(elements[member].data[0])? s8("") : str_elements_prefix, - elements[member], s8("]")); + if (member == s->member_count && s->flags & MetaStructFlag_Union && p.layout_style == MetaPushStructStyle_C) { + metagen_push_table(m, m->scratch, p.prefix, p.suffix, columns, row, 2); + while (scope > 0) { + meta_end_scope(m, s8("};")); + scope--; + } + row = 0; } - meta_end_line(m, s8(";"), suffix); } + metagen_push_table(m, m->scratch, p.prefix, p.suffix, columns, row, 2); +} + +function void +meta_push_matlab_properties(MetaprogramContext *m, MetaContext *ctx, MetaStruct *meta_struct) +{ + meta_begin_scope(m, s8("properties")); + { + meta_push_struct_body(ctx, m, meta_entity(ctx, meta_struct->entity), (MetaPushStructParameters){ + .layout_style = MetaPushStructStyle_MATLAB, + .union_style = MetaPushStructStyle_MATLAB, + .element_count_style = MetaPushStructStyle_MATLAB, + .base_types = meta_kind_matlab_types, + .suffix = str8(""), + .str_element_prefix = str8(MATLAB_NAMESPACE META_NAMESPACE_UPPER), + }); + } meta_end_scope(m, s8("end")); } + function void meta_push_shader_reload_info(MetaprogramContext *m, MetaContext *ctx) { @@ -3146,8 +3499,14 @@ meta_push_shader_reload_info(MetaprogramContext *m, MetaContext *ctx) case MetaEntityKind_Struct:{ meta_push_line(m, s8("s8_comp(\"\"")); meta_push_line(m, s8("\"struct "), entity_name, s8(" {\\n\"")); - metagen_push_struct_body(m, &e->table, meta_kind_glsl_types, e->table.entries[MetaStructField_Name], - e->table.entries[MetaStructField_Elements], s8("\" "), s8("\\n\""), s8("")); + meta_push_struct_body(ctx, m, e, (MetaPushStructParameters){ + .layout_style = MetaPushStructStyle_C, + .union_style = MetaPushStructStyle_C, + .element_count_style = MetaPushStructStyle_C, + .base_types = meta_kind_glsl_types, + .prefix = str8("\" "), + .suffix = str8("\\n\""), + }); meta_push_line(m, s8("\"};\\n\"")); meta_push_line(m, s8("\"\\n\"),")); }break; @@ -3155,8 +3514,14 @@ meta_push_shader_reload_info(MetaprogramContext *m, MetaContext *ctx) case MetaEntityKind_PushConstants:{ meta_push_line(m, s8("s8_comp(\"\"")); meta_push_line(m, s8("\"layout(std140, binding = 0) uniform PushConstants {\\n\"")); - metagen_push_struct_body(m, &e->table, meta_kind_glsl_types, e->table.entries[MetaStructField_Name], - e->table.entries[MetaStructField_Elements], s8("\" "), s8("\\n\""), s8("")); + meta_push_struct_body(ctx, m, e, (MetaPushStructParameters){ + .layout_style = MetaPushStructStyle_C, + .union_style = MetaPushStructStyle_C, + .element_count_style = MetaPushStructStyle_C, + .base_types = meta_kind_glsl_types, + .prefix = str8("\" "), + .suffix = str8(";\\n\""), + }); meta_push_line(m, s8("\"};\\n\"")); meta_push_line(m, s8("\"\\n\"),")); }break; @@ -3296,7 +3661,7 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) row_count++; } } - metagen_push_table(m, m->scratch, s8("#define " META_NAMESPACE_UPPER), s8(")"), columns, row_count, 2); + metagen_push_table(m, m->scratch, str8("#define " META_NAMESPACE_UPPER), str8(")"), columns, row_count, 2); row_count = 0; meta_push_line(m, s8("\n// NOTE: Constants (Float)")); @@ -3312,7 +3677,7 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) row_count++; } } - metagen_push_table(m, m->scratch, s8("#define " META_NAMESPACE_UPPER), s8(")"), columns, row_count, 2); + metagen_push_table(m, m->scratch, str8("#define " META_NAMESPACE_UPPER), str8(")"), columns, row_count, 2); m->scratch = ctx->scratch; } @@ -3371,7 +3736,7 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) rows += 3; } } - metagen_push_table(m, m->scratch, s8(""), s8(","), columns, rows, 2); + metagen_push_table(m, m->scratch, str8(""), str8(","), columns, rows, 2); meta_end_scope(m, s8("} "), kind, s8(";\n")); m->scratch = ctx->scratch; @@ -3380,21 +3745,23 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) ////////////////////// // NOTE(rnp): structs { - MetaEntityKind struct_kinds[] = {MetaEntityKind_Struct, MetaEntityKind_PushConstants, MetaEntityKind_BakeParameters}; - da_count element_ids[] = {MetaStructField_Elements, MetaStructField_Elements, -1}; - da_count name_ids[] = {MetaStructField_Name, MetaStructField_Name, MetaBakeField_NameLower}; - for EachElement(struct_kinds, kind_it) { - for (da_count it = 0; it < ctx->entity_kind_counts[struct_kinds[kind_it]]; it++) { - da_count entity = ctx->entity_kind_ids[struct_kinds[kind_it]][it]; - - MetaEntity *e = ctx->entities.data + entity; - meta_begin_scope(m, s8("typedef struct {")); { - s8 *elements = element_ids[kind_it] < 0 ? 0 : e->table.entries[element_ids[kind_it]]; - - metagen_push_struct_body(m, &e->table, meta_kind_c_types, e->table.entries[name_ids[kind_it]], - elements, s8(""), s8(""), s8(META_NAMESPACE_UPPER)); - } meta_end_scope(m, s8("} " META_NAMESPACE_UPPER), ctx->entity_names.data[entity], s8(";")); - meta_push(m, s8("\n")); + for EachElement(meta_struct_entity_kinds, kind_it) { + if (meta_struct_emit[kind_it]) { + for (da_count it = 0; it < ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; it++) { + da_count entity = ctx->entity_kind_ids[meta_struct_entity_kinds[kind_it]][it]; + + meta_begin_scope(m, s8("typedef struct {")); { + meta_push_struct_body(ctx, m, ctx->entities.data + entity, (MetaPushStructParameters){ + .layout_style = MetaPushStructStyle_C, + .union_style = MetaPushStructStyle_C, + .element_count_style = MetaPushStructStyle_C, + .base_types = meta_kind_c_types, + .suffix = str8(";"), + .str_element_prefix = str8(META_NAMESPACE_UPPER), + }); + } meta_end_scope(m, s8("} " META_NAMESPACE_UPPER), ctx->entity_names.data[entity], s8(";")); + meta_push(m, s8("\n")); + } } } } @@ -3418,12 +3785,12 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) columns[0][bake] = push_s8_from_parts(&m->scratch, s8(""), s8(META_NAMESPACE_UPPER), bake_name); columns[1][bake] = shader_name; } - metagen_push_table(m, m->scratch, s8(""), s8(";"), columns, + metagen_push_table(m, m->scratch, str8(""), str8(";"), columns, ctx->entity_kind_counts[MetaEntityKind_BakeParameters], 2); } } meta_end_scope(m, s8("} " META_NAMESPACE_UPPER "ShaderBakeParameters;\n")); - metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_C, meta_kind_c_types); + metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_C, (s8 *)meta_kind_c_types); ///////////////////////////////// // NOTE(rnp): shader info tables @@ -3490,10 +3857,13 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) MetaEntityID bp_id = meta_entity_first_child_of_kind(ctx, e, MetaEntityKind_BakeParameters); u32 hex = 0; if (bp_id.value != 0) { - MetaTable *t = &ctx->entities.data[bp_id.value].table; - for (u32 entry = 0; entry < t->entry_count; entry++) - if (t->struct_type_ids[entry] == MetaKind_F32) - hex |= 1 << entry; + MetaTable *t = &ctx->entities.data[bp_id.value].table; + MetaStruct *s = ctx->struct_infos + t->struct_info_id; + for EachIndex(s->member_count, member) { + b32 type_reference = (s->member_flags[member] & MetaStructMemberFlag_ReferenceType) != 0; + if (!type_reference && s->type_ids[member] == MetaKind_F32) + hex |= 1 << member; + } } meta_begin_line(m, s8("0x")); meta_push_u64_hex_width(m, hex, 8); @@ -3524,105 +3894,124 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) } function b32 -metagen_matlab_union(MetaprogramContext *m, MetaContext *ctx, MetaMUnion *mu, s8 outdir) +metagen_matlab_union(MetaprogramContext *m, MetaContext *ctx, MetaStruct *u, s8 outdir, s8 namespace) { - b32 result = 1; - Arena scratch = m->scratch; - - i32 enumeration_id = -1; - for (da_count it = 0; it < ctx->entity_kind_counts[MetaEntityKind_Enumeration]; it++) { - da_count id = ctx->entity_kind_ids[MetaEntityKind_Enumeration][it]; - if (s8_equal(mu->enumeration_name, ctx->entity_names.data[id])) { - enumeration_id = id; - break; - } - } - - if (enumeration_id < 0) { - meta_compiler_error(mu->location, "Kind Enumeration '%.*s' requested by @MUnion not defined\n", - (i32)mu->enumeration_name.len, mu->enumeration_name.data); - } - - MetaTable *etable = &ctx->entities.data[enumeration_id].table; - if (etable->entry_count != mu->sub_table_count) { - meta_compiler_error(mu->location, "'%.*s' contains %u members but %u were requested by @MUnion\n", - (i32)mu->enumeration_name.len, mu->enumeration_name.data, - etable->entry_count, mu->sub_table_count); - } - - MetaTable **table_matches = push_array(&scratch, MetaTable *, mu->sub_table_count); - for (u32 index = 0; index < mu->sub_table_count; index++) { - s8 sub_table_name = mu->sub_table_names[index]; - da_count struct_id = -1; - for (da_count it = 0; it < ctx->entity_kind_counts[MetaEntityKind_Struct]; it++) { - da_count id = ctx->entity_kind_ids[MetaEntityKind_Struct][it]; - if (s8_equal(sub_table_name, ctx->entity_names.data[id])) { - struct_id = it; - break; - } - } - - if (struct_id < 0) { - meta_compiler_error(mu->location, "Struct '%.*s' requested by @MUnion not defined\n", - (i32)sub_table_name.len, sub_table_name.data); - } - - table_matches[index] = &ctx->entities.data[struct_id].table; - } - - u32 max_parameter_size = 0; - for (u32 member = 0; member < etable->entry_count; member++) { - u32 parameter_size = 0; - for (u32 prop = 0; prop < table_matches[member]->entry_count; prop++) - parameter_size += meta_kind_byte_sizes[table_matches[member]->struct_type_ids[prop]]; - max_parameter_size = Max(parameter_size, max_parameter_size); - } - - Arena scratch_temp = scratch; - s8 namespace = ctx->munion_namespaces.data[mu->namespace_id]; + b32 result = 1; - s8 outfile = push_s8_from_parts(&scratch, s8(OS_PATH_SEPARATOR), outdir, s8("Base.m")); - meta_begin_scope(m, s8("classdef Base")); + Arena scratch; + DeferLoop(scratch = m->scratch, m->scratch = scratch) { - meta_begin_scope(m, s8("methods")); + s8 outfile = push_s8_from_parts(&m->scratch, s8(OS_PATH_SEPARATOR), outdir, s8("Base.m")); + meta_begin_scope(m, s8("classdef Base")); { - meta_begin_scope(m, s8("function out = Pack(obj)")); + meta_begin_scope(m, s8("properties (Constant)")); { - meta_begin_line(m, s8("out = zeros(1, ")); - meta_push_u64(m, max_parameter_size); - meta_end_line(m, s8(", 'uint8');")); - meta_push_line(m, s8("fields = struct2cell(struct(obj));")); - meta_push_line(m, s8("offset = 1;")); - meta_begin_scope(m, s8("for i = 1:numel(fields)")); - { - meta_push_line(m, s8("bytes = typecast(fields{i}, 'uint8');")); - meta_push_line(m, s8("out(offset:(offset + numel(bytes) - 1)) = bytes;")); - meta_push_line(m, s8("offset = offset + numel(bytes);")); - } meta_end_scope(m, s8("end")); + meta_begin_line(m, s8("byteSize(1,1) uint32 = ")); + meta_push_u64(m, u->byte_size); + meta_end_line(m); } meta_end_scope(m, s8("end")); } meta_end_scope(m, s8("end")); - } meta_end_scope(m, s8("end")); - result &= meta_end_and_write_matlab(m, (c8 *)outfile.data); - scratch = scratch_temp; + result &= meta_end_and_write_matlab(m, (c8 *)outfile.data); + } - for (u32 member = 0; member < etable->entry_count; member++) { - MetaTable *t = table_matches[member]; + for EachIndex(u->member_count, union_member) { + if ((u->member_flags[union_member] & MetaStructMemberFlag_ReferenceType) == 0) { + str8 type_name = meta_kind_c_types[u->type_ids[union_member]]; + str8 name = u->members[union_member]; + build_log_failure("%.*s:%u:%u: error: base type in MATLAB union:\n" + "%.*s %.*s\n" + "MATLAB unions only support Struct and Union members\n", + (i32)ctx->filename.len, ctx->filename.data, u->location.line, u->location.column, + (i32)name.length, name.data, (i32)type_name.length, type_name.data); + result = 0; + break; + } - s8 sub_name = etable->entries[0][member]; - outfile = push_s8_from_parts(&scratch, s8(""), outdir, s8(OS_PATH_SEPARATOR), sub_name, s8(".m")); - meta_begin_scope(m, s8("classdef "), sub_name, s8(" < OGL" META_NAMESPACE_UPPER), namespace, s8(".Base")); + DeferLoop(scratch = m->scratch, m->scratch = scratch) { - meta_begin_scope(m, s8("properties")); + MetaStruct *s = ctx->struct_infos + ctx->entities.data[u->type_ids[union_member]].table.struct_info_id; + s8 sub_name = s8_from_str8(u->members[union_member]); + s8 outfile = push_s8_from_parts(&m->scratch, s8(""), outdir, s8(OS_PATH_SEPARATOR), sub_name, s8(".m")); + meta_begin_scope(m, s8("classdef "), sub_name, s8(" < " MATLAB_NAMESPACE META_NAMESPACE_UPPER), + namespace, s8(".Base")); { - for (u32 prop = 0; prop < t->entry_count; prop++) { - meta_begin_line(m, t->entries[MetaStructField_Name][prop], s8("(1,")); - meta_push_u64(m, meta_kind_elements[t->struct_type_ids[prop]]); - meta_end_line(m, s8(") "), meta_kind_matlab_types[t->struct_type_ids[prop]]); - } + meta_push_matlab_properties(m, ctx, s); + + meta_push(m, s8("\n")); + + meta_begin_scope(m, s8("methods")); + { + meta_begin_scope(m, s8("function bytes = toBytes(obj)")); + { + meta_begin_scope(m, s8("arguments (Output)")); + { + meta_push_line(m, s8("bytes uint8")); + } meta_end_scope(m, s8("end")); + meta_push_line(m, s8("bytes = zeros(1, obj.byteSize, 'uint8');")); + + s8 *columns[3]; + columns[0] = push_array(&m->scratch, s8, s->member_count); + columns[1] = push_array(&m->scratch, s8, s->member_count); + columns[2] = push_array(&m->scratch, s8, s->member_count); + + u32 offset = 1; + for EachIndex(s->member_count, member) { + Stream sb = arena_stream(m->scratch); + + i32 type_id = s->type_ids[member]; + + u32 member_size = 0; + if (s->member_flags[member] & MetaStructMemberFlag_ReferenceType) { + MetaStruct *ref = ctx->struct_infos + ctx->entities.data[type_id].table.struct_info_id; + member_size = ref->byte_size; + // TODO(rnp): arrays of structs + // - calculate member count with element count multiplied in for struct members + // - do a sub loop for struct arrays calling toBytes method on each struct array element + if (meta_struct_member_elements(ctx, s, member) != 1) { + str8 name = s->members[member]; + build_log_failure("%.*s:%u:%u: error: array of structs present in struct referenced by MATLAB union:\n" + "%.*s %.*s\n" + "MATLAB unions do not currently support array of structs\n", + (i32)ctx->filename.len, ctx->filename.data, u->location.line, u->location.column, + (i32)name.length, name.data, (i32)ref->name.length, ref->name.data); + } + } else { + member_size = meta_kind_byte_sizes[type_id]; + } + + stream_append_u64(&sb, offset); + stream_append_byte(&sb, ':'); + stream_append_u64(&sb, offset - 1 + member_size); + stream_append_byte(&sb, ')'); + offset += member_size; + + columns[0][member] = arena_stream_commit_and_reset(&m->scratch, &sb); + + stream_append_s8s(&sb, s8("= typecast(obj."), s8_from_str8(s->members[member])); + if (s->member_flags[member] & MetaStructMemberFlag_ReferenceType) { + // TODO(rnp): arrays of structs + // - calculate member count with element count multiplied in for struct members + // - do a sub loop for struct arrays calling toBytes method on each struct array element + // lookup subtype, if union replace with byte array, else reference sub type + MetaStruct *ref = ctx->struct_infos + ctx->entities.data[type_id].table.struct_info_id; + if ((ref->flags & MetaStructFlag_Union) == 0) { + stream_append_s8(&sb, s8(".toBytes()")); + } + } else { + stream_append_s8(&sb, s8("(:)")); + } + stream_append_byte(&sb, ','); + + columns[1][member] = arena_stream_commit_and_reset(&m->scratch, &sb); + columns[2][member] = s8("'uint8');"); + } + + metagen_push_table(m, m->scratch, str8("bytes("), str8(""), columns, s->member_count, 3); + } meta_end_scope(m, s8("end")); + } meta_end_scope(m, s8("end")); } meta_end_scope(m, s8("end")); - } meta_end_scope(m, s8("end")); - result &= meta_end_and_write_matlab(m, (c8 *)outfile.data); - scratch = scratch_temp; + result &= meta_end_and_write_matlab(m, (c8 *)outfile.data); + } } return result; @@ -3677,22 +4066,14 @@ metagen_emit_matlab_code(MetaContext *ctx, Arena arena) } } if (group_id != -1) { - da_count children = meta_entity_children_count(ctx, (MetaEntityID){.value = group_id}); + da_count children; + da_count *ids = meta_entity_extract_children(ctx, (MetaEntityID){.value = group_id}, + &children, &m->scratch); if (children > 0) { - da_count *ids = push_array(&m->scratch, da_count, children); - - // NOTE(rnp): children are pushed in LIFO order - da_count index = 0; - MetaEntityID child = ctx->entities.data[group_id].first_child; - do { - child = ctx->entities.data[child.value].previous_sibling; - ids[index++] = child.value; - } while (child.value != ctx->entities.data[group_id].first_child.value); - metagen_push_counted_enum_body_from_ids(m, s8(""), s8(""), s8("("), s8(")"), ids, ctx->entity_names.data, children); - m->scratch = ctx->scratch; } + m->scratch = ctx->scratch; } else { build_log_failure("failed to find Compute shader group in meta info\n"); } @@ -3727,48 +4108,66 @@ 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, (s8 *)meta_kind_matlab_types); result &= meta_write_and_reset(m, (c8 *)output.data); m->scratch = scratch; } } - ////////////////// - // NOTE: MUnions - for (iz munion = 0; munion < ctx->munions.count; munion++) { - Arena scratch = m->scratch; - MetaMUnion *mu = ctx->munions.data + munion; - s8 namespace = ctx->munion_namespaces.data[mu->namespace_id]; - s8 outdir = push_s8_from_parts(&m->scratch, s8(""), s8(OUTPUT("matlab")), - s8(OS_PATH_SEPARATOR "+OGLBeamformer"), namespace); - os_make_directory((c8 *)outdir.data); - result &= metagen_matlab_union(m, ctx, mu, outdir); - m->scratch = scratch; - } + ///////////////////////// + // NOTE(rnp): entities marked @MATLAB + { + da_count children; + da_count *ids = meta_entity_extract_children(ctx, ctx->matlab_entity, &children, &m->scratch); - return result; -} + for EachIndex((u64)children, it) { + MetaEntity *rr = ctx->entities.data + ids[it]; + da_count ref_id = ctx->entities.data[rr->reference.resolved_id.value].reference.resolved_id.value; + MetaEntity *re = ctx->entities.data + ref_id; -function b32 -metagen_emit_helper_library_header(MetaContext *ctx, Arena arena) -{ - b32 result = 1; - char *out = OUTPUT("ogl_beamformer_lib.h"); - if (!needs_rebuild(out, "lib/ogl_beamformer_lib_base.h", "beamformer.meta")) - return result; + switch (re->kind) { + InvalidDefaultCase; + case MetaEntityKind_Union:{ + Arena scratch; + DeferLoop(scratch = m->scratch, m->scratch = scratch) { + MetaStruct *s = ctx->struct_infos + re->table.struct_info_id; + s8 name = (rr->reference.scope_name.len > 0) ? rr->reference.scope_name : s8_from_str8(s->name); + s8 outdir = push_s8_from_parts(&m->scratch, s8(""), s8(OUTPUT("matlab") OS_PATH_SEPARATOR), + s8("+" MATLAB_NAMESPACE META_NAMESPACE_UPPER), name); + os_make_directory((c8 *)outdir.data); + result &= metagen_matlab_union(m, ctx, s, outdir, name); + } + }break; - build_log_generate("Library Header"); + case MetaEntityKind_Struct:{ + MetaStruct *s = ctx->struct_infos + re->table.struct_info_id; + s8 name = (rr->reference.scope_name.len > 0) ? rr->reference.scope_name : s8_from_str8(s->name); + s8 outfile = push_s8_from_parts(&m->scratch, s8(""), s8(OUTPUT("matlab") OS_PATH_SEPARATOR), + s8(MATLAB_NAMESPACE META_NAMESPACE_UPPER), name, + s8(".m")); + meta_begin_scope(m, s8("classdef " MATLAB_NAMESPACE META_NAMESPACE_UPPER), name); + { + meta_push_matlab_properties(m, ctx, s); + } meta_end_scope(m, s8("end")); + result &= meta_end_and_write_matlab(m, (c8 *)outfile.data); + }break; - s8 parameters_header = read_entire_file("beamformer_parameters.h", &arena); - s8 base_header = read_entire_file("lib/ogl_beamformer_lib_base.h", &arena); + } + } + m->scratch = ctx->scratch; + } - MetaprogramContext m[1] = {{.stream = arena_stream(arena), .scratch = ctx->scratch}}; + return result; +} +function void +meta_push_helper_library_header_base(MetaprogramContext *m, MetaContext *ctx) +{ meta_push(m, c_file_header); meta_push_line(m, s8("#include <stdint.h>\n")); ///////////////////////// - // NOTE(rnp): enumerents + // NOTE(rnp): Constants { u32 integers = 0; for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { @@ -3795,11 +4194,12 @@ metagen_emit_helper_library_header(MetaContext *ctx, Arena arena) row_count++; } } - metagen_push_table(m, m->scratch, s8("#define " META_NAMESPACE_UPPER), s8(")"), columns, row_count, 2); + metagen_push_table(m, m->scratch, str8("#define " META_NAMESPACE_UPPER), str8(")"), columns, row_count, 2); + meta_push(m, s8("\n")); } ///////////////////////// - // NOTE(rnp): enumerents + // NOTE(rnp): enumerants for (da_count kind = 0; kind < ctx->entity_kind_counts[MetaEntityKind_Enumeration]; kind++) { da_count id = ctx->entity_kind_ids[MetaEntityKind_Enumeration][kind]; MetaEntity *e = ctx->entities.data + id; @@ -3822,26 +4222,17 @@ metagen_emit_helper_library_header(MetaContext *ctx, Arena arena) } if (group_id != -1) { - da_count children = meta_entity_children_count(ctx, (MetaEntityID){.value = group_id}); + da_count children; + da_count *ids = meta_entity_extract_children(ctx, (MetaEntityID){.value = group_id}, + &children, &m->scratch); if (children > 0) { s8 kind = s8(META_NAMESPACE_UPPER "ShaderKind"); s8 kind_full = s8(META_NAMESPACE_UPPER "ShaderKind_"); - - da_count *ids = push_array(&m->scratch, da_count, children); - - // NOTE(rnp): children are pushed in LIFO order - da_count index = 0; - MetaEntityID child = ctx->entities.data[group_id].first_child; - do { - child = ctx->entities.data[child.value].previous_sibling; - ids[index++] = child.value; - } while (child.value != ctx->entities.data[group_id].first_child.value); - meta_begin_scope(m, s8("typedef enum {")); { metagen_push_counted_enum_body_from_ids(m, kind_full, s8(""), s8("= "), s8(","), ids, ctx->entity_names.data, children); - meta_push_line(m, kind_full, s8("Count,\n")); + meta_push_line(m, kind_full, s8("Count,")); } meta_end_scope(m, s8("} "), kind, s8(";\n")); m->scratch = ctx->scratch; @@ -3850,18 +4241,127 @@ metagen_emit_helper_library_header(MetaContext *ctx, Arena arena) meta_push_i64(m, children); meta_end_line(m, s8(")\n")); } + m->scratch = ctx->scratch; } else { build_log_failure("failed to find Compute shader group in meta info\n"); } } +} - metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_CLibrary, meta_kind_base_c_types); +function void +meta_entity_resolve_references(MetaContext *ctx, da_count *ids, u64 id_count) +{ + for EachIndex(id_count, it) { + MetaEntity *e = meta_entity(ctx, (MetaEntityID){ids[it]}); + switch (e->kind) { + InvalidDefaultCase; + case MetaEntityKind_ReferenceReference:{ + MetaEntity *r = meta_entity(ctx, e->reference.resolved_id); + ids[it] = r->reference.resolved_id.value; + }break; + } + } +} + +function b32 +metagen_emit_helper_library_header(MetaContext *ctx, Arena arena) +{ + b32 result = 1; + char *out = OUTPUT("ogl_beamformer_lib.h"); + if (!needs_rebuild(out, "lib/ogl_beamformer_lib_base.h", "beamformer.meta")) + return result; + + build_log_generate("Library Header"); + + s8 parameters_header = read_entire_file("beamformer_parameters.h", &arena); + s8 base_header = read_entire_file("lib/ogl_beamformer_lib_base.h", &arena); + + MetaprogramContext m[1] = {{.stream = arena_stream(arena), .scratch = ctx->scratch}}; + + meta_push_helper_library_header_base(m, ctx); + ///////////////////////// + // NOTE(rnp): entities marked @Library + { + da_count children; + da_count *ids = meta_entity_extract_children(ctx, ctx->library_entity, &children, &m->scratch); + + meta_entity_resolve_references(ctx, ids, children); + + for EachIndex((u64)children, it) { + MetaEntity *e = ctx->entities.data + ids[it]; + switch (e->kind) { + InvalidDefaultCase; + + case MetaEntityKind_Struct:{ + meta_begin_scope(m, s8("typedef struct {")); { + meta_push_struct_body(ctx, m, e, (MetaPushStructParameters){ + .layout_style = MetaPushStructStyle_C, + .union_style = MetaPushStructStyle_C, + .element_count_style = MetaPushStructStyle_C, + .base_types = meta_kind_base_c_types, + .suffix = str8(";"), + .str_element_prefix = str8(META_NAMESPACE_UPPER), + }); + } meta_end_scope(m, s8("} " META_NAMESPACE_UPPER), ctx->entity_names.data[ids[it]], s8(";\n")); + }break; + + case MetaEntityKind_Union:{ + }break; + + } + } + m->scratch = ctx->scratch; + } + + metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_CLibrary, (s8 *)meta_kind_base_c_types); meta_push_line(m, s8("// END GENERATED CODE\n")); meta_push(m, parameters_header, base_header); result &= meta_write_and_reset(m, out); + // NOTE(rnp): matlab compatible header + { + meta_push_helper_library_header_base(m, ctx); + ///////////////////////// + // NOTE(rnp): entities marked @Library + { + da_count children; + da_count *ids = meta_entity_extract_children(ctx, ctx->library_entity, &children, &m->scratch); + + meta_entity_resolve_references(ctx, ids, children); + + for EachIndex((u64)children, it) { + MetaEntity *e = ctx->entities.data + ids[it]; + switch (e->kind) { + InvalidDefaultCase; + case MetaEntityKind_Struct:{ + meta_begin_scope(m, s8("typedef struct {")); + { + meta_push_struct_body(ctx, m, e, (MetaPushStructParameters){ + .layout_style = MetaPushStructStyle_C, + .union_style = MetaPushStructStyle_MATLAB, + .element_count_style = MetaPushStructStyle_C, + .base_types = meta_kind_base_c_types, + .suffix = str8(";"), + .str_element_prefix = str8(META_NAMESPACE_UPPER), + }); + } meta_end_scope(m, s8("} " META_NAMESPACE_UPPER), ctx->entity_names.data[ids[it]], s8(";\n")); + }break; + case MetaEntityKind_Union:{}break; + } + } + m->scratch = ctx->scratch; + } + + metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_CLibrary, (s8 *)meta_kind_base_c_types); + + meta_push_line(m, s8("// END GENERATED CODE\n")); + + meta_push(m, parameters_header, base_header); + result &= meta_write_and_reset(m, OUTPUT("ogl_beamformer_lib_matlab.h")); + } + { CommandList cpp = {0}; cmd_append(&arena, &cpp, PREPROCESSOR, out, COMPILER_OUTPUT, OUTPUT("ogl_beamformer_lib_python_ffi.h")); @@ -3917,8 +4417,25 @@ metagen_load_context(Arena *arena, char *filename) i += meta_expand(ctx, scratch, e, entries.count - i, 0); }break; - case MetaEntryKind_MUnion:{ - meta_pack_munion(ctx, e, entries.count - i); + case MetaEntryKind_Library: + case MetaEntryKind_MATLAB: + { + if (e->kind == MetaEntryKind_Library && ctx->library_entity.value == 0) { + ctx->library_entity = meta_intern_entity(ctx, s8("LibraryEntity"), MetaEntityKind_List, + meta_root_entity_id(ctx), (MetaLocation){0}, 0); + } + + if (e->kind == MetaEntryKind_MATLAB && ctx->matlab_entity.value == 0) { + ctx->matlab_entity = meta_intern_entity(ctx, s8("MATLABEntity"), MetaEntityKind_List, + meta_root_entity_id(ctx), (MetaLocation){0}, 0); + } + + MetaEntityID parent = e->kind == MetaEntryKind_Library ? ctx->library_entity : ctx->matlab_entity; + s8 prefix = e->kind == MetaEntryKind_Library ? s8("Library") : s8("MATLAB"); + s8 scope_name = s8(""); + if (e->argument_count > 0) + scope_name = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; + i += meta_pack_references(ctx, e, entries.count - i, parent, scope_name, prefix); }break; case MetaEntryKind_ShaderGroup:{ @@ -3928,6 +4445,7 @@ metagen_load_context(Arena *arena, char *filename) case MetaEntryKind_Enumeration: case MetaEntryKind_Struct: case MetaEntryKind_Table: + case MetaEntryKind_Union: { i += meta_pack_table_entity(ctx, e, entries.count - i, e->name, meta_root_entity_id(ctx)); }break; @@ -3996,25 +4514,165 @@ metagen_load_context(Arena *arena, char *filename) // NOTE(rnp): finalize struct info { - MetaEntityKind struct_kinds[] = {MetaEntityKind_Struct, MetaEntityKind_PushConstants, MetaEntityKind_BakeParameters}; - u32 type_fields[] = {MetaStructField_Type, MetaStructField_Type, MetaBakeField_Type}; - static_assert(countof(struct_kinds) == countof(type_fields), ""); - for EachElement(struct_kinds, kind_it) { - for (da_count it = 0; it < ctx->entity_kind_counts[struct_kinds[kind_it]]; it++) { - da_count entity = ctx->entity_kind_ids[struct_kinds[kind_it]][it]; + da_count struct_infos_count = 0; + for EachElement(meta_struct_entity_kinds, kind_it) + struct_infos_count += ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; + + ctx->struct_infos_count = struct_infos_count; + ctx->struct_infos = push_array(ctx->arena, MetaStruct, struct_infos_count); + + da_count struct_info_index = 0; + for EachElement(meta_struct_entity_kinds, kind_it) { + for (da_count it = 0; it < ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; it++) { + da_count entity = ctx->entity_kind_ids[meta_struct_entity_kinds[kind_it]][it]; MetaEntity *e = ctx->entities.data + entity; - MetaTable *s = &e->table; - s8 *types = s->entries[type_fields[kind_it]]; - for (u32 member = 0; member < s->entry_count; member++) { - s->struct_type_ids[member] = meta_lookup_string_slow(meta_kind_meta_types, MetaKind_Count, types[member]); - if (s->struct_type_ids[member] == -1) { - s8 name = ctx->entity_names.data[entity]; + e->table.struct_info_id = struct_info_index++; + + MetaStruct *s = ctx->struct_infos + e->table.struct_info_id; + s->name = str8_from_s8(ctx->entity_names.data[entity]); + s->members = (str8 *)e->table.entries[meta_struct_name_field[kind_it]]; + s->member_count = e->table.entry_count; + s->location = e->location; + s->byte_size = (u32)-1; + s->entity = (MetaEntityID){entity}; + if (meta_struct_entity_kinds[kind_it] == MetaEntityKind_Union) + s->flags = MetaStructFlag_Union; + + s->member_flags = push_array(ctx->arena, MetaStructMemberFlags, s->member_count); + s->elements = push_array_no_zero(ctx->arena, i32, s->member_count); + s->type_ids = push_array_no_zero(ctx->arena, i32, s->member_count); + memory_clear(s->type_ids, -1, sizeof(*s->type_ids) * s->member_count); + memory_clear(s->elements, -1, sizeof(*s->elements) * s->member_count); + } + } + + // NOTE(rnp): resolve types + for EachElement(meta_struct_entity_kinds, kind_it) { + for (da_count it = 0; it < ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; it++) { + da_count entity = ctx->entity_kind_ids[meta_struct_entity_kinds[kind_it]][it]; + MetaEntity *e = ctx->entities.data + entity; + MetaStruct *s = ctx->struct_infos + e->table.struct_info_id; + + s8 *types = e->table.entries[meta_struct_type_field[kind_it]]; + for EachIndex(s->member_count, member) { + s->type_ids[member] = meta_lookup_string_slow((s8 *)meta_kind_meta_types, MetaKind_Count, types[member]); + + if (s->type_ids[member] == -1 && meta_struct_allow_references[kind_it]) { + s->member_flags[member] = MetaStructMemberFlag_ReferenceType; + i64 id = meta_lookup_string_slow(ctx->entity_names.data, ctx->entity_names.count, types[member]); + if (id >= 0) { + MetaEntityKind kind = ctx->entities.data[id].kind; + if (!meta_entity_kind_struct_reference_target[kind]) { + meta_compiler_error(e->location, "struct '%.*s' references entity '%.*s' which is not a valid struct member\n", + (i32)s->name.length, s->name.data, (i32)types[member].len, types[member].data); + } + if (ctx->entities.data[id].kind == MetaEntityKind_Union) + s->flags |= MetaStructFlag_ContainsUnion; + s->type_ids[member] = id; + } + } + + if (s->type_ids[member] == -1) { meta_compiler_error(e->location, "struct '%.*s' references undefined type '%.*s'\n", - (i32)name.len, name.data, (i32)types[member].len, types[member].data); + (i32)s->name.length, s->name.data, (i32)types[member].len, types[member].data); } } } } + + // NOTE(rnp): resolve element counts + for EachElement(meta_struct_entity_kinds, kind_it) { + for (da_count it = 0; it < ctx->entity_kind_counts[meta_struct_entity_kinds[kind_it]]; it++) { + da_count entity = ctx->entity_kind_ids[meta_struct_entity_kinds[kind_it]][it]; + MetaEntity *e = ctx->entities.data + entity; + MetaStruct *s = ctx->struct_infos + e->table.struct_info_id; + + i32 field = meta_struct_element_field[kind_it]; + s8 *elements = field >= 0 ? e->table.entries[field] : 0; + for EachIndex(s->member_count, member) { + if (elements) { + NumberConversion integer = integer_from_s8(elements[member]); + if (integer.result == NumberConversionResult_Success) { + s->elements[member] = integer.U64; + } else { + s->member_flags[member] |= MetaStructMemberFlag_ReferenceElements; + i64 id = meta_lookup_string_slow(ctx->entity_names.data, ctx->entity_names.count, elements[member]); + if (id >= 0) { + MetaEntity *ee = ctx->entities.data + id; + if (ee->kind != MetaEntityKind_Constant || ee->constant.kind != MetaConstantKind_Integer) { + // TODO(rnp): point at correct member + meta_compiler_error(e->location, "struct '%.*s': element count for field '%.*s'" + "references '%.*s' which is not an integer constant\n", + (i32)s->name.length, s->name.data, + (i32)s->members[member].length, s->members[member].data, + (i32)elements[member].len, elements[member].data); + } + s->elements[member] = id; + } + } + } else { + s->elements[member] = 1; + } + + if (s->elements[member] == -1) { + meta_compiler_error(e->location, "struct '%.*s': element count for field '%.*s' could not be determined\n", + (i32)s->name.length, s->name.data, + (i32)s->members[member].length, s->members[member].data); + } + } + } + } + + // NOTE(rnp): resolve size + // TODO(rnp): depth could be predetermined + b32 all_done = 0; + for (u32 iterations = 0; !all_done && iterations < 16; iterations++) { + for EachIndex(ctx->struct_infos_count, structure) { + MetaStruct *s = ctx->struct_infos + structure; + u32 size = 0; + b32 is_union = (s->flags & MetaStructFlag_Union) != 0; + for EachIndex(s->member_count, member) { + b32 type_reference = (s->member_flags[member] & MetaStructMemberFlag_ReferenceType) != 0; + u32 elements = meta_struct_member_elements(ctx, s, member); + + u32 member_size = 0; + if (type_reference) { + MetaEntity *ref = ctx->entities.data + s->type_ids[member]; + if (ref->kind == MetaEntityKind_Enumeration) { + if (ref->table.entry_count < U32_MAX) member_size = sizeof(u32); + else member_size = sizeof(u64); + } else { + MetaStruct *sub_struct = ctx->struct_infos + ref->table.struct_info_id; + if (sub_struct->byte_size != (u32)-1) { + member_size = sub_struct->byte_size * elements; + } else { + size = (u32)-1; + break; + } + } + } else { + member_size = meta_kind_byte_sizes[s->type_ids[member]] * elements; + } + size = is_union ? Max(size, member_size) : size + member_size; + } + if (size != (u32)-1) + s->byte_size = size; + } + + all_done = 1; + for EachIndex(ctx->struct_infos_count, structure) + all_done &= ctx->struct_infos[structure].byte_size != (u32)-1; + } + + if (!all_done) { + for EachIndex(ctx->struct_infos_count, structure) { + MetaStruct *s = ctx->struct_infos + structure; + if (s->byte_size == (u32)-1) { + meta_compiler_error(s->location, "storage size for struct '%.*s' could not be determined\n", + (i32)s->name.length, s->name.data); + } + } + } } // NOTE(rnp): finalize base shader nonsense @@ -4094,7 +4752,7 @@ metagen_file_direct(Arena arena, char *filename) if (needs_rebuild_(out, deps.data, deps.count)) { build_log_generate(out); meta_push(m, c_file_header); - metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_C, meta_kind_c_types); + metagen_run_emit_set(m, ctx, ctx->emit_sets + MetaEmitLang_C, (s8 *)meta_kind_c_types); result &= meta_write_and_reset(m, out); } diff --git a/generated/beamformer.meta.c b/generated/beamformer.meta.c @@ -6,7 +6,7 @@ #define BeamformerFilterSlots (4) #define BeamformerMaxBacklogFrames (16) #define BeamformerMaxChannelCount (256) -#define BeamformerMaxEmmissionsCount (256) +#define BeamformerMaxEmissionsCount (256) #define BeamformerMaxComputeShaderStages (16) #define BeamformerMaxParameterBlocks (16) #define BeamformerMaxRawDataFramesInFlight (3) @@ -104,76 +104,6 @@ typedef enum { } BeamformerShaderKind; typedef struct { - f32 cycles; - f32 frequency; -} BeamformerSineParameters; - -typedef struct { - f32 duration; - f32 min_frequency; - f32 max_frequency; -} BeamformerChirpParameters; - -typedef struct { - f32 cutoff_frequency; - f32 beta; - u32 length; -} BeamformerKaiserFilterParameters; - -typedef struct { - f32 duration; - f32 min_frequency; - f32 max_frequency; -} BeamformerChirpFilterParameters; - -typedef struct { - m4 das_voxel_transform; - m4 xdc_transform; - v2 xdc_element_pitch; - uv2 raw_data_dimensions; - v2 focal_vector; - u32 transmit_receive_orientation; - u32 sample_count; - u32 channel_count; - u32 acquisition_count; - u32 acquisition_kind; - f32 time_offset; - u8 single_focus; - u8 single_orientation; - u8 decode_mode; - u8 sampling_mode; -} BeamformerParametersHead; - -typedef struct { - iv4 output_points; - f32 sampling_frequency; - f32 demodulation_frequency; - f32 speed_of_sound; - f32 f_number; - u32 interpolation_mode; - u32 coherency_weighting; - u32 decimation_rate; -} BeamformerParametersUI; - -typedef struct { - i16 channel_mapping[256]; - i16 sparse_elements[256]; - u8 transmit_receive_orientations[256]; - f32 steering_angles[256]; - f32 focal_depths[256]; - i32 compute_stages[16]; - i32 compute_stage_parameters[16]; - u32 compute_stages_count; - i32 data_kind; -} BeamformerParametersSimple; - -typedef struct { - m4 xdc_transform; - m4 voxel_transform; - v2 xdc_element_pitch; -} BeamformerDASPushConstants; - -typedef struct { u32 data_kind; u32 dilate_output; u32 use_shared_memory; @@ -228,125 +158,157 @@ typedef struct { f32 transmit_angle; } BeamformerDASBakeParameters; -typedef union { - BeamformerDecodeBakeParameters Decode; - BeamformerFilterBakeParameters Filter; - BeamformerDASBakeParameters DAS; -} BeamformerShaderBakeParameters; +typedef struct { + m4 xdc_transform; + m4 voxel_transform; + v2 xdc_element_pitch; +} BeamformerDASPushConstants; -typedef union { - struct { - f32 cycles; - f32 frequency; - } sine; - struct { - f32 duration; - f32 min_frequency; - f32 max_frequency; - } chirp; +typedef struct { + f32 cycles; + f32 frequency; +} BeamformerSineParameters; + +typedef struct { + f32 duration; + f32 min_frequency; + f32 max_frequency; +} BeamformerChirpParameters; + +typedef struct { + BeamformerEmissionKind kind; + union { + BeamformerSineParameters sine; + BeamformerChirpParameters chirp; + }; } BeamformerEmissionParameters; typedef struct { - m4 das_voxel_transform; - m4 xdc_transform; - v2 xdc_element_pitch; - uv2 raw_data_dimensions; - v2 focal_vector; - u32 transmit_receive_orientation; - u32 sample_count; - u32 channel_count; - u32 acquisition_count; - u32 acquisition_kind; - f32 time_offset; - u8 single_focus; - u8 single_orientation; - u8 decode_mode; - u8 sampling_mode; - iv4 output_points; - f32 sampling_frequency; - f32 demodulation_frequency; - f32 speed_of_sound; - f32 f_number; - u32 interpolation_mode; - u32 coherency_weighting; - u32 decimation_rate; - BeamformerContrastMode contrast_mode; - BeamformerEmissionKind emission_kind; - BeamformerEmissionParameters emission_parameters; -} BeamformerParameters; + f32 cutoff_frequency; + f32 beta; + u32 length; +} BeamformerKaiserFilterParameters; typedef struct { - iv4 output_points; - f32 sampling_frequency; - f32 demodulation_frequency; - f32 speed_of_sound; - f32 f_number; - u32 interpolation_mode; - u32 coherency_weighting; - u32 decimation_rate; + f32 duration; + f32 min_frequency; + f32 max_frequency; +} BeamformerMatchedChirpFilterParameters; + +typedef struct { + BeamformerFilterKind kind; + f32 sampling_frequency; + b32 complex; + union { + BeamformerKaiserFilterParameters kaiser; + BeamformerMatchedChirpFilterParameters matched_chirp; + }; +} BeamformerFilterParameters; + +typedef struct { + m4 das_voxel_transform; + m4 xdc_transform; + v2 xdc_element_pitch; + uv2 raw_data_dimensions; + v2 focal_vector; + u32 transmit_receive_orientation; + u32 sample_count; + u32 channel_count; + u32 acquisition_count; + BeamformerAcquisitionKind acquisition_kind; + BeamformerDecodeMode decode_mode; + BeamformerSamplingMode sampling_mode; + f32 time_offset; + b32 single_focus; + b32 single_orientation; +} BeamformerParametersHead; + +typedef struct { + iv4 output_points; + f32 sampling_frequency; + f32 demodulation_frequency; + f32 speed_of_sound; + f32 f_number; + BeamformerInterpolationMode interpolation_mode; + b32 coherency_weighting; + u32 decimation_rate; } BeamformerUIParameters; typedef struct { BeamformerContrastMode contrast_mode; - BeamformerEmissionKind emission_kind; BeamformerEmissionParameters emission_parameters; -} BeamformerParametersExtra; +} BeamformerExtraParameters; typedef struct { - m4 das_voxel_transform; - m4 xdc_transform; - v2 xdc_element_pitch; - uv2 raw_data_dimensions; - v2 focal_vector; - u32 transmit_receive_orientation; - u32 sample_count; - u32 channel_count; - u32 acquisition_count; - u32 acquisition_kind; - f32 time_offset; - u8 single_focus; - u8 single_orientation; - u8 decode_mode; - u8 sampling_mode; - iv4 output_points; - f32 sampling_frequency; - f32 demodulation_frequency; - f32 speed_of_sound; - f32 f_number; - u32 interpolation_mode; - u32 coherency_weighting; - u32 decimation_rate; + m4 das_voxel_transform; + m4 xdc_transform; + v2 xdc_element_pitch; + uv2 raw_data_dimensions; + v2 focal_vector; + u32 transmit_receive_orientation; + u32 sample_count; + u32 channel_count; + u32 acquisition_count; + BeamformerAcquisitionKind acquisition_kind; + BeamformerDecodeMode decode_mode; + BeamformerSamplingMode sampling_mode; + f32 time_offset; + b32 single_focus; + b32 single_orientation; + iv4 output_points; + f32 sampling_frequency; + f32 demodulation_frequency; + f32 speed_of_sound; + f32 f_number; + BeamformerInterpolationMode interpolation_mode; + b32 coherency_weighting; + u32 decimation_rate; BeamformerContrastMode contrast_mode; - BeamformerEmissionKind emission_kind; BeamformerEmissionParameters emission_parameters; - i16 channel_mapping[256]; - i16 sparse_elements[256]; - u8 transmit_receive_orientations[256]; - f32 steering_angles[256]; - f32 focal_depths[256]; - i32 compute_stages[16]; - i32 compute_stage_parameters[16]; - u32 compute_stages_count; - i32 data_kind; -} BeamformerSimpleParameters; +} BeamformerParameters; typedef struct { - BeamformerFilterKind kind; - union { - struct { - f32 cutoff_frequency; - f32 beta; - u32 length; - } kaiser; - struct { - f32 duration; - f32 min_frequency; - f32 max_frequency; - } matched_chirp; - }; - f32 sampling_frequency; - b16 complex; -} BeamformerFilterParameters; + m4 das_voxel_transform; + m4 xdc_transform; + v2 xdc_element_pitch; + uv2 raw_data_dimensions; + v2 focal_vector; + u32 transmit_receive_orientation; + u32 sample_count; + u32 channel_count; + u32 acquisition_count; + BeamformerAcquisitionKind acquisition_kind; + BeamformerDecodeMode decode_mode; + BeamformerSamplingMode sampling_mode; + f32 time_offset; + b32 single_focus; + b32 single_orientation; + iv4 output_points; + f32 sampling_frequency; + f32 demodulation_frequency; + f32 speed_of_sound; + f32 f_number; + BeamformerInterpolationMode interpolation_mode; + b32 coherency_weighting; + u32 decimation_rate; + BeamformerContrastMode contrast_mode; + BeamformerEmissionParameters emission_parameters; + i16 channel_mapping[BeamformerMaxChannelCount]; + i16 sparse_elements[BeamformerMaxEmissionsCount]; + u8 transmit_receive_orientations[BeamformerMaxEmissionsCount]; + f32 steering_angles[BeamformerMaxEmissionsCount]; + f32 focal_depths[BeamformerMaxEmissionsCount]; + i32 compute_stages[BeamformerMaxComputeShaderStages]; + i32 compute_stage_parameters[BeamformerMaxComputeShaderStages]; + u32 compute_stages_count; + BeamformerDataKind data_kind; +} BeamformerSimpleParameters; + +typedef union { + BeamformerDecodeBakeParameters Decode; + BeamformerFilterBakeParameters Filter; + BeamformerDASBakeParameters DAS; +} BeamformerShaderBakeParameters; read_only global u8 beamformer_data_kind_element_size[] = { 2, diff --git a/lib/ogl_beamformer_lib.c b/lib/ogl_beamformer_lib.c @@ -354,39 +354,23 @@ beamformer_push_pipeline(i32 *shaders, u32 shader_count, BeamformerDataKind data return result; } -function b32 -beamformer_create_filter_base(BeamformerFilterParameters params, u8 filter_slot, u8 parameter_block) -{ - b32 result = 0; - if (check_shared_memory()) { - BeamformWork *work = try_push_work_queue(); - if (work) { - BeamformerCreateFilterContext *ctx = &work->create_filter_context; - work->kind = BeamformerWorkKind_CreateFilter; - ctx->parameters = params; - ctx->filter_slot = filter_slot % BeamformerFilterSlots; - ctx->parameter_block = parameter_block % BeamformerMaxParameterBlocks; - beamform_work_queue_push_commit(&g_beamformer_library_context.bp->external_work_queue); - result = 1; - } - } - return result; -} - b32 -beamformer_create_filter(BeamformerFilterKind kind, void *filter_parameters, u32 filter_size, - f32 sampling_frequency, b32 complex, u8 filter_slot, u8 parameter_block) +beamformer_create_filter(BeamformerFilterParameters *filter, u8 filter_slot, u8 parameter_block) { b32 result = 0; - if (lib_error_check(kind >= 0 && kind < BeamformerFilterKind_Count, InvalidFilterKind)) { - BeamformerFilterParameters fp = {0}; - /* NOTE(rnp): any parameter struct works as base offset */ - filter_size = MIN(filter_size, sizeof(fp) - offsetof(BeamformerFilterParameters, kaiser)); - mem_copy(&fp.kaiser, filter_parameters, filter_size); - fp.kind = kind; - fp.complex = complex != 0; - fp.sampling_frequency = sampling_frequency; - result = beamformer_create_filter_base(fp, filter_slot, parameter_block); + if (lib_error_check(filter->kind >= 0 && filter->kind < BeamformerFilterKind_Count, InvalidFilterKind)) { + if (check_shared_memory()) { + BeamformWork *work = try_push_work_queue(); + if (work) { + BeamformerCreateFilterContext *ctx = &work->create_filter_context; + work->kind = BeamformerWorkKind_CreateFilter; + ctx->parameters = *filter; + ctx->filter_slot = filter_slot % BeamformerFilterSlots; + ctx->parameter_block = parameter_block % BeamformerMaxParameterBlocks; + beamform_work_queue_push_commit(&g_beamformer_library_context.bp->external_work_queue); + result = 1; + } + } } return result; } diff --git a/lib/ogl_beamformer_lib_base.h b/lib/ogl_beamformer_lib_base.h @@ -137,9 +137,7 @@ BEAMFORMER_LIB_EXPORT uint32_t beamformer_push_transmit_receive_orientations_at( * M = (A - 8) / (2.285 (ω_s - ω_p)) */ -BEAMFORMER_LIB_EXPORT uint32_t beamformer_create_filter(BeamformerFilterKind kind, - void *filter_parameters, uint32_t filter_size, - float sampling_frequency, uint32_t complex, +BEAMFORMER_LIB_EXPORT uint32_t beamformer_create_filter(BeamformerFilterParameters *filter, uint8_t filter_slot, uint8_t parameter_block); ////////////////////////// diff --git a/tests/throughput.c b/tests/throughput.c @@ -175,7 +175,7 @@ beamformer_simple_parameters_from_zbp_file(BeamformerSimpleParameters *bp, char // NOTE(rnp): ignores emission count and ensemble count mem_copy(bp->raw_data_dimensions.E, header->raw_data_dimension, sizeof(bp->raw_data_dimensions)); - bp->data_kind = ZBP_DataKind_Int16; + bp->data_kind = (BeamformerDataKind)ZBP_DataKind_Int16; raw_data->kind = ZBP_DataKind_Int16; raw_data->compression_kind = ZBP_DataCompressionKind_ZSTD; @@ -217,7 +217,7 @@ beamformer_simple_parameters_from_zbp_file(BeamformerSimpleParameters *bp, char bp->transmit_receive_orientations[it] = bp->transmit_receive_orientation; } - bp->emission_kind = BeamformerEmissionKind_Sine; + bp->emission_parameters.kind = BeamformerEmissionKind_Sine; bp->emission_parameters.sine.cycles = 2; bp->emission_parameters.sine.frequency = bp->demodulation_frequency; }break; @@ -280,14 +280,14 @@ beamformer_simple_parameters_from_zbp_file(BeamformerSimpleParameters *bp, char case ZBP_EmissionKind_Sine:{ ZBP_EmissionSineParameters *ep = (ZBP_EmissionSineParameters *)(raw.data + ed->parameters_offset); - bp->emission_kind = BeamformerEmissionKind_Sine; + bp->emission_parameters.kind = BeamformerEmissionKind_Sine; bp->emission_parameters.sine.cycles = ep->cycles; bp->emission_parameters.sine.frequency = ep->frequency; }break; case ZBP_EmissionKind_Chirp:{ ZBP_EmissionChirpParameters *ep = (ZBP_EmissionChirpParameters *)(raw.data + ed->parameters_offset); - bp->emission_kind = BeamformerEmissionKind_Chirp; + bp->emission_parameters.kind = BeamformerEmissionKind_Chirp; bp->emission_parameters.chirp.duration = ep->duration; bp->emission_parameters.chirp.min_frequency = ep->min_frequency; bp->emission_parameters.chirp.max_frequency = ep->max_frequency; @@ -464,30 +464,24 @@ execute_study(Arena arena, Stream path, Options *options) bp.compute_stages[bp.compute_stages_count++] = BeamformerShaderKind_DAS; { - BeamformerFilterParameters filter = {0}; - BeamformerFilterKind filter_kind = 0; - b32 complex = 0; - u32 size = 0; + BeamformerFilterParameters filter = {.sampling_frequency = bp.sampling_frequency / 2}; BeamformerEmissionParameters *ep = &bp.emission_parameters; - switch (bp.emission_kind) { + switch (bp.emission_parameters.kind) { case BeamformerEmissionKind_Sine:{ - filter_kind = BeamformerFilterKind_Kaiser; + filter.kind = BeamformerFilterKind_Kaiser; filter.kaiser.beta = 5.65f; filter.kaiser.cutoff_frequency = 0.5f * ep->sine.frequency; filter.kaiser.length = 36; - size = sizeof(filter.kaiser); }break; case BeamformerEmissionKind_Chirp:{ - filter_kind = BeamformerFilterKind_MatchedChirp; - + filter.kind = BeamformerFilterKind_MatchedChirp; filter.matched_chirp.duration = ep->chirp.duration; filter.matched_chirp.min_frequency = ep->chirp.min_frequency - bp.demodulation_frequency; filter.matched_chirp.max_frequency = ep->chirp.max_frequency - bp.demodulation_frequency; - size = sizeof(filter.matched_chirp); - complex = 1; + filter.complex = 1; //bp.time_offset += ep->chirp.duration / 2; }break; @@ -495,8 +489,7 @@ execute_study(Arena arena, Stream path, Options *options) InvalidDefaultCase; } - beamformer_create_filter(filter_kind, (f32 *)&filter.kaiser, size, bp.sampling_frequency / 2, - complex, 0, 0); + beamformer_create_filter(&filter, 0, 0); bp.compute_stage_parameters[0] = 0; } diff --git a/util.h b/util.h @@ -208,12 +208,19 @@ typedef alignas(16) union { typedef struct { u8 *beg, *end; } Arena; typedef struct { Arena *arena, original_arena; } TempArena; -typedef struct { iz len; u8 *data; } s8; +typedef struct { i64 len; u8 *data; } s8; #define s8(s) (s8){.len = countof(s) - 1, .data = (u8 *)s} #define s8_comp(s) {sizeof(s) - 1, (u8 *)s} -#define s8_struct(v) (s8){.len = sizeof(*v), .data = (u8 *)v} -typedef struct { iz len; u16 *data; } s16; +typedef struct { i64 length; u8 *data; } str8; +#define str8(s) (str8){.length = countof(s) - 1, .data = (u8 *)s} +#define str8_comp(s) {sizeof(s) - 1, (u8 *)s} +#define str8_struct(v) (str8){.length = sizeof(*v), .data = (u8 *)v} + +#define str8_from_s8(s) (str8){.length = (s).len, .data = (s).data} +#define s8_from_str8(s) (s8){.len = (s).length, .data = (s).data} + +typedef struct { i64 len; u16 *data; } s16; typedef struct { u32 cp, consumed; } UnicodeDecode;