ogl_beamforming

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

Commit: 07cbb9cf1e7d8ec3cd21e094e03c790c53bebd58
Parent: ffe7d0f89e0b7c0ed51eef32b3f84dd735625aac
Author: Randy Palamar
Date:   Mon,  4 May 2026 14:55:27 -0600

meta: import entity packing/referencing code from another project

There are still some things which could be better integrated with
this project but this is a much better place for getting contants,
structs, and enumerations into shaders. This is already being used
to drop a few extra pointer push constants for DAS.

Now if only GLSL allowed struct splatting like the msvc extension.

Diffstat:
Mbeamformer.meta | 231+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mbeamformer_core.c | 99++++++++++++++++++++++++++++++-------------------------------------------------
Mbeamformer_internal.h | 6+++---
Mbeamformer_parameters.h | 13+------------
Mbeamformer_shared_memory.c | 10+++++-----
Mbuild.c | 1867++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mgenerated/beamformer.meta.c | 322+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mlib/ogl_beamformer_lib.c | 4++--
Mmain_linux.c | 12++++++------
Mmain_w32.c | 8++++----
Mui.c | 27+++++++++++++++------------
Mutil.c | 49++++++++++++++++++++++++++++++++-----------------
Mutil.h | 29+++++++++++++++++++----------
13 files changed, 1539 insertions(+), 1138 deletions(-)

diff --git a/beamformer.meta b/beamformer.meta @@ -1,8 +1,31 @@ -@Enumeration(DecodeMode [None Hadamard]) -@Enumeration(RCAOrientation [None Rows Columns]) -@Enumeration(SamplingMode [2X 4X]) +@Constant(4) FilterSlots +@Constant(16) MaxBacklogFrames +@Constant(256) MaxChannelCount +@Constant(256) MaxEmmissionsCount +@Constant(16) MaxComputeShaderStages +@Constant(16) MaxParameterBlocks +@Constant(3) MaxRawDataFramesInFlight + +@Enumeration DecodeMode +{ + None + Hadamard +} + +@Enumeration RCAOrientation +{ + None + Rows + Columns +} -@Table([name size elements complex]) DataKind +@Enumeration SamplingMode +{ + 2X + 4X +} + +@Table([name size elements complex]) DataKindTable { [Int16 2 1 0] [Int16Complex 2 2 1] @@ -11,26 +34,39 @@ [Float16 2 1 0] [Float16Complex 2 2 1] } +@Expand(DataKindTable) @Enumeration(`$(name)`) DataKind -@Table([name samples]) ContrastMode +@Table([name samples]) ContrastModeTable { [None 1] [A1S2 3] } +@Expand(ContrastModeTable) @Enumeration(`$(name)`) ContrastMode -@Enumeration(EmissionKind [Sine Chirp]) +@Enumeration EmissionKind +{ + Sine + Chirp +} -@Table([type name]) SineParameters +@Enumeration InterpolationMode { - [F32 cycles ] - [F32 frequency] + Nearest + Linear + Cubic } -@Table([type name]) ChirpParameters +@Struct SineParameters { - [F32 duration ] - [F32 min_frequency] - [F32 max_frequency] + [cycles F32] + [frequency F32] +} + +@Struct ChirpParameters +{ + [duration F32] + [min_frequency F32] + [max_frequency F32] } @MUnion(EmissionKind [ @@ -38,24 +74,25 @@ ChirpParameters ]) Emission -@Table([name name_lower]) FilterKind +@Table([name name_lower]) FilterKindTable { [Kaiser kaiser] [MatchedChirp matched_chirp] } +@Expand(FilterKindTable) @Enumeration(`$(name)`) FilterKind -@Table([type name]) KaiserFilterParameters +@Struct KaiserFilterParameters { - [F32 cutoff_frequency] - [F32 beta] - [U32 length] + [cutoff_frequency F32] + [beta F32] + [length U32] } -@Table([type name]) ChirpFilterParameters +@Struct ChirpFilterParameters { - [F32 duration] - [F32 min_frequency] - [F32 max_frequency] + [duration F32] + [min_frequency F32] + [max_frequency F32] } @MUnion(FilterKind [ @@ -63,7 +100,7 @@ ChirpFilterParameters ]) Filter -@Table([name pretty_name fixed_transmits]) AcquisitionKind +@Table([name pretty_name fixed_transmits]) AcquisitionKindTable { [FORCES FORCES 1] [UFORCES UFORCES 0] @@ -78,15 +115,9 @@ [Flash Flash 0] [HERO_PA HERO-PA 0] } +@Expand(AcquisitionKindTable) @Enumeration(`$(name)`) AcquisitionKind -@Table([name]) InterpolationMode -{ - [Nearest] - [Linear] - [Cubic] -} - -@Table([name type]) ParametersHead +@Struct ParametersHead { [das_voxel_transform M4] [xdc_transform M4] @@ -105,7 +136,7 @@ [sampling_mode U8] } -@Table([name type]) ParametersUI +@Struct ParametersUI { [output_points SV4] [sampling_frequency F32] @@ -124,8 +155,8 @@ [emission_parameters BeamformerEmissionParameters uint8 12] } -// TODO(rnp): definable constants in meta code (or at least references to enum values) -@Table([name type elements]) ParametersSimple +// TODO(rnp): allow emit statements to reference Constants +@Struct ParametersSimple { [channel_mapping S16 256] [sparse_elements S16 256] @@ -138,11 +169,6 @@ [data_kind S32 1] } -@Expand(AcquisitionKind) @Enumeration(AcquisitionKind `$(name)`) -@Expand(ContrastMode) @Enumeration(ContrastMode `$(name)`) -@Expand(DataKind) @Enumeration(DataKind `$(name)`) -@Expand(FilterKind) @Enumeration(FilterKind `$(name)`) -@Expand(InterpolationMode) @Enumeration(InterpolationMode `$(name)`) @Emit { @@ -162,10 +188,6 @@ `} BeamformerParameters;` `` `typedef struct {` - @Expand(ParametersHead) ` $(%type)$(|)$(name);` - `} BeamformerParametersHead;` - `` - `typedef struct {` @Expand(ParametersUI) ` $(%type)$(|)$(name);` `} BeamformerUIParameters;` `` @@ -195,35 +217,35 @@ `} BeamformerFilterParameters;` `` `read_only global u8 beamformer_data_kind_element_size[] = {` - @Expand(DataKind) ` $(size),` + @Expand(DataKindTable) ` $(size),` `};` `` `read_only global u8 beamformer_data_kind_element_count[] = {` - @Expand(DataKind) ` $(elements),` + @Expand(DataKindTable) ` $(elements),` `};` `` `read_only global u8 beamformer_data_kind_byte_size[] = {` - @Expand(DataKind) ` $(size) * $(elements),` + @Expand(DataKindTable) ` $(size) * $(elements),` `};` `` `read_only global b8 beamformer_data_kind_complex[] = {` - @Expand(DataKind) ` $(complex),` + @Expand(DataKindTable) ` $(complex),` `};` `` `read_only global u8 beamformer_contrast_mode_samples[] = {` - @Expand(ContrastMode) ` $(samples),` + @Expand(ContrastModeTable) ` $(samples),` `};` `` `read_only global u8 beamformer_acquisition_kind_has_fixed_transmits[] = {` - @Expand(AcquisitionKind) ` $(fixed_transmits),` + @Expand(AcquisitionKindTable) ` $(fixed_transmits),` `};` `` `read_only global s8 beamformer_acquisition_kind_strings[] = {` - @Expand(AcquisitionKind) ` s8_comp("$(pretty_name)"),` + @Expand(AcquisitionKindTable) ` s8_comp("$(pretty_name)"),` `};` `` `read_only global s8 beamformer_filter_kind_strings[] = {` - @Expand(FilterKind) ` s8_comp("$(name)"),` + @Expand(FilterKindTable) ` s8_comp("$(name)"),` `};` `` `read_only global s8 beamformer_interpolation_mode_strings[] = {` @@ -238,78 +260,89 @@ @Shader(decode.glsl) Decode { - @Enumeration(DataKind) - @Enumeration(DecodeMode) - @Flags([DilateOutput UseSharedMemory]) + @Enumeration DataKind + @Enumeration DecodeMode @Bake { - @BakeInt(DecodeMode decode_mode ) - @BakeInt(InputChannelStride input_channel_stride ) - @BakeInt(InputSampleStride input_sample_stride ) - @BakeInt(InputTransmitStride input_transmit_stride ) - @BakeInt(OutputChannelStride output_channel_stride ) - @BakeInt(OutputSampleStride output_sample_stride ) - @BakeInt(OutputTransmitStride output_transmit_stride) - @BakeInt(ToProcess to_process ) - @BakeInt(TransmitCount transmit_count ) + [DataKind data_kind U32] + [DilateOutput dilate_output U32] + [UseSharedMemory use_shared_memory U32] + [DecodeMode decode_mode U32] + [InputChannelStride input_channel_stride U32] + [InputSampleStride input_sample_stride U32] + [InputTransmitStride input_transmit_stride U32] + [OutputChannelStride output_channel_stride U32] + [OutputSampleStride output_sample_stride U32] + [OutputTransmitStride output_transmit_stride U32] + [ToProcess to_process U32] + [TransmitCount transmit_count U32] } } @Shader(filter.glsl) Filter { - @Enumeration(DataKind) - @Flags([ComplexFilter OutputFloats]) + @Enumeration DataKind @ShaderAlias Demodulate @Bake { - @BakeInt(DecimationRate decimation_rate ) - @BakeInt(FilterLength filter_length ) - @BakeInt(InputChannelStride input_channel_stride ) - @BakeInt(InputSampleStride input_sample_stride ) - @BakeInt(InputTransmitStride input_transmit_stride ) - @BakeInt(OutputChannelStride output_channel_stride ) - @BakeInt(OutputSampleStride output_sample_stride ) - @BakeInt(OutputTransmitStride output_transmit_stride) - @BakeInt(SampleCount sample_count ) - @BakeFloat(DemodulationFrequency demodulation_frequency) - @BakeFloat(SamplingFrequency sampling_frequency ) + [DataKind data_kind U32] + [Demodulate demodulate U32] + [ComplexFilter complex_filter U32] + [OutputFloats output_floats U32] + [DecimationRate decimation_rate U32] + [FilterLength filter_length U32] + [InputChannelStride input_channel_stride U32] + [InputSampleStride input_sample_stride U32] + [InputTransmitStride input_transmit_stride U32] + [OutputChannelStride output_channel_stride U32] + [OutputSampleStride output_sample_stride U32] + [OutputTransmitStride output_transmit_stride U32] + [SampleCount sample_count U32] + + [DemodulationFrequency demodulation_frequency F32] + [SamplingFrequency sampling_frequency F32] } } @Shader(das.glsl) DAS { - @Enumeration(AcquisitionKind) - @Enumeration(DataKind) - @Enumeration(InterpolationMode) - @Enumeration(RCAOrientation) - @Flags([Fast Sparse CoherencyWeighting SingleFocus SingleOrientation]) + @Enumeration AcquisitionKind + @Enumeration DataKind + @Enumeration InterpolationMode + @Enumeration RCAOrientation @Bake { - @BakeInt(AcquisitionCount acquisition_count ) - @BakeInt(AcquisitionKind acquisition_kind ) - @BakeInt(ChannelCount channel_count ) - @BakeInt(InterpolationMode interpolation_mode ) - @BakeInt(SampleCount sample_count ) - @BakeInt(TransmitReceiveOrientation transmit_receive_orientation) - - @BakeFloat(DemodulationFrequency demodulation_frequency) - @BakeFloat(FNumber f_number ) - @BakeFloat(FocusDepth focus_depth ) - @BakeFloat(SamplingFrequency sampling_frequency ) - @BakeFloat(SpeedOfSound speed_of_sound ) - @BakeFloat(TimeOffset time_offset ) - @BakeFloat(TransmitAngle transmit_angle ) + [DataKind data_kind U32] + [CoherencyWeighting coherency_weighting U32] + [SingleFocus single_focus U32] + [SingleOrientation single_orientation U32] + [Fast fast U32] + [Sparse sparse U32] + [AcquisitionCount acquisition_count U32] + [AcquisitionKind acquisition_kind U32] + [ChannelCount channel_count U32] + [InterpolationMode interpolation_mode U32] + [SampleCount sample_count U32] + [TransmitReceiveOrientation transmit_receive_orientation U32] + + [DemodulationFrequency demodulation_frequency F32] + [FNumber f_number F32] + [FocusDepth focus_depth F32] + [SamplingFrequency sampling_frequency F32] + [SpeedOfSound speed_of_sound F32] + [TimeOffset time_offset F32] + [TransmitAngle transmit_angle F32] } @PushConstants { - [mat4 M4 xdc_transform ] - [mat4 M4 voxel_transform ] - [vec2 V2 xdc_element_pitch] + [xdc_transform M4] + [voxel_transform M4] + [xdc_element_pitch V2] } } @@ -412,7 +445,7 @@ ` properties` @Expand(ParametersHead) ` $(name)(1,$(#type)) $(%type)` @Expand(ParametersUI) ` $(name)(1,$(#type)) $(%type)` - @Expand(ParametersExtra) ` $(name)(1,$(m_size))$(|)$(m_type)` + @Expand(ParametersExtra) ` $(name)(1,$(m_size)) $(m_type)` @Expand(ParametersSimple) ` $(name)(1,$(elements)) $(%type)` ` end` `end` diff --git a/beamformer_core.c b/beamformer_core.c @@ -174,12 +174,12 @@ beamformer_filter_update(BeamformerFilter *f, BeamformerFilterParameters fp, u32 function ComputeFrameIterator compute_frame_iterator(BeamformerCtx *ctx, u32 start_index, u32 needed_frames) { - start_index = start_index % ARRAY_COUNT(ctx->beamform_frames); + start_index = start_index % countof(ctx->beamform_frames); ComputeFrameIterator result; result.frames = ctx->beamform_frames; result.offset = start_index; - result.capacity = ARRAY_COUNT(ctx->beamform_frames); + result.capacity = countof(ctx->beamform_frames); result.cursor = 0; result.needed_frames = needed_frames; return result; @@ -394,12 +394,13 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) /* TODO(rnp): rework decode first and demodulate after */ b32 first = slot == 0; - sd->bake.data_kind = data_kind; + BeamformerDecodeBakeParameters *db = &sd->bake.Decode; + db->data_kind = data_kind; if (!first) { if (data_kind == BeamformerDataKind_Int16) { - sd->bake.data_kind = BeamformerDataKind_Int16Complex; + db->data_kind = BeamformerDataKind_Int16Complex; } else { - sd->bake.data_kind = BeamformerDataKind_Float32Complex; + db->data_kind = BeamformerDataKind_Float32Complex; } } @@ -407,7 +408,6 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) assert(first || ((*last_shader == BeamformerShaderKind_Demodulate || *last_shader == BeamformerShaderKind_Filter))); - BeamformerShaderDecodeBakeParameters *db = &sd->bake.Decode; db->decode_mode = pb->parameters.decode_mode; db->transmit_count = pb->parameters.acquisition_count; @@ -424,7 +424,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) db->output_transmit_stride *= decimation_rate; } - if (run_cuda_hilbert) sd->bake.flags |= BeamformerShaderDecodeFlags_DilateOutput; + db->dilate_output = run_cuda_hilbert; if (db->decode_mode == BeamformerDecodeMode_None) { sd->layout = (uv3){{subgroup_size, 1, 1}}; @@ -433,8 +433,8 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) sd->dispatch.y = (u32)ceil_f32((f32)pb->parameters.channel_count / (f32)sd->layout.y); sd->dispatch.z = (u32)ceil_f32((f32)pb->parameters.acquisition_count / (f32)sd->layout.z); } else if (db->transmit_count > 40) { - sd->bake.flags |= BeamformerShaderDecodeFlags_UseSharedMemory; - db->to_process = 2; + db->use_shared_memory = 1; + db->to_process = 2; if (db->transmit_count == 48) db->to_process = db->transmit_count / 16; @@ -475,13 +475,13 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) time_offset += f->time_delay; - BeamformerShaderFilterBakeParameters *fb = &sd->bake.Filter; - fb->filter_length = (u32)f->length; - if (demod) sd->bake.flags |= BeamformerShaderFilterFlags_Demodulate; - if (f->parameters.complex) sd->bake.flags |= BeamformerShaderFilterFlags_ComplexFilter; + BeamformerFilterBakeParameters *fb = &sd->bake.Filter; + fb->filter_length = (u32)f->length; + fb->demodulate = demod; + fb->complex_filter = f->parameters.complex; - sd->bake.data_kind = data_kind; - if (!first) sd->bake.data_kind = BeamformerDataKind_Float32; + fb->data_kind = data_kind; + if (!first) fb->data_kind = BeamformerDataKind_Float32; /* NOTE(rnp): when we are demodulating we pretend that the sampler was alternating * between sampling the I portion and the Q portion of an IQ signal. Therefore there @@ -508,7 +508,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) fb->input_transmit_stride = pb->parameters.sample_count / 2; if (pb->parameters.decode_mode == BeamformerDecodeMode_None) { - sd->bake.flags |= BeamformerShaderFilterFlags_OutputFloats; + fb->output_floats = 1; } else { /* NOTE(rnp): output optimized layout for decoding */ fb->output_channel_stride = das_channel_stride; @@ -541,12 +541,12 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) commit = 1; }break; case BeamformerShaderKind_DAS:{ - sd->bake.data_kind = BeamformerDataKind_Float32; - if (cp->iq_pipeline) - sd->bake.data_kind = BeamformerDataKind_Float32Complex; + BeamformerDASBakeParameters *db = &sd->bake.DAS; - BeamformerShaderDASBakeParameters *db = &sd->bake.DAS; - BeamformerShaderDASPushConstants *du = &cp->das_ubo_data; + db->data_kind = BeamformerDataKind_Float32; + if (cp->iq_pipeline) db->data_kind = BeamformerDataKind_Float32Complex; + + BeamformerDASPushConstants *du = &cp->das_ubo_data; du->xdc_element_pitch = pb->parameters.xdc_element_pitch; db->sampling_frequency = sampling_frequency; db->demodulation_frequency = pb->parameters.demodulation_frequency; @@ -573,13 +573,13 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) if (id == BeamformerAcquisitionKind_UFORCES || id == BeamformerAcquisitionKind_FORCES) du->voxel_transform = m4_mul(du->xdc_transform, du->voxel_transform); - if (id == BeamformerAcquisitionKind_UFORCES || id == BeamformerAcquisitionKind_UHERCULES) - sd->bake.flags |= BeamformerShaderDASFlags_Sparse; + db->sparse = id == BeamformerAcquisitionKind_UFORCES || + id == BeamformerAcquisitionKind_UHERCULES; - if (pb->parameters.single_focus) sd->bake.flags |= BeamformerShaderDASFlags_SingleFocus; - if (pb->parameters.single_orientation) sd->bake.flags |= BeamformerShaderDASFlags_SingleOrientation; - if (pb->parameters.coherency_weighting) sd->bake.flags |= BeamformerShaderDASFlags_CoherencyWeighting; - else sd->bake.flags |= BeamformerShaderDASFlags_Fast; + db->single_focus = pb->parameters.single_focus; + db->single_orientation = pb->parameters.single_orientation; + db->coherency_weighting = pb->parameters.coherency_weighting; + db->fast = !pb->parameters.coherency_weighting; sd->layout = (uv3){{1, 1, 1}}; @@ -702,28 +702,6 @@ load_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, u32 shader_sl stream_append_s8(&shader_stream, s8(")\n")); } - stream_append_s8(&shader_stream, s8("#define DataKind (0x")); - stream_append_hex_u64(&shader_stream, sd->bake.data_kind); - stream_append_s8(&shader_stream, s8(")\n\n")); - - s8 *flag_names = beamformer_shader_flag_strings[reloadable_index]; - u32 flag_count = beamformer_shader_flag_strings_count[reloadable_index]; - u32 flags = sd->bake.flags; - for (u32 bit = 0; bit < flag_count; bit++) { - stream_append_s8s(&shader_stream, s8("#define "), flag_names[bit], - (flags & (1 << bit))? s8(" 1") : s8(" 0"), s8("\n")); - } - - u32 pc_count = beamformer_shader_push_constant_counts[reloadable_index]; - s8 *pc_names = beamformer_shader_push_constant_names[reloadable_index]; - s8 *pc_types = beamformer_shader_push_constant_glsl_types[reloadable_index]; - if (pc_count) { - stream_append_s8s(&shader_stream, s8("\n\nlayout(std140, binding = 0) uniform PushConstants {\n")); - for (u32 it = 0; it < pc_count; it++) - stream_append_s8s(&shader_stream, s8("\t"), pc_types[it], s8(" "), pc_names[it],s8(";\n")); - stream_append_s8s(&shader_stream, s8("};")); - } - if (!renderdoc_attached()) stream_append_s8(&shader_stream, s8("\n#line 1\n")); @@ -906,11 +884,8 @@ do_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, BeamformerFrame case BeamformerShaderKind_DAS:{ local_persist u32 das_cycle_t = 0; - BeamformerShaderBakeParameters *bp = &cp->shader_descriptors[shader_slot].bake; - b32 fast = (bp->flags & BeamformerShaderDASFlags_Fast) != 0; - b32 sparse = (bp->flags & BeamformerShaderDASFlags_Sparse) != 0; - - if (fast) { + BeamformerDASBakeParameters *db = &cp->shader_descriptors[shader_slot].bake.DAS; + if (db->fast) { glClearTexImage(frame->texture, 0, GL_RED, GL_FLOAT, 0); glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT); glBindImageTexture(0, frame->texture, 0, GL_TRUE, 0, GL_READ_WRITE, cp->iq_pipeline ? GL_RG32F : GL_R32F); @@ -919,7 +894,7 @@ do_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, BeamformerFrame } u32 sparse_texture = cp->textures[BeamformerComputeTextureKind_SparseElements]; - if (!sparse) sparse_texture = 0; + if (!db->sparse) sparse_texture = 0; glBindBufferBase(GL_UNIFORM_BUFFER, 0, cp->ubos[BeamformerComputeUBOKind_DAS]); glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, cc->ping_pong_ssbos[input_ssbo_idx], 0, cp->rf_size); @@ -929,16 +904,16 @@ do_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, BeamformerFrame glProgramUniform1ui(program, DAS_CYCLE_T_UNIFORM_LOC, das_cycle_t++); - if (fast) { + if (db->fast) { i32 loop_end; - if (bp->DAS.acquisition_kind == BeamformerAcquisitionKind_RCA_VLS || - bp->DAS.acquisition_kind == BeamformerAcquisitionKind_RCA_TPW) + if (db->acquisition_kind == BeamformerAcquisitionKind_RCA_VLS || + db->acquisition_kind == BeamformerAcquisitionKind_RCA_TPW) { /* NOTE(rnp): to avoid repeatedly sampling the whole focal vectors * texture we loop over transmits for VLS/TPW */ - loop_end = (i32)bp->DAS.acquisition_count; + loop_end = (i32)db->acquisition_count; } else { - loop_end = (i32)bp->DAS.channel_count; + loop_end = (i32)db->channel_count; } f32 percent_per_step = 1.0f / (f32)loop_end; cc->processing_progress = -percent_per_step; @@ -956,7 +931,7 @@ do_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, BeamformerFrame glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT|GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); }break; case BeamformerShaderKind_Sum:{ - u32 aframe_index = ctx->averaged_frame_index % ARRAY_COUNT(ctx->averaged_frames); + u32 aframe_index = ctx->averaged_frame_index % countof(ctx->averaged_frames); BeamformerFrame *aframe = ctx->averaged_frames + aframe_index; aframe->id = ctx->averaged_frame_index; atomic_store_u32(&aframe->ready_to_present, 0); @@ -967,7 +942,7 @@ do_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, BeamformerFrame u32 base_index = (u32)(frame - ctx->beamform_frames); u32 to_average = (u32)cp->average_frames; u32 frame_count = 0; - u32 *in_textures = push_array(&arena, u32, BeamformerMaxSavedFrames); + u32 *in_textures = push_array(&arena, u32, BeamformerMaxBacklogFrames); ComputeFrameIterator cfi = compute_frame_iterator(ctx, 1 + base_index - to_average, to_average); for (BeamformerFrame *it = frame_next(&cfi); it; it = frame_next(&cfi)) in_textures[frame_count++] = it->texture; diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -101,7 +101,7 @@ typedef struct { /* TODO(rnp): need 1 UBO per filter slot */ #define BEAMFORMER_COMPUTE_UBO_LIST \ - X(DAS, BeamformerShaderDASPushConstants, das) + X(DAS, BeamformerDASPushConstants, das) #define X(k, ...) BeamformerComputeUBOKind_##k, typedef enum {BEAMFORMER_COMPUTE_UBO_LIST BeamformerComputeUBOKind_Count} BeamformerComputeUBOKind; @@ -188,7 +188,7 @@ typedef struct { typedef struct { BeamformerRFBuffer rf_buffer; - BeamformerComputePlan *compute_plans[BeamformerMaxParameterBlockSlots]; + BeamformerComputePlan *compute_plans[BeamformerMaxParameterBlocks]; BeamformerComputePlan *compute_plan_freelist; /* NOTE(rnp): two interstage ssbos are allocated so that they may be used to @@ -316,7 +316,7 @@ typedef struct { BeamformerSharedMemory *shared_memory; i64 shared_memory_size; - BeamformerFrame beamform_frames[BeamformerMaxSavedFrames]; + BeamformerFrame beamform_frames[BeamformerMaxBacklogFrames]; BeamformerFrame *latest_frame; u32 next_render_frame_index; u32 display_frame_index; diff --git a/beamformer_parameters.h b/beamformer_parameters.h @@ -12,7 +12,7 @@ typedef struct { /* NOTE(rnp): this wants to be iterated on both dimensions. it depends entirely on which * visualization method you want to use. the coalescing function wants both directions */ - float times[32][BeamformerShaderKind_ComputeCount]; + float times[32][BeamformerMaxComputeShaderStages]; float rf_time_deltas[32]; } BeamformerComputeStatsTable; @@ -30,17 +30,6 @@ typedef enum { BeamformerViewPlaneTag_Count, } BeamformerViewPlaneTag; -#define BEAMFORMER_CONSTANTS_LIST \ - X(FilterSlots, 4) \ - X(MaxChannelCount, 256) \ - X(MaxComputeShaderStages, 16) \ - X(MaxParameterBlockSlots, 16) \ - X(MaxRawDataFramesInFlight, 3) \ - X(MaxSavedFrames, 16) -#define X(k, v, ...) Beamformer##k = v, -typedef enum {BEAMFORMER_CONSTANTS_LIST} BeamformerConstants; -#undef X - #define BEAMFORMER_LIVE_IMAGING_DIRTY_FLAG_LIST \ X(ImagePlaneOffsets, 0) \ X(TransmitPower, 1) \ diff --git a/beamformer_shared_memory.c b/beamformer_shared_memory.c @@ -14,8 +14,8 @@ typedef struct { BeamformerFilterParameters parameters; u8 filter_slot; u8 parameter_block; - static_assert(BeamformerFilterSlots <= 255, "CreateFilterContext only supports 255 filter slots"); - static_assert(BeamformerMaxParameterBlockSlots <= 255, "CreateFilterContext only supports 255 parameter blocks"); + static_assert(BeamformerFilterSlots <= 255, "CreateFilterContext only supports 255 filter slots"); + static_assert(BeamformerMaxParameterBlocks <= 255, "CreateFilterContext only supports 255 parameter blocks"); } BeamformerCreateFilterContext; typedef enum { @@ -151,7 +151,7 @@ typedef struct { /* NOTE(rnp): not used for locking on w32 but we can use these to peek at the status of * the lock without leaving userspace. */ - i32 locks[(u32)BeamformerSharedMemoryLockKind_Count + (u32)BeamformerMaxParameterBlockSlots]; + i32 locks[(u32)BeamformerSharedMemoryLockKind_Count + (u32)BeamformerMaxParameterBlocks]; /* NOTE(rnp): total number of parameter block regions the client has requested. * used to calculate offset to scratch space and to track number of allocated @@ -265,7 +265,7 @@ beamformer_parameter_block_dirty(BeamformerSharedMemory *sm, u32 block) function BeamformerParameterBlock * beamformer_parameter_block_lock(BeamformerSharedMemory *sm, u32 block, i32 timeout_ms) { - assert(block < BeamformerMaxParameterBlockSlots); + assert(block < BeamformerMaxParameterBlocks); BeamformerParameterBlock *result = 0; if (beamformer_shared_memory_take_lock(sm, BeamformerSharedMemoryLockKind_Count + block, (u32)timeout_ms)) result = beamformer_parameter_block(sm, block); @@ -275,7 +275,7 @@ beamformer_parameter_block_lock(BeamformerSharedMemory *sm, u32 block, i32 timeo function void beamformer_parameter_block_unlock(BeamformerSharedMemory *sm, u32 block) { - assert(block < BeamformerMaxParameterBlockSlots); + assert(block < BeamformerMaxParameterBlocks); beamformer_shared_memory_release_lock(sm, BeamformerSharedMemoryLockKind_Count + block); } diff --git a/build.c b/build.c @@ -15,11 +15,14 @@ #include <setjmp.h> #include <stdio.h> -#define BeamformerShaderKind_ComputeCount (1) +#define BeamformerMaxComputeShaderStages 1 #include "beamformer_parameters.h" global char *g_argv0; +#define META_NAMESPACE_UPPER "Beamformer" +#define META_NAMESPACE_LOWER "beamformer" + #define OUTDIR "out" #define OUTPUT(s) OUTDIR OS_PATH_SEPARATOR s @@ -871,15 +874,15 @@ build_tests(Arena arena) } typedef struct { - s8 *data; - iz count; - iz capacity; + s8 *data; + da_count count; + da_count capacity; } s8_list; function s8 s8_chop(s8 *in, iz count) { - count = CLAMP(count, 0, in->len); + count = Clamp(count, 0, in->len); s8 result = {.data = in->data, .len = count}; in->data += count; in->len -= count; @@ -939,6 +942,7 @@ meta_push_(MetaprogramContext *m, s8 *items, iz count) #define meta_push_line(m, ...) do { meta_indent(m); meta_push(m, ##__VA_ARGS__, s8("\n")); } while(0) #define meta_begin_scope(m, ...) do { meta_push_line(m, __VA_ARGS__); (m)->indentation_level++; } while(0) #define meta_end_scope(m, ...) do { (m)->indentation_level--; meta_push_line(m, __VA_ARGS__); } while(0) +#define meta_push_f64(m, n) stream_append_f64(&(m)->stream, (n), 1000000) #define meta_push_u64(m, n) stream_append_u64(&(m)->stream, (n)) #define meta_push_i64(m, n) stream_append_i64(&(m)->stream, (n)) #define meta_push_u64_hex(m, n) stream_append_hex_u64(&(m)->stream, (n)) @@ -974,21 +978,20 @@ meta_end_and_write_matlab(MetaprogramContext *m, char *path) X(Invalid) \ X(Array) \ X(Bake) \ - X(BakeInt) \ - X(BakeFloat) \ X(BeginScope) \ - X(Emit) \ + X(Constant) \ X(Embed) \ + X(Emit) \ X(EndScope) \ X(Enumeration) \ X(Expand) \ - X(Flags) \ X(MUnion) \ X(PushConstants) \ - X(String) \ X(Shader) \ X(ShaderAlias) \ X(ShaderGroup) \ + X(String) \ + X(Struct) \ X(Table) \ typedef enum { @@ -1015,19 +1018,25 @@ typedef enum { } MetaEmitLang; #define META_KIND_LIST \ - X(M4, m4, float, single, 64, 16) \ - X(SV4, iv4, int32_t, int32, 16, 4) \ - X(UV4, uv4, uint32_t, uint32, 16, 4) \ - X(UV2, uv2, uint32_t, uint32, 8, 2) \ - X(V3, v3, float, single, 12, 3) \ - X(V2, v2, float, single, 8, 2) \ - X(F32, f32, float, single, 4, 1) \ - X(S32, i32, int32_t, int32, 4, 1) \ - X(S16, i16, int16_t, int16, 2, 1) \ - X(S8, i8, int8_t, int8, 1, 1) \ - X(U32, u32, uint32_t, uint32, 4, 1) \ - X(U16, u16, uint16_t, uint16, 2, 1) \ - X(U8, u8, uint8_t, uint8, 1, 1) + X(M4, m4, mat4, float, single, 64, 16) \ + X(V4, v4, vec4, float, single, 16, 4) \ + X(SV4, iv4, ivec4, int32_t, int32, 16, 4) \ + X(UV4, uv4, uvec4, uint32_t, uint32, 16, 4) \ + X(UV2, uv2, uvec2, uint32_t, uint32, 8, 2) \ + X(V3, v3, vec3, float, single, 12, 3) \ + X(V2, v2, vec2, float, single, 8, 2) \ + X(F32, f32, float, float, single, 4, 1) \ + X(S32, i32, int32_t, int32_t, int32, 4, 1) \ + X(S16, i16, int16_t, int16_t, int16, 2, 1) \ + X(S8, i8, int8_t, int8_t, int8, 1, 1) \ + X(B64, b64, uint64_t, uint64_t, uint64, 8, 1) \ + X(B32, b32, bool, uint32_t, uint32, 4, 1) \ + X(B16, b16, uint16_t, uint16_t, uint16, 2, 1) \ + X(B8, b8, uint8_t, uint8_t, uint8, 1, 1) \ + X(U64, u64, uint64_t, uint64_t, uint64, 8, 1) \ + X(U32, u32, uint32_t, uint32_t, uint32, 4, 1) \ + X(U16, u16, uint16_t, uint16_t, uint16, 2, 1) \ + X(U8, u8, uint8_t, uint8_t, uint8, 1, 1) \ typedef enum { #define X(k, ...) MetaKind_## k, @@ -1037,13 +1046,13 @@ typedef enum { } MetaKind; read_only global u8 meta_kind_byte_sizes[] = { - #define X(_k, _c, _b, _m, bytes, ...) bytes, + #define X(_k, _c, _g, _b, _m, bytes, ...) bytes, META_KIND_LIST #undef X }; read_only global u8 meta_kind_elements[] = { - #define X(_k, _c, _b, _m, _by, elements, ...) elements, + #define X(_k, _c, _g, _b, _m, _by, elements, ...) elements, META_KIND_LIST #undef X }; @@ -1055,13 +1064,19 @@ read_only global s8 meta_kind_meta_types[] = { }; read_only global s8 meta_kind_matlab_types[] = { - #define X(_k, _c, _b, m, ...) s8_comp(#m), + #define X(_k, _c, _g, _b, m, ...) s8_comp(#m), META_KIND_LIST #undef X }; read_only global s8 meta_kind_base_c_types[] = { - #define X(_k, _c, base, ...) s8_comp(#base), + #define X(_k, _c, _g, base, ...) s8_comp(#base), + META_KIND_LIST + #undef X +}; + +read_only global s8 meta_kind_glsl_types[] = { + #define X(_k, _c, glsl, ...) s8_comp(#glsl), META_KIND_LIST #undef X }; @@ -1106,8 +1121,8 @@ typedef struct { typedef struct { MetaEntry *data; - iz count; - iz capacity; + da_count count; + da_count capacity; s8 raw; } MetaEntryStack; @@ -1153,6 +1168,9 @@ global jmp_buf compiler_jmp_buf; #define meta_parser_restore(v) swap((v)->p, (v)->save_point) #define meta_parser_commit(v) meta_parser_restore(v) +#define meta_compiler_message(format, ...) \ + fprintf(stderr, format, ##__VA_ARGS__) + #define meta_compiler_error_message(loc, format, ...) \ fprintf(stderr, "%s:%u:%u: error: "format, compiler_file, \ loc.line + 1, loc.column + 1, ##__VA_ARGS__) @@ -1263,7 +1281,7 @@ meta_parser_trim(MetaParser *p) }break; case '\n':{ p->p.location.line++; p->p.location.column = 0; comment = 0; }break; case '/':{ - comment = ((s + 1) != end && s[1] == '/'); + comment |= ((s + 1) != end && s[1] == '/'); if (comment) s++; } /* FALLTHROUGH */ default:{done = !comment;}break; @@ -1494,14 +1512,22 @@ meta_entry_stack_from_file(Arena *arena, char *file) { MetaEntry *e = da_push(arena, &result); switch (token) { - case MetaParseToken_RawString:{ + case MetaParseToken_String: + case MetaParseToken_RawString: + { e->kind = MetaEntryKind_String; e->location = parser.save_point.location; e->name = parser.u.string; }break; - case MetaParseToken_BeginArray: + case MetaParseToken_BeginScope: case MetaParseToken_EndScope: + { + e->kind = parser.u.kind; + e->location = parser.save_point.location; + }break; + + case MetaParseToken_BeginArray: case MetaParseToken_Entry: { e->kind = parser.u.kind; @@ -1569,63 +1595,12 @@ meta_entry_argument_expect(MetaEntry *e, u32 index, MetaEntryArgumentKind kind) } typedef struct { - s8_list *data; - iz count; - iz capacity; -} s8_list_table; - -typedef struct { - s8 *names_upper; - s8 *names_lower; - u32 floating_point; - u32 entry_count; - u32 shader_id; -} MetaShaderBakeParameters; -DA_STRUCT(MetaShaderBakeParameters, MetaShaderBakeParameters); - -typedef struct { - iz kind; - iz variation; -} MetaEnumeration; - -typedef struct { - u32 *data; - iz count; - iz capacity; + da_count *data; + da_count count; + da_count capacity; } MetaIDList; typedef struct { - MetaShaderBakeParameters *bake_parameters; - u32 name_id; - i32 base_shader_id; - u32 push_constants_id; - u32 flag_list_id; - MetaIDList shader_enumeration_ids; -} MetaShader; -DA_STRUCT(MetaShader, MetaShader); - -typedef struct { - MetaShader *shader; - s8 file; -} MetaBaseShader; -DA_STRUCT(MetaBaseShader, MetaBaseShader); - -typedef struct { - s8 name; - MetaIDList shaders; -} MetaShaderGroup; -DA_STRUCT(MetaShaderGroup, MetaShaderGroup); - -typedef struct { - s8 *fields; - s8 **entries; - u32 field_count; - u32 entry_count; - u32 table_name_id; -} MetaTable; -DA_STRUCT(MetaTable, MetaTable); - -typedef struct { s8 enumeration_name; s8 *sub_table_names; u32 sub_table_count; @@ -1690,8 +1665,8 @@ typedef enum { typedef struct { MetaExpansionPart *parts; - u32 part_count; - u32 table_id; + u32 part_count; + da_count table_entity_id; } MetaEmitOperationExpansion; typedef struct { @@ -1705,54 +1680,165 @@ typedef struct { typedef struct { MetaEmitOperation *data; - iz count; - iz capacity; + da_count count; + da_count capacity; s8 filename; } MetaEmitOperationList; typedef struct { MetaEmitOperationList *data; - iz count; - iz capacity; + da_count count; + da_count capacity; } MetaEmitOperationListSet; +typedef struct { da_count value; } MetaEntityID; + +typedef enum { + MetaShaderKind_Alias, + MetaShaderKind_Compute, + MetaShaderKind_Count, +} MetaShaderKind; + +typedef struct { + MetaShaderKind kind; + MetaIDList entity_reference_ids; + s8 file; + MetaEntityID alias_parent_id; +} MetaShader; + +#define META_STRUCT_FIELDS \ + X(Name, name) \ + X(Type, type) \ + X(Elements, elements) \ + +#define X(id, ...) MetaStructField_##id, +typedef enum {META_STRUCT_FIELDS} MetaStructFields; +#undef X + +#define META_BAKE_FIELDS \ + X(NameUpper, name_upper) \ + X(NameLower, name_lower) \ + X(Type, type) \ + +#define X(id, ...) MetaBakeField_##id, +typedef enum {META_BAKE_FIELDS} MetaBakeFields; +#undef X + +typedef struct { + s8 *fields; + s8 **entries; + u32 field_count; + u32 entry_count; + union { + i32 *struct_type_ids; + }; +} MetaTable; + +typedef enum { + MetaConstantKind_Integer, + MetaConstantKind_Float, + MetaConstantKind_Count, +} MetaConstantKind; + +typedef struct { + MetaConstantKind kind; + u32 name_id; + union { + u64 U64; + f64 F64; + }; +} MetaConstant; + +typedef struct { + s8 reference_name; + MetaEntityID resolved_id; + da_count reference_count; +} 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 +}; + +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 + #undef X + MetaEntityKind_Count, +} MetaEntityKind; + +typedef struct { + MetaEntityKind kind; + MetaEntityID parent; + MetaEntityID first_child; + MetaEntityID next_sibling; + MetaEntityID previous_sibling; + MetaLocation location; + union { + MetaConstant constant; + MetaEntityReference reference; + MetaShader shader; + MetaTable table; + }; +} MetaEntity; +DA_STRUCT(MetaEntity, MetaEntity); + typedef struct { Arena *arena, scratch; s8 filename; s8 directory; - s8_list enumeration_kinds; - s8_list_table enumeration_members; + s8_list munion_namespaces; + MetaMUnionList munions; - s8_list_table flags_for_shader; + // NOTE(rnp): arrays of entity ids sorted by kind and counted by entity_kind_counts + da_count *entity_kind_ids[MetaEntityKind_Count]; - s8_list table_names; - MetaTableList tables; + da_count entity_kind_counts[MetaEntityKind_Count]; + s8_list entity_names; + MetaEntityList entities; - MetaTableList push_constant_tables; + // NOTE(rnp): list of all entities referenced by shaders. needed for header string baking + MetaIDList shader_entity_references; - s8_list munion_namespaces; - MetaMUnionList munions; + // NOTE(rnp): dumb jank to support treating CudaHilbert/CudaDecode as shaders and + // allowing shader names to alias. + da_count base_shader_count; + da_count *base_shader_ids; + // 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]; - - MetaShaderBakeParametersList shader_bake_parameters; - MetaIDList shader_enumerations; - MetaShaderGroupList shader_groups; - MetaShaderList shaders; - MetaBaseShaderList base_shaders; - s8_list shader_names; } MetaContext; -function iz -meta_lookup_id_slow(MetaIDList *v, u32 id) +function da_count +meta_lookup_id_slow(da_count *v, da_count count, da_count id) { // TODO(rnp): obviously this is slow - iz result = -1; - for (iz i = 0; i < v->count; i++) { - if (id == v->data[i]) { + da_count result = -1; + for (da_count i = 0; i < count; i++) { + if (id == v[i]) { result = i; break; } @@ -1760,10 +1846,10 @@ meta_lookup_id_slow(MetaIDList *v, u32 id) return result; } -function iz +function da_count meta_intern_string(MetaContext *ctx, s8_list *sv, s8 s) { - iz result = meta_lookup_string_slow(sv->data, sv->count, s); + da_count result = meta_lookup_string_slow(sv->data, sv->count, s); if (result < 0) { *da_push(ctx->arena, sv) = s; result = sv->count - 1; @@ -1771,10 +1857,10 @@ meta_intern_string(MetaContext *ctx, s8_list *sv, s8 s) return result; } -function iz -meta_intern_id(MetaContext *ctx, MetaIDList *v, u32 id) +function da_count +meta_intern_id(MetaContext *ctx, MetaIDList *v, da_count id) { - iz result = meta_lookup_id_slow(v, id); + da_count result = meta_lookup_id_slow(v->data, v->count, id); if (result < 0) { *da_push(ctx->arena, v) = id; result = v->count - 1; @@ -1782,115 +1868,221 @@ meta_intern_id(MetaContext *ctx, MetaIDList *v, u32 id) return result; } -function iz -meta_pack_shader_bake_parameters(MetaContext *ctx, MetaEntry *e, iz entry_count, u32 shader_id, u32 *table_id) +function da_count +meta_entity_children_count(MetaContext *ctx, MetaEntityID entity_id) { - assert(e->kind == MetaEntryKind_Bake); + MetaEntityID child = ctx->entities.data[entity_id.value].first_child; + da_count result = 0; + if (child.value != 0) { + do { + result++; + child = ctx->entities.data[child.value].next_sibling; + } while (child.value != ctx->entities.data[entity_id.value].first_child.value); + } + return result; +} - MetaShaderBakeParameters *bp = da_push(ctx->arena, &ctx->shader_bake_parameters); - bp->shader_id = shader_id; - if (table_id) *table_id = (u32)da_index(bp, &ctx->shader_bake_parameters); +function MetaEntity * +meta_entity(MetaContext *ctx, MetaEntityID id) +{ + assert(id.value != 0 && id.value < ctx->entities.count); + MetaEntity *result = ctx->entities.data + id.value; + return result; +} - if (e->argument_count) meta_entry_argument_expected_(e, 0, 0); +function MetaEntityID +meta_root_entity_id(MetaContext *ctx) +{ + MetaEntityID result = {0}; + return result; +} - MetaEntryScope scope = meta_entry_extract_scope(e, entry_count); - if (scope.consumed > 1) { - for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) { - if (row->kind != MetaEntryKind_BakeInt && row->kind != MetaEntryKind_BakeFloat) - meta_entry_nesting_error(row, MetaEntryKind_Bake); - meta_entry_argument_expected(row, s8("name"), s8("name_lower")); - bp->entry_count++; +function MetaEntityID +meta_intern_entity(MetaContext *ctx, s8 name, MetaEntityKind kind, MetaEntityID parent, + MetaLocation location, b32 allow_existing) +{ + MetaEntityID result = {0}; + assert(ctx->entities.data[0].kind == MetaEntityKind_Nil); + assert(Between(kind, MetaEntityKind_Nil + 1, MetaEntityKind_Count - 1)); + + da_count name_id = meta_intern_string(ctx, &ctx->entity_names, name); + if (name_id < ctx->entities.count && ctx->entities.data[name_id].kind != kind) { + s8 old_kind = meta_entity_kind_names[ctx->entities.data[name_id].kind]; + s8 new_kind = meta_entity_kind_names[kind]; + meta_compiler_error_message(location, "attempting to redefine %.*s as kind %.*s\n", + (i32)name.len, name.data, (i32)new_kind.len, new_kind.data); + meta_compiler_error_message(ctx->entities.data[name_id].location, "previously defined as kind %.*s\n", + (i32)old_kind.len, old_kind.data); + meta_error(); + } else if (name_id < ctx->entities.count && !allow_existing) { + meta_compiler_error_message(location, "redefinition of %.*s\n", (i32)name.len, name.data); + meta_compiler_error_message(ctx->entities.data[name_id].location, "previously defined here\n"); + meta_error(); + } else { + if (name_id < ctx->entities.count) { + result.value = name_id; + } else { + ctx->entity_kind_counts[kind]++; + MetaEntity *new = da_push(ctx->arena, &ctx->entities); + new->location = location; + result.value = da_index(new, &ctx->entities); } - if (bp->entry_count > 32) - meta_entry_error(e, "maximum bake parameter count exceeded: limit: 32\n"); + MetaEntity *e = ctx->entities.data + result.value; + e->kind = kind; + e->parent = parent; - bp->names_upper = push_array(ctx->arena, s8, bp->entry_count); - bp->names_lower = push_array(ctx->arena, s8, bp->entry_count); + MetaEntity *p = ctx->entities.data + parent.value; + e->next_sibling = p->first_child; + p->first_child = result; - u32 row_index = 0; - for (MetaEntry *row = scope.start; row != scope.one_past_last; row++, row_index++) { - bp->names_upper[row_index] = row->arguments[0].string; - bp->names_lower[row_index] = row->arguments[1].string; - bp->floating_point |= (u32)(row->kind == MetaEntryKind_BakeFloat) << row_index; - } + if (e->next_sibling.value == 0) + e->next_sibling = p->first_child; + + e->previous_sibling = ctx->entities.data[e->next_sibling.value].previous_sibling; + ctx->entities.data[e->next_sibling.value].previous_sibling = result; + ctx->entities.data[e->previous_sibling.value].next_sibling = result; } - return scope.consumed; + return result; } -function iz -meta_enumeration_id(MetaContext *ctx, s8 kind) +function MetaEntityID +meta_entity_reference(MetaContext *ctx, s8 name, MetaLocation location) { - iz result = meta_intern_string(ctx, &ctx->enumeration_kinds, kind); - if (ctx->enumeration_kinds.count != ctx->enumeration_members.count) { - da_push(ctx->arena, &ctx->enumeration_members); - assert(result == (ctx->enumeration_members.count - 1)); + MetaEntityID result = {0}; + 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); + MetaEntity *r = meta_entity(ctx, result); + if (r->reference.reference_count == 0) + ctx->entity_names.data[result.value] = push_s8(ctx->arena, ref_name); + r->reference.reference_count++; + r->reference.reference_name = name; } return result; } -function void -meta_extend_enumeration(MetaContext *ctx, s8 kind, s8 *variations, uz count) +function MetaEntityID +meta_entity_first_child_of_kind(MetaContext *ctx, MetaEntity *e, MetaEntityKind kind) { - iz kidx = meta_enumeration_id(ctx, kind); - /* NOTE(rnp): may overcommit if duplicates exist in variations */ - da_reserve(ctx->arena, ctx->enumeration_members.data + kidx, (iz)count); - for (uz i = 0; i < count; i++) - meta_intern_string(ctx, ctx->enumeration_members.data + kidx, variations[i]); -} - -function MetaEnumeration -meta_commit_enumeration(MetaContext *ctx, s8 kind, s8 variation) -{ - iz kidx = meta_enumeration_id(ctx, kind); - iz vidx = meta_intern_string(ctx, ctx->enumeration_members.data + kidx, variation); - MetaEnumeration result = {.kind = kidx, .variation = vidx}; + MetaEntityID result = {0}; + MetaEntityID child = e->first_child; + do { + if (ctx->entities.data[child.value].kind == kind) { + result = child; + break; + } + child = ctx->entities.data[child.value].next_sibling; + } while (child.value != e->first_child.value); return result; } -function u16 -meta_pack_shader_name(MetaContext *ctx, s8 base_name, MetaLocation loc) +function void +meta_pack_table_begin(MetaEntry *e, MetaTable *t) { - iz result = meta_intern_string(ctx, &ctx->shader_names, base_name); - if (result > (iz)U16_MAX) - meta_compiler_error(loc, "maximum base shaders exceeded: limit: %lu\n", U16_MAX); - return (u16)result; + switch (e->kind) { + + case MetaEntryKind_Bake: + { + meta_entry_argument_expected_(e, 0, 0); + #define X(_i, name, ...) s8_comp(#name), + read_only local_persist s8 bake_fields[] = {META_BAKE_FIELDS}; + #undef X + t->fields = bake_fields; + t->field_count = countof(bake_fields); + }break; + + case MetaEntryKind_Enumeration:{ + read_only local_persist s8 enumeration_fields[] = {s8_comp("name")}; + t->fields = enumeration_fields; + t->field_count = countof(enumeration_fields); + }break; + + case MetaEntryKind_PushConstants: + case MetaEntryKind_Struct: + { + meta_entry_argument_expected_(e, 0, 0); + #define X(_i, name, ...) s8_comp(#name), + read_only local_persist s8 struct_fields[] = {META_STRUCT_FIELDS}; + #undef X + t->fields = struct_fields; + t->field_count = countof(struct_fields); + }break; + + case MetaEntryKind_Table:{ + meta_entry_argument_expected(e, s8("[field ...]")); + MetaEntryArgument fields = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_Array); + t->fields = fields.strings; + t->field_count = (u32)fields.count; + }break; + + InvalidDefaultCase; + } } -function u8 -meta_commit_shader_flag(MetaContext *ctx, u32 flag_list_id, s8 flag, MetaEntry *e) +function void +meta_direct_enumeration(MetaContext *ctx, s8 name, s8 *variations, u64 count, MetaLocation location) { - assert(flag_list_id < ctx->flags_for_shader.count); - iz index = meta_intern_string(ctx, ctx->flags_for_shader.data + flag_list_id, flag); - if (index > 31) meta_entry_error(e, "maximum shader local flags exceeded: limit: 32\n"); - u8 result = (u8)index; - return result; + 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 iz -meta_fill_table(MetaContext *ctx, MetaEntry *e, iz entry_count, MetaTable *t) +function i64 +meta_pack_table_entity(MetaContext *ctx, MetaEntry *e, i64 entry_count, s8 name, MetaEntityID parent) { - MetaEntryScope scope = meta_entry_extract_scope(e, entry_count); + MetaEntityKind entity_kind = MetaEntityKind_Nil; + switch (e->kind) { + case MetaEntryKind_Bake:{ entity_kind = MetaEntityKind_BakeParameters;}break; + case MetaEntryKind_Enumeration:{ entity_kind = MetaEntityKind_Enumeration; }break; + case MetaEntryKind_PushConstants:{entity_kind = MetaEntityKind_PushConstants; }break; + case MetaEntryKind_Struct:{ entity_kind = MetaEntityKind_Struct; }break; + case MetaEntryKind_Table:{ entity_kind = MetaEntityKind_Table; }break; + InvalidDefaultCase; + } + + MetaEntityID entity_id = meta_intern_entity(ctx, name, entity_kind, parent, e->location, 0); + MetaTable table = {0}, *t = &table; + meta_pack_table_begin(e, t); + + b32 structure = (e->kind == MetaEntryKind_Struct || e->kind == MetaEntryKind_PushConstants); + + MetaEntryScope scope = meta_entry_extract_scope(e, entry_count); if (scope.consumed > 1) { for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) { - if (row->kind != MetaEntryKind_Array) + if (row->kind != MetaEntryKind_Array && row->kind != MetaEntryKind_String) meta_entry_nesting_error(row, e->kind); - MetaEntryArgument entries = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_Array); - if (entries.count != t->field_count) { + MetaEntryArgument entries = {.count = 1}; + if (row->kind == MetaEntryKind_Array) + entries.count = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_Array).count; + + if (structure && entries.count != 2 && entries.count != 3) { + meta_compiler_error(row->location, "incorrect field count for @%s entry got: %zu expected: " + "[name type (elements)]\n", meta_entry_kind_strings[e->kind], + (size_t)entries.count); + } else if (!structure && entries.count != t->field_count) { meta_compiler_error_message(row->location, "incorrect field count for @%s entry got: %zu expected: %u\n", - meta_entry_kind_strings[e->kind], - entries.count, t->field_count); + meta_entry_kind_strings[e->kind], (size_t)entries.count, t->field_count); fprintf(stderr, " fields: ["); - for (uz i = 0; i < t->field_count; i++) { + for (u64 i = 0; i < t->field_count; i++) { if (i != 0) fprintf(stderr, ", "); fprintf(stderr, "%.*s", (i32)t->fields[i].len, t->fields[i].data); } fprintf(stderr, "]\n"); meta_error(); } + t->entry_count++; } @@ -1900,123 +2092,104 @@ meta_fill_table(MetaContext *ctx, MetaEntry *e, iz entry_count, MetaTable *t) u32 row_index = 0; for (MetaEntry *row = scope.start; row != scope.one_past_last; row++, row_index++) { - s8 *fs = row->arguments->strings; + s8 *fs = &row->name; + if (row->arguments) + fs = row->arguments->strings; + for (u32 field = 0; field < t->field_count; field++) t->entries[field][row_index] = fs[field]; + + // NOTE(rnp): if we are filling out a struct the array element count is optional + // and defaults to 1. fill this out here for uniformity elsewhere in the code + if (structure && row->arguments->count == 2) + t->entries[2][row_index] = s8("1"); } } + MetaEntity *entity = meta_entity(ctx, entity_id); + entity->table = table; + + switch (e->kind) { + 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_Enumeration: + case MetaEntryKind_Table: + {}break; + + InvalidDefaultCase; + } + return scope.consumed; } -function iz -meta_pack_shader_common(MetaContext *ctx, MetaShader *s, MetaEntry *e, iz entry_count, MetaEntryKind base_kind) +function i64 +meta_pack_shader_common(MetaContext *ctx, MetaEntityID shader_id, MetaEntry *e, i64 entry_count, MetaEntityID group_entity_id) { - iz result = 0; + assert(ctx->entities.data[shader_id.value].kind == MetaEntityKind_Shader); + i64 result = 0; + switch(e->kind) { - case MetaEntryKind_Enumeration:{ - meta_entry_argument_expected(e, s8("kind")); - s8 kind = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; - iz kid = meta_enumeration_id(ctx, kind); - meta_intern_id(ctx, &s->shader_enumeration_ids, - (u32)meta_intern_id(ctx, &ctx->shader_enumerations, (u32)kid)); + case MetaEntryKind_Bake:{ + e->name = push_s8_from_parts(ctx->arena, s8(""), ctx->entity_names.data[shader_id.value], s8("BakeParameters")); + result = meta_pack_table_entity(ctx, e, entry_count, e->name, shader_id); }break; case MetaEntryKind_PushConstants:{ - if (s->push_constants_id != (u32)-1) { - meta_entry_error(e, "invalid @%s in @%s: only one @%s allowed per @%s\n", - meta_entry_kind_strings[e->kind], meta_entry_kind_strings[base_kind], - meta_entry_kind_strings[e->kind], meta_entry_kind_strings[base_kind]); - } - - read_only local_persist s8 push_constant_fields[] = { - s8_comp("glsl_type"), - s8_comp("type"), - s8_comp("name"), - }; - - MetaTable *t = da_push(ctx->arena, &ctx->push_constant_tables); - t->fields = push_constant_fields; - t->field_count = countof(push_constant_fields); - - s->push_constants_id = (u32)da_index(t, &ctx->push_constant_tables); + e->name = push_s8_from_parts(ctx->arena, s8(""), ctx->entity_names.data[shader_id.value], s8("PushConstants")); + result = meta_pack_table_entity(ctx, e, entry_count, e->name, shader_id); + goto reference; + }break; - result = meta_fill_table(ctx, e, entry_count, t); + case MetaEntryKind_ShaderAlias:{ + MetaEntityID alias_id = meta_intern_entity(ctx, e->name, MetaEntityKind_Shader, group_entity_id, + e->location, 0); + meta_entity(ctx, alias_id)->shader.kind = MetaShaderKind_Alias; + meta_entity(ctx, alias_id)->shader.alias_parent_id = shader_id; + }break; - if (t->entry_count > 32) - meta_entry_error(e, "maximum push constant parameters exceeded: limit: 32\n"); + case MetaEntryKind_Enumeration: + case MetaEntryKind_Constant: + case MetaEntryKind_Struct: + reference: + { + 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); + meta_intern_id(ctx, &meta_entity(ctx, shader_id)->shader.entity_reference_ids, ref_id.value); }break; - default:{ meta_entry_nesting_error(e, base_kind); }break; + default:{ meta_entry_nesting_error(e, MetaEntryKind_Shader); }break; } return result; } -function iz -meta_pack_compute_shader(MetaContext *ctx, MetaEntry *entries, iz entry_count, MetaShaderGroup *sg) +function i64 +meta_pack_compute_shader(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID group_entity_id) { assert(entries[0].kind == MetaEntryKind_Shader); - MetaShader *s = da_push(ctx->arena, &ctx->shaders); - { - s8_list *flag_list = da_push(ctx->arena, &ctx->flags_for_shader); - s->flag_list_id = (u32)da_index(flag_list, &ctx->flags_for_shader); - } - s->name_id = meta_pack_shader_name(ctx, entries->name, entries->location); - s->push_constants_id = -1; - s->base_shader_id = -1; - - *da_push(ctx->arena, &sg->shaders) = (u32)da_index(s, &ctx->shaders); + MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_Shader, group_entity_id, + entries->location, 0); + meta_entity(ctx, entity_id)->shader.kind = MetaShaderKind_Compute; if (entries->argument_count > 1) { meta_entry_argument_expected(entries, s8("[file_name]")); } else if (entries->argument_count == 1) { - MetaBaseShader *bs = da_push(ctx->arena, &ctx->base_shaders); - bs->file = meta_entry_argument_expect(entries, 0, MetaEntryArgumentKind_String).string; - bs->shader = s; - s->base_shader_id = (u32)da_index(bs, &ctx->base_shaders); + s8 shader_file = meta_entry_argument_expect(entries, 0, MetaEntryArgumentKind_String).string; + meta_entity(ctx, entity_id)->shader.file = shader_file; } MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count); if (scope.consumed > 1) { - for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) { - switch (e->kind) { - - case MetaEntryKind_ShaderAlias:{ - MetaShader *sa = da_push(ctx->arena, &ctx->shaders); - sa->base_shader_id = s->base_shader_id; - sa->name_id = meta_pack_shader_name(ctx, e->name, e->location); - sa->push_constants_id = -1; - *da_push(ctx->arena, &sg->shaders) = (u32)da_index(sa, &ctx->shaders); - meta_commit_shader_flag(ctx, s->flag_list_id, e->name, e); - }break; - - case MetaEntryKind_Flags:{ - meta_entry_argument_expected(e, s8("[flag ...]")); - MetaEntryArgument flags = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_Array); - for (u32 index = 0; index < flags.count; index++) - meta_commit_shader_flag(ctx, s->flag_list_id, flags.strings[index], e); - }break; - - case MetaEntryKind_Bake:{ - if (s->bake_parameters) { - meta_entry_error(e, "invalid @%s in @%s: only one @%s allowed per @%s\n", - meta_entry_kind_strings[e->kind], meta_entry_kind_strings[MetaEntryKind_Shader], - meta_entry_kind_strings[e->kind], meta_entry_kind_strings[MetaEntryKind_Shader]); - } - u32 table_id; - e += meta_pack_shader_bake_parameters(ctx, e, scope.one_past_last - e, - (u32)da_index(s, &ctx->shaders), &table_id); - s->bake_parameters = ctx->shader_bake_parameters.data + table_id; - }break; - - default:{ - e += meta_pack_shader_common(ctx, s, e, scope.one_past_last - e, MetaEntryKind_Shader); - }break; - } - } + for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) + e += meta_pack_shader_common(ctx, entity_id, e, scope.one_past_last - e, group_entity_id); } else { assert(scope.consumed == 1); // TODO(rnp): some functions (@Expand) expect no scope and that the next entry @@ -2026,20 +2199,20 @@ meta_pack_compute_shader(MetaContext *ctx, MetaEntry *entries, iz entry_count, M return scope.consumed; } -function iz -meta_pack_shader_group(MetaContext *ctx, MetaEntry *entries, iz entry_count) +function i64 +meta_pack_shader_group(MetaContext *ctx, MetaEntry *entries, i64 entry_count) { assert(entries->kind == MetaEntryKind_ShaderGroup); - MetaShaderGroup *sg = da_push(ctx->arena, &ctx->shader_groups); - sg->name = entries->name; + MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_ShaderGroup, + meta_root_entity_id(ctx), entries->location, 0); MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count); if (scope.consumed > 1) { for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) { switch (e->kind) { case MetaEntryKind_Shader:{ - e += meta_pack_compute_shader(ctx, e, scope.one_past_last - e, sg); + e += meta_pack_compute_shader(ctx, e, scope.one_past_last - e, entity_id); }break; default:{meta_entry_nesting_error(e, MetaEntryKind_ShaderGroup);}break; } @@ -2092,27 +2265,33 @@ meta_expansion_string_split(s8 string, s8 *left, s8 *inner, s8 *remainder, MetaL function MetaExpansionPart * meta_push_expansion_part(MetaContext *ctx, Arena *arena, MetaExpansionPartList *parts, - MetaExpansionPartKind kind, s8 string, MetaTable *t, MetaLocation loc) + MetaExpansionPartKind kind, s8 string, MetaEntity *table, MetaLocation loc) { MetaExpansionPart *result = da_push(arena, parts); + result->kind = kind; switch (kind) { case MetaExpansionPartKind_Alignment: case MetaExpansionPartKind_Conditional: {}break; + case MetaExpansionPartKind_EvalKind: case MetaExpansionPartKind_EvalKindCount: case MetaExpansionPartKind_Reference: { - iz index = meta_lookup_string_slow(t->fields, t->field_count, string); + assert(meta_entity_kind_is_table[table->kind]); + MetaTable *t = &table->table; + + da_count index = meta_lookup_string_slow(t->fields, t->field_count, string); result->strings = t->entries[index]; if (index < 0) { /* TODO(rnp): fix this location to point directly at the field in the string */ - s8 table_name = ctx->table_names.data[t->table_name_id]; + s8 table_name = ctx->entity_names.data[da_index(table, &ctx->entities)]; meta_compiler_error(loc, "table \"%.*s\" does not contain member: %.*s\n", (i32)table_name.len, table_name.data, (i32)string.len, string.data); } }break; + case MetaExpansionPartKind_String:{ result->string = string; }break; InvalidDefaultCase; } @@ -2213,8 +2392,8 @@ meta_expansion_token(MetaExpansionParser *p) switch (result) { case MetaExpansionToken_Number:{ - IntegerConversion integer = integer_from_s8(p->s); - if (integer.result != IntegerConversionResult_Success) { + NumberConversion integer = integer_from_s8(p->s); + if (integer.result != NumberConversionResult_Success) { /* TODO(rnp): point at start */ meta_compiler_error(p->loc, "invalid integer in expansion string\n"); } @@ -2262,13 +2441,13 @@ meta_expansion_end_conditional(MetaExpansionPart *ep, MetaExpansionParser *p, Me } function MetaExpansionPartList -meta_generate_expansion_set(MetaContext *ctx, Arena *arena, s8 expansion_string, MetaTable *t, MetaLocation loc) +meta_generate_expansion_set(MetaContext *ctx, Arena *arena, s8 expansion_string, MetaEntity *table, MetaLocation loc) { MetaExpansionPartList result = {0}; s8 left = {0}, inner, remainder = expansion_string; do { meta_expansion_string_split(remainder, &left, &inner, &remainder, loc); - if (left.len) meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, left, t, loc); + if (left.len) meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, left, table, loc); if (inner.len) { MetaExpansionParser p[1] = {{.s = inner, .loc = loc}}; @@ -2282,11 +2461,11 @@ meta_generate_expansion_set(MetaContext *ctx, Arena *arena, s8 expansion_string, if (count_test_parts) test_part->conditional.instruction_skip++; switch (token) { case MetaExpansionToken_Alignment:{ - meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Alignment, p->s, t, loc); + meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Alignment, p->s, table, loc); }break; case MetaExpansionToken_Identifier:{ - meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Reference, p->string, t, loc); + meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Reference, p->string, table, loc); }break; case MetaExpansionToken_TypeEval: @@ -2299,7 +2478,7 @@ meta_generate_expansion_set(MetaContext *ctx, Arena *arena, s8 expansion_string, MetaExpansionPartKind kind = token == MetaExpansionToken_TypeEval ? MetaExpansionPartKind_EvalKind : MetaExpansionPartKind_EvalKindCount; - meta_push_expansion_part(ctx, arena, &result, kind, p->string, t, loc); + meta_push_expansion_part(ctx, arena, &result, kind, p->string, table, loc); }break; case MetaExpansionToken_Quote:{ @@ -2311,7 +2490,7 @@ meta_generate_expansion_set(MetaContext *ctx, Arena *arena, s8 expansion_string, /* TODO(rnp): point at start */ meta_compiler_error(loc, "unterminated string in expansion\n"); } - meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, string, t, loc); + meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, string, table, loc); }break; case MetaExpansionToken_Dash:{ @@ -2397,10 +2576,20 @@ meta_expand(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count, MetaE meta_entry_argument_expected(e, s8("table_name")); s8 table_name = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; - MetaTable *t = ctx->tables.data + meta_lookup_string_slow(ctx->table_names.data, - ctx->table_names.count, table_name); - if (t < ctx->tables.data) + MetaEntity *table = ctx->entities.data + meta_lookup_string_slow(ctx->entity_names.data, + ctx->entity_names.count, + table_name); + + if (table < ctx->entities.data) meta_entry_error(e, "undefined table %.*s\n", (i32)table_name.len, table_name.data); + if (!meta_entity_kind_is_table[table->kind]) { + s8 old_kind = meta_entity_kind_names[table->kind]; + s8 wanted_kind = meta_entity_kind_names[MetaEntityKind_Table]; + meta_entry_error(e, "%.*s previously defined as %.*s but should be %.*s\n", + (i32)table_name.len, table_name.data, + (i32)old_kind.len, old_kind.data, + (i32)wanted_kind.len, wanted_kind.data); + } MetaEntryScope scope = meta_entry_extract_scope(e, entry_count); for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) { @@ -2408,25 +2597,24 @@ meta_expand(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count, MetaE case MetaEntryKind_String:{ if (!ops) goto error; - MetaExpansionPartList parts = meta_generate_expansion_set(ctx, ctx->arena, row->name, t, row->location); + MetaExpansionPartList parts = meta_generate_expansion_set(ctx, ctx->arena, row->name, table, row->location); MetaEmitOperation *op = da_push(ctx->arena, ops); op->kind = MetaEmitOperationKind_Expand; op->location = row->location; - op->expansion_operation.parts = parts.data; - op->expansion_operation.part_count = (u32)parts.count; - op->expansion_operation.table_id = (u32)da_index(t, &ctx->tables); + op->expansion_operation.parts = parts.data; + 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("kind"), s8("`raw_string`")); - s8 kind = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_String).string; - s8 expand = meta_entry_argument_expect(row, 1, MetaEntryArgumentKind_String).string; + 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, t, row->location); - s8 *variations = push_array(&scratch, s8, t->entry_count); - for (u32 expansion = 0; expansion < t->entry_count; expansion++) { + 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; @@ -2436,7 +2624,7 @@ meta_expand(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count, MetaE } variations[expansion] = arena_stream_commit(ctx->arena, &sb); } - meta_extend_enumeration(ctx, kind, variations, t->entry_count); + meta_direct_enumeration(ctx, row->name, variations, table->table.entry_count, e->location); }break; error: default: @@ -2503,6 +2691,32 @@ meta_map_emit_lang(s8 lang, MetaEntry *e) return result; } +function void +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); + + meta_entry_argument_expected(e, s8("value")); + s8 value = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; + + NumberConversion number = number_from_s8(value); + if (number.result != NumberConversionResult_Success || number.unparsed.len != 0) { + meta_compiler_error(e->location, "Invalid integer in definition of Constant '%.*s': %.*s\n", + (i32)e->name.len, e->name.data, (i32)value.len, value.data); + } + + MetaEntity *entity = meta_entity(ctx, entity_id); + if (number.kind == NumberConversionKind_Float) { + entity->constant.kind = MetaConstantKind_Float; + entity->constant.F64 = number.F64; + } else { + entity->constant.kind = MetaConstantKind_Integer; + entity->constant.U64 = number.U64; + } +} + function iz meta_pack_emit(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count) { @@ -2561,27 +2775,6 @@ meta_pack_munion(MetaContext *ctx, MetaEntry *e, iz entry_count) mu->sub_table_count = (u32)sub_tables.count; } -function iz -meta_pack_table(MetaContext *ctx, MetaEntry *e, iz entry_count) -{ - assert(e->kind == MetaEntryKind_Table); - - MetaTable *t = da_push(ctx->arena, &ctx->tables); - iz table_name_id = meta_lookup_string_slow(ctx->table_names.data, ctx->table_names.count, e->name); - if (table_name_id >= 0) meta_entry_error(e, "table redefined\n"); - - s8 *t_name = da_push(ctx->arena, &ctx->table_names); - t->table_name_id = (u32)da_index(t_name, &ctx->table_names); - *t_name = e->name; - - meta_entry_argument_expected(e, s8("[field ...]")); - MetaEntryArgument fields = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_Array); - t->fields = fields.strings; - t->field_count = (u32)fields.count; - - return meta_fill_table(ctx, e, entry_count, t); -} - function CommandList meta_extract_emit_file_dependencies(MetaContext *ctx, Arena *arena) { @@ -2663,8 +2856,8 @@ meta_expansion_part_conditional_argument(MetaExpansionConditionalArgument a, u32 case MetaExpansionConditionalArgumentKind_Reference:{ s8 string = a.strings[entry]; - IntegerConversion integer = integer_from_s8(string); - if (integer.result != IntegerConversionResult_Success) { + NumberConversion integer = integer_from_s8(string); + if (integer.result != NumberConversionResult_Success) { meta_compiler_error(loc, "Invalid integer in '%.*s' table expansion: %.*s\n", (i32)table_name.len, table_name.data, (i32)string.len, string.data); } @@ -2693,8 +2886,7 @@ meta_expansion_part_conditional(MetaExpansionPart *p, u32 entry, s8 table_name, } function void -metagen_run_emit(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationList *ops, - MetaTableList *tables, s8 *evaluation_table) +metagen_run_emit(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationList *ops, s8 *evaluation_table) { for (iz opcode = 0; opcode < ops->count; opcode++) { MetaEmitOperation *op = ops->data + opcode; @@ -2712,10 +2904,8 @@ metagen_run_emit(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationList Arena scratch = m->scratch; MetaEmitOperationExpansion *eop = &op->expansion_operation; - MetaTable *t = tables->data + eop->table_id; - // TODO(rnp): table_names should be stored with the in the table list - s8 table_name = eop->table_id < ctx->table_names.count ? ctx->table_names.data[t->table_name_id] - : s8("(Unamed Table)"); + MetaTable *t = &ctx->entities.data[eop->table_entity_id].table; + s8 table_name = ctx->entity_names.data[eop->table_entity_id]; u32 alignment_count = 1; u32 evaluation_count = 0; @@ -2798,7 +2988,7 @@ metagen_run_emit_set(MetaprogramContext *m, MetaContext *ctx, MetaEmitOperationL { for (iz set = 0; set < emit_set->count; set++) { MetaEmitOperationList *ops = emit_set->data + set; - metagen_run_emit(m, ctx, ops, &ctx->tables, evaluation_table); + metagen_run_emit(m, ctx, ops, evaluation_table); } } @@ -2819,6 +3009,23 @@ metagen_push_counted_enum_body(MetaprogramContext *m, s8 kind, s8 prefix, s8 mid } function void +metagen_push_counted_enum_body_from_ids(MetaprogramContext *m, s8 kind, s8 prefix, s8 mid, s8 suffix, + da_count *ids, s8 *id_names, da_count ids_count) +{ + i64 max_id_length = 0; + for (i64 id = 0; id < ids_count; id++) + max_id_length = Max(max_id_length, id_names[ids[id]].len); + + for (i64 id = 0; id < ids_count; id++) { + meta_begin_line(m, prefix, kind, id_names[ids[id]]); + meta_pad(m, ' ', 1 + (i32)(max_id_length - id_names[ids[id]].len)); + meta_push(m, mid); + meta_push_i64(m, id); + meta_end_line(m, suffix); + } +} + +function void metagen_push_c_enum(MetaprogramContext *m, Arena scratch, s8 kind, s8 *ids, iz ids_count) { s8 kind_full = push_s8_from_parts(&scratch, s8(""), kind, s8("_")); @@ -2829,12 +3036,29 @@ metagen_push_c_enum(MetaprogramContext *m, Arena scratch, s8 kind, s8 *ids, iz i } function void -metagen_push_c_flag_enum(MetaprogramContext *m, Arena scratch, s8 kind, s8 *ids, iz ids_count) +metagen_push_struct_body(MetaprogramContext *m, MetaTable *s, s8 *types, s8 *members, s8 *elements, + s8 prefix, s8 suffix, s8 str_elements_prefix) { - s8 kind_full = push_s8_from_parts(&scratch, s8(""), kind, s8("_")); - meta_begin_scope(m, s8("typedef enum {")); - metagen_push_counted_enum_body(m, kind_full, s8(""), s8("= (1 << "), s8("),"), ids, ids_count); - meta_end_scope(m, s8("} "), kind, s8(";\n")); + 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); + } + + 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("]")); + } + meta_end_line(m, s8(";"), suffix); + } } function void @@ -2842,134 +3066,146 @@ meta_push_shader_reload_info(MetaprogramContext *m, MetaContext *ctx) { /////////////////////////////// // NOTE(rnp): reloadable infos - meta_begin_scope(m, s8("read_only global BeamformerShaderKind beamformer_reloadable_shader_kinds[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - meta_push_line(m, s8("BeamformerShaderKind_"), ctx->shader_names.data[s->name_id], s8(",")); - } - meta_end_scope(m, s8("};\n")); + meta_begin_scope(m, s8("read_only global " META_NAMESPACE_UPPER "ShaderKind " META_NAMESPACE_LOWER "_reloadable_shader_kinds[] = {")); + { + for (da_count shader = 0; shader < ctx->base_shader_count; shader++) { + da_count id = ctx->base_shader_ids[shader]; + meta_push_line(m, s8(META_NAMESPACE_UPPER "ShaderKind_"), ctx->entity_names.data[id], s8(",")); + } + } meta_end_scope(m, s8("};\n")); - meta_begin_scope(m, s8("read_only global s8 beamformer_reloadable_shader_files[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - meta_push_line(m, s8("s8_comp(\""), ctx->base_shaders.data[shader].file, s8("\"),")); - } - meta_end_scope(m, s8("};\n")); + meta_begin_scope(m, s8("read_only global s8 " META_NAMESPACE_LOWER "_reloadable_shader_files[] = {")); + { + for (da_count shader = 0; shader < ctx->base_shader_count; shader++) { + da_count id = ctx->base_shader_ids[shader]; + MetaShader *s = &ctx->entities.data[id].shader; + meta_push_line(m, s8("s8_comp(\""), s->file, s8("\"),")); + } + } meta_end_scope(m, s8("};\n")); + meta_begin_scope(m, s8("read_only global i32 " META_NAMESPACE_LOWER "_shader_reloadable_index_by_shader[] = {")); { - meta_begin_scope(m, s8("read_only global i32 beamformer_shader_reloadable_index_by_shader[] = {")); - for (iz shader = 0; shader < ctx->shaders.count; shader++) { + for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { meta_indent(m); - meta_push_i64(m, ctx->shaders.data[shader].base_shader_id); + meta_push_i64(m, ctx->base_shader_id_map[shader]); meta_end_line(m, s8(",")); } - meta_end_scope(m, s8("};\n")); - } + } meta_end_scope(m, s8("};\n")); { u32 info_index = 0; - for (iz group = 0; group < ctx->shader_groups.count; group++) { - MetaShaderGroup *sg = ctx->shader_groups.data + group; - meta_begin_line(m, s8("read_only global i32 beamformer_reloadable")); - for (iz i = 0; i < sg->name.len; i++) { - if IsUpper(sg->name.data[i]) + for (da_count group = 0; group < ctx->entity_kind_counts[MetaEntityKind_ShaderGroup]; group++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_ShaderGroup][group]; + s8 name = ctx->entity_names.data[id]; + meta_begin_line(m, s8("read_only global i32 " META_NAMESPACE_LOWER "_reloadable")); + for (i64 i = 0; i < name.len; i++) { + if IsUpper(name.data[i]) stream_append_byte(&m->stream, '_'); - stream_append_byte(&m->stream, ToLower(sg->name.data[i])); + stream_append_byte(&m->stream, ToLower(name.data[i])); } - meta_begin_scope(m, s8("_shader_info_indices[] = {")); - - for (iz shader = 0; shader < sg->shaders.count; shader++) { - MetaShader *s = ctx->shaders.data + sg->shaders.data[shader]; - /* TODO(rnp): store base shader list in a better format */ - for (iz base_shader = 0; base_shader < ctx->base_shaders.count; base_shader++) { - MetaBaseShader *bs = ctx->base_shaders.data + base_shader; - if (bs->shader == s) { - meta_indent(m); - meta_push_u64(m, info_index++); - meta_end_line(m, s8(",")); - break; + + meta_begin_scope(m, s8("_shader_info_indices[] = {")); { + MetaEntityID child = ctx->entities.data[id].first_child; + do { + /* TODO(rnp): store base shader list in a better format */ + for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { + if (ctx->base_shader_ids[bs] == child.value) { + meta_indent(m); + meta_push_u64(m, info_index++); + meta_end_line(m, s8(",")); + break; + } } - } - } - meta_end_scope(m, s8("};\n")); + child = ctx->entities.data[child.value].next_sibling; + } while (child.value != ctx->entities.data[id].first_child.value); + } meta_end_scope(m, s8("};\n")); } } //////////////////////////////////// // NOTE(rnp): shader header strings - meta_begin_scope(m, s8("read_only global s8 beamformer_shader_global_header_strings[] = {")); - for (iz ref = 0; ref < ctx->shader_enumerations.count; ref++) { - u32 kind = ctx->shader_enumerations.data[ref]; - s8_list *sub_list = ctx->enumeration_members.data + kind; - s8 kind_name = push_s8_from_parts(&m->scratch, s8(""), ctx->enumeration_kinds.data[kind], s8("_")); - meta_push_line(m, s8("s8_comp(\"\"")); - metagen_push_counted_enum_body(m, kind_name, s8("\"#define "), s8(""), s8("\\n\""), - sub_list->data, sub_list->count); - meta_push_line(m, s8("\"\\n\"),")); - m->scratch = ctx->scratch; - } - meta_end_scope(m, s8("};\n")); + meta_begin_scope(m, s8("read_only global s8 " META_NAMESPACE_LOWER "_shader_global_header_strings[] = {")); + { + for (da_count ref = 0; ref < ctx->shader_entity_references.count; ref++) { + da_count entity_id = ctx->shader_entity_references.data[ref]; + s8 entity_name = ctx->entity_names.data[entity_id]; + MetaEntity *e = ctx->entities.data + entity_id; - meta_begin_scope(m, s8("read_only global s8 *beamformer_shader_flag_strings[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - s8_list *flag_list = ctx->flags_for_shader.data + s->flag_list_id; + switch (e->kind) { - if (flag_list->count) { - meta_begin_scope(m, s8("(s8 []){")); - for (iz flag = 0; flag < flag_list->count; flag++) - meta_push_line(m, s8("s8_comp(\""), flag_list->data[flag], s8("\"),")); - meta_end_scope(m, s8("},")); - } else { - meta_push_line(m, s8("0,")); - } - } - meta_end_scope(m, s8("};\n")); + case MetaEntityKind_Constant:{ + meta_begin_line(m, s8("s8_comp(\"#define "), entity_name, s8(" (")); + switch(e->constant.kind) { + case MetaConstantKind_Integer:{ meta_push_u64(m, e->constant.U64); }break; + case MetaConstantKind_Float:{ meta_push_f64(m, e->constant.F64); }break; + InvalidDefaultCase; + } + meta_end_line(m, s8(")\\n\\n\"),")); + }break; - meta_begin_scope(m, s8("read_only global u8 beamformer_shader_flag_strings_count[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - u64 count = (u64)ctx->flags_for_shader.data[s->flag_list_id].count; + 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_line(m, s8("\"};\\n\"")); + meta_push_line(m, s8("\"\\n\"),")); + }break; - meta_indent(m); - meta_push_u64(m, count); - meta_end_line(m, s8(",")); - } - meta_end_scope(m, s8("};\n")); + 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_line(m, s8("\"};\\n\"")); + meta_push_line(m, s8("\"\\n\"),")); + }break; + + case MetaEntityKind_Enumeration:{ + s8 kind_name = push_s8_from_parts(&m->scratch, s8(""), entity_name, s8("_")); + meta_push_line(m, s8("s8_comp(\"\"")); + metagen_push_counted_enum_body(m, kind_name, s8("\"#define "), s8(""), s8("\\n\""), + e->table.entries[0], e->table.entry_count); + meta_push_line(m, s8("\"\\n\"),")); + }break; + + InvalidDefaultCase; + } + + m->scratch = ctx->scratch; + } + } meta_end_scope(m, s8("};\n")); } function void meta_push_shader_bake(MetaprogramContext *m, MetaContext *ctx) { - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaBaseShader *bs = ctx->base_shaders.data + shader; - MetaShader *s = bs->shader; + for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { + MetaShader *s = &ctx->entities.data[ctx->base_shader_ids[bs]].shader; - s8 shader_name = ctx->shader_names.data[s->name_id]; + s8 shader_name = ctx->entity_names.data[ctx->base_shader_ids[bs]]; - meta_begin_line(m, s8("read_only global u8 beamformer_shader_")); - for (iz i = 0; i < shader_name.len; i++) + meta_begin_line(m, s8("read_only global u8 " META_NAMESPACE_LOWER "_shader_")); + for (i64 i = 0; i < shader_name.len; i++) stream_append_byte(&m->stream, ToLower(shader_name.data[i])); meta_begin_scope(m, s8("_bytes[] = {")); { Arena scratch = m->scratch; - s8 filename = push_s8_from_parts(&scratch, s8(OS_PATH_SEPARATOR), s8("shaders"), bs->file); + s8 filename = push_s8_from_parts(&scratch, s8(OS_PATH_SEPARATOR), s8("shaders"), s->file); s8 file = read_entire_file((c8 *)filename.data, &scratch); metagen_push_byte_array(m, file); } meta_end_scope(m, s8("};\n")); } - meta_begin_scope(m, s8("read_only global s8 beamformer_shader_data[] = {")); { - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaBaseShader *bs = ctx->base_shaders.data + shader; - MetaShader *s = bs->shader; + meta_begin_scope(m, s8("read_only global s8 " META_NAMESPACE_LOWER "_shader_data[] = {")); { + for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { + s8 shader_name = ctx->entity_names.data[ctx->base_shader_ids[bs]]; - s8 shader_name = ctx->shader_names.data[s->name_id]; - - meta_begin_line(m, s8("{.data = beamformer_shader_")); + meta_begin_line(m, s8("{.data = " META_NAMESPACE_LOWER "_shader_")); for (iz i = 0; i < shader_name.len; i++) stream_append_byte(&m->stream, ToLower(shader_name.data[i])); - meta_push(m, s8("_bytes, .len = countof(beamformer_shader_")); + meta_push(m, s8("_bytes, .len = countof(" META_NAMESPACE_LOWER "_shader_")); for (iz i = 0; i < shader_name.len; i++) stream_append_byte(&m->stream, ToLower(shader_name.data[i])); meta_end_line(m, s8("_bytes)},")); @@ -3004,11 +3240,11 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) // NOTE(rnp): shader baking { char *out_shaders = "generated" OS_PATH_SEPARATOR "beamformer_shaders.c"; - char **deps = push_array(&m->scratch, char *, 2 * ctx->base_shaders.count); + char **deps = push_array(&m->scratch, char *, 2 * ctx->base_shader_count); u32 dep_count = 0; - for (iz i = 0; i < ctx->base_shaders.count; i++) { - MetaBaseShader *b = ctx->base_shaders.data + i; - deps[dep_count++] = (c8 *)push_s8_from_parts(&m->scratch, s8(OS_PATH_SEPARATOR), s8("shaders"), b->file).data; + for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { + MetaShader *s = &ctx->entities.data[ctx->base_shader_ids[bs]].shader; + deps[dep_count++] = (c8 *)push_s8_from_parts(&m->scratch, s8(OS_PATH_SEPARATOR), s8("shaders"), s->file).data; } if (needs_rebuild_(out_shaders, deps, dep_count)) { build_log_generate("Bake Shaders"); @@ -3027,55 +3263,109 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) meta_push(m, c_file_header); ///////////////////////// - // NOTE(rnp): enumerants - for (iz kind = 0; kind < ctx->enumeration_kinds.count; kind++) { - s8 enum_name = push_s8_from_parts(&m->scratch, s8(""), s8("Beamformer"), ctx->enumeration_kinds.data[kind]); - metagen_push_c_enum(m, m->scratch, enum_name, ctx->enumeration_members.data[kind].data, - ctx->enumeration_members.data[kind].count); + // NOTE(rnp): constants + { + u32 integers = 0; + u32 floats = 0; + + for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; + MetaEntity *e = ctx->entities.data + id; + if (e->constant.kind == MetaConstantKind_Integer) integers++; + if (e->constant.kind == MetaConstantKind_Float) floats++; + } + + u32 row_alloc_count = Max(integers, floats); + s8 *columns[2]; + columns[0] = push_array(&m->scratch, s8, row_alloc_count); + columns[1] = push_array(&m->scratch, s8, row_alloc_count); + + u32 row_count; + + row_count = 0; + meta_push_line(m, s8("// NOTE: Constants (Integer)")); + for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; + MetaEntity *e = ctx->entities.data + id; + if (e->constant.kind == MetaConstantKind_Integer) { + Stream sb = arena_stream(m->scratch); + stream_append_s8(&sb, s8("(")); + stream_append_u64(&sb, e->constant.U64); + columns[0][row_count] = ctx->entity_names.data[id]; + columns[1][row_count] = arena_stream_commit(&m->scratch, &sb); + row_count++; + } + } + metagen_push_table(m, m->scratch, s8("#define " META_NAMESPACE_UPPER), s8(")"), columns, row_count, 2); + + row_count = 0; + meta_push_line(m, s8("\n// NOTE: Constants (Float)")); + for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; + MetaEntity *e = ctx->entities.data + id; + if (e->constant.kind == MetaConstantKind_Float) { + Stream sb = arena_stream(m->scratch); + stream_append_s8(&sb, s8("(")); + stream_append_f64(&sb, e->constant.F64, 1000000); + columns[0][row_count] = ctx->entity_names.data[id]; + columns[1][row_count] = arena_stream_commit(&m->scratch, &sb); + row_count++; + } + } + metagen_push_table(m, m->scratch, s8("#define " META_NAMESPACE_UPPER), s8(")"), columns, row_count, 2); + m->scratch = ctx->scratch; } + meta_push(m, s8("\n")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - s8_list *flag_list = ctx->flags_for_shader.data + s->flag_list_id; - if (flag_list->count) { - s8 enum_name = push_s8_from_parts(&m->scratch, s8(""), s8("BeamformerShader"), - ctx->shader_names.data[s->name_id], s8("Flags")); - metagen_push_c_flag_enum(m, m->scratch, enum_name, flag_list->data, flag_list->count); - m->scratch = ctx->scratch; - } + ///////////////////////// + // 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; + + s8 enum_name = push_s8_from_parts(&m->scratch, s8(""), s8(META_NAMESPACE_UPPER), + ctx->entity_names.data[id]); + metagen_push_c_enum(m, m->scratch, enum_name, e->table.entries[0], e->table.entry_count); + m->scratch = ctx->scratch; } { - s8 kind = s8("BeamformerShaderKind"); - s8 kind_full = s8("BeamformerShaderKind_"); + s8 kind = s8(META_NAMESPACE_UPPER "ShaderKind"); + s8 kind_full = s8(META_NAMESPACE_UPPER "ShaderKind_"); meta_begin_scope(m, s8("typedef enum {")); - metagen_push_counted_enum_body(m, kind_full, s8(""), s8("= "), s8(","), - ctx->shader_names.data, ctx->shader_names.count); + metagen_push_counted_enum_body_from_ids(m, kind_full, s8(""), s8("= "), s8(","), + ctx->entity_kind_ids[MetaEntityKind_Shader], ctx->entity_names.data, + ctx->entity_kind_counts[MetaEntityKind_Shader]); meta_push_line(m, kind_full, s8("Count,\n")); s8 *columns[2]; - columns[0] = push_array(&m->scratch, s8, ctx->shader_groups.count * 3); - columns[1] = push_array(&m->scratch, s8, ctx->shader_groups.count * 3); + columns[0] = push_array(&m->scratch, s8, ctx->entity_kind_counts[MetaEntityKind_ShaderGroup] * 3); + columns[1] = push_array(&m->scratch, s8, ctx->entity_kind_counts[MetaEntityKind_ShaderGroup] * 3); u32 rows = 0; - for (iz group = 0; group < ctx->shader_groups.count; group++) { - MetaShaderGroup *sg = ctx->shader_groups.data + group; + for (da_count group = 0; group < ctx->entity_kind_counts[MetaEntityKind_ShaderGroup]; group++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_ShaderGroup][group]; + MetaEntityID child = ctx->entities.data[id].first_child; + s8 name = ctx->entity_names.data[id]; - if (sg->shaders.count > 0) { - s8 first_name = ctx->shader_names.data[ctx->shaders.data[sg->shaders.data[0]].name_id]; - s8 last_name = ctx->shader_names.data[ctx->shaders.data[sg->shaders.data[sg->shaders.count - 1]].name_id]; + da_count shader_count = meta_entity_children_count(ctx, (MetaEntityID){.value = id}); - columns[0][3 * group + 0] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), sg->name, s8("First")); + if (child.value != 0) { + // NOTE(rnp): childen pushed in LIFO order + s8 first_name = ctx->entity_names.data[ctx->entities.data[child.value].previous_sibling.value]; + s8 last_name = ctx->entity_names.data[child.value]; + + columns[0][3 * group + 0] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), name, s8("First")); columns[1][3 * group + 0] = push_s8_from_parts(&m->scratch, s8(""), s8("= "), kind, s8("_"), first_name); - columns[0][3 * group + 1] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), sg->name, s8("Last")); + columns[0][3 * group + 1] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), name, s8("Last")); columns[1][3 * group + 1] = push_s8_from_parts(&m->scratch, s8(""),s8("= "), kind, s8("_"), last_name); - columns[0][3 * group + 2] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), sg->name, s8("Count")); + columns[0][3 * group + 2] = push_s8_from_parts(&m->scratch, s8(""), kind, s8("_"), name, s8("Count")); Stream sb = arena_stream(m->scratch); stream_append_s8(&sb, s8("= ")); - stream_append_u64(&sb, (u64)sg->shaders.count); + stream_append_i64(&sb, shader_count); columns[1][3 * group + 2] = arena_stream_commit(&m->scratch, &sb); rows += 3; @@ -3089,204 +3379,142 @@ metagen_emit_c_code(MetaContext *ctx, Arena arena) ////////////////////// // NOTE(rnp): structs - for (u32 bake = 0; bake < ctx->shader_bake_parameters.count; bake++) { - Arena tmp = m->scratch; - - // NOTE: Bake Parameters - MetaShaderBakeParameters *b = ctx->shader_bake_parameters.data + bake; - MetaShader *s = ctx->shaders.data + b->shader_id; - s8 name = push_s8_from_parts(&m->scratch, s8(""), s8("BeamformerShader"), - ctx->shader_names.data[s->name_id], s8("BakeParameters")); - meta_begin_scope(m, s8("typedef struct {")); - for (u32 entry = 0; entry < b->entry_count; entry++) { - s8 kind = (b->floating_point & (1 << entry))? s8("f32 ") : s8("u32 "); - meta_push_line(m, kind, b->names_lower[entry], s8(";")); + { + 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")); } - meta_end_scope(m, s8("} "), name, s8(";\n")); - m->scratch = tmp; - } - - - for (iz base_shader = 0; base_shader < ctx->base_shaders.count; base_shader++) { - Arena tmp = m->scratch; - - // NOTE: Push Constants - MetaShader *s = ctx->base_shaders.data[base_shader].shader; - if (s->push_constants_id != (u32)-1) { - MetaEmitOperationList ops[1] = {0}; - MetaTable *pc = ctx->push_constant_tables.data + s->push_constants_id; - - MetaEmitOperation *op = da_push(&m->scratch, ops); - op->kind = MetaEmitOperationKind_String; - op->string = s8("typedef struct {"); - - s8 expr = s8(" $(%type)$(|)$(name);"); - - MetaExpansionPartList parts = meta_generate_expansion_set(ctx, &m->scratch, expr, pc, META_CURRENT_LOCATION); - op = da_push(&m->scratch, ops); - op->kind = MetaEmitOperationKind_Expand; - op->expansion_operation.parts = parts.data; - op->expansion_operation.part_count = (u32)parts.count; - op->expansion_operation.table_id = s->push_constants_id; - - op = da_push(&m->scratch, ops); - op->kind = MetaEmitOperationKind_String; - op->string = push_s8_from_parts(&m->scratch, s8(""), s8("} BeamformerShader"), - ctx->shader_names.data[s->name_id], s8("PushConstants;")); - - metagen_run_emit(m, ctx, ops, &ctx->push_constant_tables, meta_kind_c_types); } - - m->scratch = tmp; } - // shader bake parameter struct - meta_begin_scope(m, s8("typedef struct {")); + // NOTE: shader bake parameter union + meta_begin_scope(m, s8("typedef union {")); { - meta_begin_scope(m, s8("union {")); + Arena scratch; + DeferLoop(scratch = m->scratch, m->scratch = scratch) { - Arena tmp = m->scratch; s8 *columns[2]; - columns[0] = push_array(&m->scratch, s8, ctx->shader_bake_parameters.count); - columns[1] = push_array(&m->scratch, s8, ctx->shader_bake_parameters.count); - for (u32 bake = 0; bake < ctx->shader_bake_parameters.count; bake++) { - MetaShaderBakeParameters *b = ctx->shader_bake_parameters.data + bake; - MetaShader *s = ctx->shaders.data + b->shader_id; - columns[0][bake] = push_s8_from_parts(&m->scratch, s8(""), s8("BeamformerShader"), - ctx->shader_names.data[s->name_id], s8("BakeParameters")); - columns[1][bake] = ctx->shader_names.data[s->name_id]; + columns[0] = push_array(&m->scratch, s8, ctx->entity_kind_counts[MetaEntityKind_BakeParameters]); + columns[1] = push_array(&m->scratch, s8, ctx->entity_kind_counts[MetaEntityKind_BakeParameters]); + + for (da_count bake = 0; bake < ctx->entity_kind_counts[MetaEntityKind_BakeParameters]; bake++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_BakeParameters][bake]; + + s8 bake_name = ctx->entity_names.data[id]; + s8 shader_name = {.data = bake_name.data, .len = bake_name.len - s8("BakeParameters").len}; + + 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, - (uz)ctx->shader_bake_parameters.count, 2); - m->scratch = tmp; - } meta_end_scope(m, s8("};")); - s8 names[] = {s8("data_kind"), s8("flags")}; - s8 types[] = {s8("u32"), s8("u32")}; - metagen_push_table(m, m->scratch, s8(""), s8(";"), (s8 *[]){types, names}, countof(names), 2); - } meta_end_scope(m, s8("} BeamformerShaderBakeParameters;\n")); + 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); ///////////////////////////////// // NOTE(rnp): shader info tables - meta_begin_scope(m, s8("read_only global s8 beamformer_shader_names[] = {")); - metagen_push_table(m, m->scratch, s8("s8_comp(\""), s8("\"),"), &ctx->shader_names.data, - (uz)ctx->shader_names.count, 1); - meta_end_scope(m, s8("};\n")); + meta_begin_scope(m, s8("read_only global s8 " META_NAMESPACE_LOWER "_shader_names[] = {")); + for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; + meta_push_line(m, s8("s8_comp(\""), ctx->entity_names.data[id], s8("\"),")); + } meta_end_scope(m, s8("};\n")); meta_push_shader_reload_info(m, ctx); - meta_begin_scope(m, s8("read_only global i32 *beamformer_shader_header_vectors[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - if (s->shader_enumeration_ids.count) { - meta_begin_line(m, s8("(i32 []){")); - for (iz id = 0; id < s->shader_enumeration_ids.count; id++) { - if (id != 0) meta_push(m, s8(", ")); - meta_push_u64(m, s->shader_enumeration_ids.data[id]); + meta_begin_scope(m, s8("read_only global i32 *" META_NAMESPACE_LOWER "_shader_header_vectors[] = {")); + { + for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { + da_count id = ctx->base_shader_ids[bs]; + MetaShader *s = &ctx->entities.data[id].shader; + if (s->entity_reference_ids.count) { + meta_begin_line(m, s8("(i32 []){")); + for (da_count ref_id = 0; ref_id < s->entity_reference_ids.count; ref_id++) { + if (ref_id != 0) meta_push(m, s8(", ")); + MetaEntityReference *r = &ctx->entities.data[s->entity_reference_ids.data[ref_id]].reference; + meta_push_i64(m, meta_lookup_id_slow(ctx->shader_entity_references.data, + ctx->shader_entity_references.count, + r->resolved_id.value)); + } + meta_end_line(m, s8("},")); + } else { + meta_push_line(m, s8("0,")); } - meta_end_line(m, s8("},")); - } else { - meta_push_line(m, s8("0,")); - } - } - meta_end_scope(m, s8("};\n")); - - meta_begin_scope(m, s8("read_only global i32 beamformer_shader_header_vector_lengths[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - meta_indent(m); - meta_push_u64(m, (u64)s->shader_enumeration_ids.count); - meta_end_line(m, s8(",")); - } - meta_end_scope(m, s8("};\n")); - - meta_begin_scope(m, s8("read_only global s8 *beamformer_shader_bake_parameter_names[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - if (s->bake_parameters) { - metagen_emit_c_s8_list(m, s->bake_parameters->names_upper, s->bake_parameters->entry_count); - } else { - meta_push_line(m, s8("0,")); } - } - meta_end_scope(m, s8("};\n")); - - meta_begin_scope(m, s8("read_only global u32 beamformer_shader_bake_parameter_float_bits[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - u32 hex = 0; - if (s->bake_parameters) - hex = s->bake_parameters->floating_point; - meta_begin_line(m, s8("0x")); - meta_push_u64_hex_width(m, hex, 8); - meta_end_line(m, s8("UL,")); - } - meta_end_scope(m, s8("};\n")); + } meta_end_scope(m, s8("};\n")); - meta_begin_scope(m, s8("read_only global i32 beamformer_shader_bake_parameter_counts[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - if (s->bake_parameters) { + meta_begin_scope(m, s8("read_only global i32 " META_NAMESPACE_LOWER "_shader_header_vector_lengths[] = {")); + { + for (da_count bs= 0; bs < ctx->base_shader_count; bs++) { + da_count id = ctx->base_shader_ids[bs]; + MetaShader *s = &ctx->entities.data[id].shader; meta_indent(m); - meta_push_u64(m, s->bake_parameters->entry_count); + meta_push_i64(m, s->entity_reference_ids.count); meta_end_line(m, s8(",")); - } else { - meta_push_line(m, s8("0,")); } - } - meta_end_scope(m, s8("};\n")); + } meta_end_scope(m, s8("};\n")); - meta_begin_scope(m, s8("read_only global s8 *beamformer_shader_push_constant_glsl_types[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - if (s->push_constants_id != (u32)-1) { - MetaTable *pc = ctx->push_constant_tables.data + s->push_constants_id; - iz field = meta_lookup_string_slow(pc->fields, pc->field_count, s8("glsl_type")); - metagen_emit_c_s8_list(m, pc->entries[field], pc->entry_count); - } else { - meta_push_line(m, s8("0,")); + meta_begin_scope(m, s8("read_only global s8 *" META_NAMESPACE_LOWER "_shader_bake_parameter_names[] = {")); + { + for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { + da_count id = ctx->base_shader_ids[bs]; + MetaEntity *e = ctx->entities.data + id; + MetaEntityID bp_id = meta_entity_first_child_of_kind(ctx, e, MetaEntityKind_BakeParameters); + if (bp_id.value != 0) { + MetaEntity *bp = meta_entity(ctx, bp_id); + metagen_emit_c_s8_list(m, bp->table.entries[MetaBakeField_NameUpper], bp->table.entry_count); + } else { + meta_push_line(m, s8("0,")); + } } - } - meta_end_scope(m, s8("};\n")); + } meta_end_scope(m, s8("};\n")); - meta_begin_scope(m, s8("read_only global s8 *beamformer_shader_push_constant_names[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - if (s->push_constants_id != (u32)-1) { - MetaTable *pc = ctx->push_constant_tables.data + s->push_constants_id; - iz field = meta_lookup_string_slow(pc->fields, pc->field_count, s8("name")); - metagen_emit_c_s8_list(m, pc->entries[field], pc->entry_count); - } else { - meta_push_line(m, s8("0,")); + meta_begin_scope(m, s8("read_only global u32 " META_NAMESPACE_LOWER "_shader_bake_parameter_float_bits[] = {")); + { + for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { + da_count id = ctx->base_shader_ids[bs]; + MetaEntity *e = ctx->entities.data + id; + 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; + } + meta_begin_line(m, s8("0x")); + meta_push_u64_hex_width(m, hex, 8); + meta_end_line(m, s8("UL,")); } - } - meta_end_scope(m, s8("};\n")); + } meta_end_scope(m, s8("};\n")); - meta_begin_scope(m, s8("read_only global u8 beamformer_shader_push_constant_counts[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - if (s->push_constants_id != (u32)-1) { + meta_begin_scope(m, s8("read_only global u8 " META_NAMESPACE_LOWER "_shader_bake_parameter_counts[] = {")); + { + for (da_count bs = 0; bs < ctx->base_shader_count; bs++) { + da_count id = ctx->base_shader_ids[bs]; + MetaEntity *e = ctx->entities.data + id; + MetaEntityID bp_id = meta_entity_first_child_of_kind(ctx, e, MetaEntityKind_BakeParameters); + u32 count = 0; + if (bp_id.value != 0) + count = ctx->entities.data[bp_id.value].table.entry_count; meta_indent(m); - meta_push_u64(m, ctx->push_constant_tables.data[s->push_constants_id].entry_count); + meta_push_u64(m, count); meta_end_line(m, s8(",")); - } else { - meta_push_line(m, s8("0,")); } - } - meta_end_scope(m, s8("};\n")); - - meta_begin_scope(m, s8("read_only global u8 beamformer_shader_push_constant_sizes[] = {")); - for (iz shader = 0; shader < ctx->base_shaders.count; shader++) { - MetaShader *s = ctx->base_shaders.data[shader].shader; - if (s->push_constants_id != (u32)-1) { - meta_push_line(m, s8("sizeof(BeamformerShader"), ctx->shader_names.data[s->name_id], - s8("PushConstants),")); - } else { - meta_push_line(m, s8("0,")); - } - } - meta_end_scope(m, s8("};\n")); + } meta_end_scope(m, s8("};\n")); //fprintf(stderr, "%.*s\n", (i32)m.stream.widx, m.stream.data); @@ -3301,64 +3529,53 @@ metagen_matlab_union(MetaprogramContext *m, MetaContext *ctx, MetaMUnion *mu, s8 b32 result = 1; Arena scratch = m->scratch; - iz enumeration_id = meta_lookup_string_slow(ctx->enumeration_kinds.data, ctx->enumeration_kinds.count, - mu->enumeration_name); + 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); } - s8_list *enumeration_members = ctx->enumeration_members.data + enumeration_id; - if ((u32)enumeration_members->count != mu->sub_table_count) { + 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, - (u32)enumeration_members->count, mu->sub_table_count); + etable->entry_count, mu->sub_table_count); } - struct table_match { - MetaTable *table; - MetaKind *kinds; - u32 name_index; - } *table_matches; - - table_matches = push_array(&scratch, struct table_match, 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]; - MetaTable *t = ctx->tables.data + meta_lookup_string_slow(ctx->table_names.data, - ctx->table_names.count, sub_table_name); - if (t < ctx->tables.data) { - meta_compiler_error(mu->location, "Parameter Table '%.*s' requested by @MUnion not defined\n", - (i32)sub_table_name.len, sub_table_name.data); + 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; + } } - iz type_index = meta_lookup_string_slow(t->fields, t->field_count, s8("type")); - iz name_index = meta_lookup_string_slow(t->fields, t->field_count, s8("name")); - if (type_index < 0) { - meta_compiler_error_message(mu->location, "'%.*s' missing fields required by @MUnion: type\n", - (i32)sub_table_name.len, sub_table_name.data); - } - if (name_index < 0) { - meta_compiler_error_message(mu->location, "'%.*s' missing fields required by @MUnion: name\n", - (i32)sub_table_name.len, sub_table_name.data); + 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); } - if (type_index < 0 || name_index < 0) meta_error(); - table_matches[index].table = t; - table_matches[index].kinds = push_array(&scratch, MetaKind, t->entry_count); - table_matches[index].name_index = (u32)name_index; - - for (u32 entry = 0; entry < t->entry_count; entry++) { - table_matches[index].kinds[entry] = meta_map_kind(t->entries[type_index][entry], sub_table_name, - mu->location); - } + table_matches[index] = &ctx->entities.data[struct_id].table; } u32 max_parameter_size = 0; - for (iz member = 0; member < enumeration_members->count; member++) { + for (u32 member = 0; member < etable->entry_count; member++) { u32 parameter_size = 0; - for (u32 prop = 0; prop < table_matches[member].table->entry_count; prop++) - parameter_size += meta_kind_byte_sizes[table_matches[member].kinds[prop]]; - max_parameter_size = MAX(parameter_size, max_parameter_size); + 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; @@ -3388,21 +3605,19 @@ metagen_matlab_union(MetaprogramContext *m, MetaContext *ctx, MetaMUnion *mu, s8 result &= meta_end_and_write_matlab(m, (c8 *)outfile.data); scratch = scratch_temp; - for (iz member = 0; member < enumeration_members->count; member++) { - MetaTable *t = table_matches[member].table; - MetaKind *kinds = table_matches[member].kinds; + for (u32 member = 0; member < etable->entry_count; member++) { + MetaTable *t = table_matches[member]; - s8 sub_name = enumeration_members->data[member]; + 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(" < OGLBeamformer"), namespace, s8(".Base")); + meta_begin_scope(m, s8("classdef "), sub_name, s8(" < OGL" META_NAMESPACE_UPPER), namespace, s8(".Base")); { meta_begin_scope(m, s8("properties")); { - u32 name_index = table_matches[member].name_index; for (u32 prop = 0; prop < t->entry_count; prop++) { - meta_begin_line(m, t->entries[name_index][prop], s8("(1,")); - meta_push_u64(m, meta_kind_elements[kinds[prop]]); - meta_end_line(m, s8(") "), meta_kind_matlab_types[kinds[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_end_scope(m, s8("end")); } meta_end_scope(m, s8("end")); @@ -3452,35 +3667,52 @@ metagen_emit_matlab_code(MetaContext *ctx, Arena arena) meta_begin_matlab_class(m, "OGLBeamformerShaderStage", "int32"); meta_begin_scope(m, s8("enumeration")); { - iz index = -1; - for (iz group = 0; group < ctx->shader_groups.count; group++) { - if (s8_equal(ctx->shader_groups.data[group].name, s8("Compute"))) { - index = group; + da_count group_id = -1; + for (da_count group = 0; group < ctx->entity_kind_counts[MetaEntityKind_ShaderGroup]; group++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_ShaderGroup][group]; + s8 group_name = ctx->entity_names.data[id]; + if (s8_equal(group_name, s8("Compute"))) { + group_id = id; break; } } - if (index != -1) { - MetaShaderGroup *sg = ctx->shader_groups.data + index; - /* TODO(rnp): this assumes that the shaders are sequential */ - s8 *names = ctx->shader_names.data + ctx->shaders.data[0].name_id; - metagen_push_counted_enum_body(m, s8(""), s8(""), s8("("), s8(")"), names, sg->shaders.count); + if (group_id != -1) { + da_count children = meta_entity_children_count(ctx, (MetaEntityID){.value = group_id}); + 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; + } } else { build_log_failure("failed to find Compute shader group in meta info\n"); } - result &= index != -1; + result &= group_id != -1; } result &= meta_end_and_write_matlab(m, OUTPUT("matlab/OGLBeamformerShaderStage.m")); - for (iz kind = 0; kind < ctx->enumeration_kinds.count; kind++) { + for (da_count kind = 0; kind < ctx->entity_kind_counts[MetaEntityKind_Enumeration]; kind++) { Arena scratch = ctx->scratch; - s8 name = ctx->enumeration_kinds.data[kind]; + da_count id = ctx->entity_kind_ids[MetaEntityKind_Enumeration][kind]; + s8 name = ctx->entity_names.data[id]; s8 output = push_s8_from_parts(&scratch, s8(""), s8(OUTPUT("matlab/OGLBeamformer")), name, s8(".m")); - s8_list *kinds = ctx->enumeration_members.data + kind; + + MetaTable *etable = &ctx->entities.data[id].table; + s8 *kinds = etable->entries[0]; meta_begin_scope(m, s8("classdef OGLBeamformer"), name, s8(" < int32")); meta_begin_scope(m, s8("enumeration")); s8 prefix = s8(""); - if (kinds->count > 0 && IsDigit(kinds->data[0].data[0])) prefix = s8("m"); - metagen_push_counted_enum_body(m, s8(""), prefix, s8("("), s8(")"), kinds->data, kinds->count); + if (etable->entry_count > 0 && IsDigit(kinds[0].data[0])) prefix = s8("m"); + metagen_push_counted_enum_body(m, s8(""), prefix, s8("("), s8(")"), kinds, etable->entry_count); result &= meta_end_and_write_matlab(m, (c8 *)output.data); } @@ -3488,14 +3720,14 @@ metagen_emit_matlab_code(MetaContext *ctx, Arena arena) // NOTE: emit files { MetaEmitOperationListSet *emit_set = ctx->emit_sets + MetaEmitLang_MATLAB; - for (u32 list = 0; list < emit_set->count; list++) { + for (da_count list = 0; list < emit_set->count; list++) { MetaEmitOperationList *ops = emit_set->data + list; Arena scratch = m->scratch; s8 output = push_s8_from_parts(&m->scratch, s8(""), s8(OUTPUT("matlab") OS_PATH_SEPARATOR "OGLBeamformer"), ops->filename, s8(".m")); meta_push_line(m, s8("% GENERATED CODE")); - metagen_run_emit(m, ctx, ops, &ctx->tables, meta_kind_matlab_types); + metagen_run_emit(m, ctx, ops, meta_kind_matlab_types); result &= meta_write_and_reset(m, (c8 *)output.data); m->scratch = scratch; } @@ -3536,53 +3768,88 @@ metagen_emit_helper_library_header(MetaContext *ctx, Arena arena) meta_push_line(m, s8("#include <stdint.h>\n")); ///////////////////////// - // NOTE(rnp): enumarents - for (iz kind = 0; kind < ctx->enumeration_kinds.count; kind++) { - s8 enum_name = push_s8_from_parts(&m->scratch, s8(""), s8("Beamformer"), ctx->enumeration_kinds.data[kind]); - metagen_push_c_enum(m, m->scratch, enum_name, ctx->enumeration_members.data[kind].data, - ctx->enumeration_members.data[kind].count); + // NOTE(rnp): enumerents + { + u32 integers = 0; + for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; + MetaEntity *e = ctx->entities.data + id; + if (e->constant.kind == MetaConstantKind_Integer) integers++; + } + + s8 *columns[2]; + columns[0] = push_array(&m->scratch, s8, integers); + columns[1] = push_array(&m->scratch, s8, integers); + + u32 row_count = 0; + meta_push_line(m, s8("// NOTE: Constants (Integer)")); + for (da_count constant = 0; constant < ctx->entity_kind_counts[MetaEntityKind_Constant]; constant++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Constant][constant]; + MetaEntity *e = ctx->entities.data + id; + if (e->constant.kind == MetaConstantKind_Integer) { + Stream sb = arena_stream(m->scratch); + stream_append_s8(&sb, s8("(")); + stream_append_u64(&sb, e->constant.U64); + columns[0][row_count] = ctx->entity_names.data[id]; + columns[1][row_count] = arena_stream_commit(&m->scratch, &sb); + row_count++; + } + } + metagen_push_table(m, m->scratch, s8("#define " META_NAMESPACE_UPPER), s8(")"), columns, row_count, 2); + } + + ///////////////////////// + // NOTE(rnp): enumerents + 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; + + s8 enum_name = push_s8_from_parts(&m->scratch, s8(""), s8(META_NAMESPACE_UPPER), + ctx->entity_names.data[id]); + metagen_push_c_enum(m, m->scratch, enum_name, e->table.entries[0], e->table.entry_count); m->scratch = ctx->scratch; } { - iz index = -1; - for (iz group = 0; group < ctx->shader_groups.count; group++) { - if (s8_equal(ctx->shader_groups.data[group].name, s8("Compute"))) { - index = group; + da_count group_id = -1; + for (da_count group = 0; group < ctx->entity_kind_counts[MetaEntityKind_ShaderGroup]; group++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_ShaderGroup][group]; + s8 group_name = ctx->entity_names.data[id]; + if (s8_equal(group_name, s8("Compute"))) { + group_id = id; break; } } - if (index != -1) { - u64 offset = 0; - for (iz group = 0; group < index; group++) - offset += (u64)ctx->shader_groups.data[group].shaders.count; + if (group_id != -1) { + da_count children = meta_entity_children_count(ctx, (MetaEntityID){.value = group_id}); + if (children > 0) { + s8 kind = s8(META_NAMESPACE_UPPER "ShaderKind"); + s8 kind_full = s8(META_NAMESPACE_UPPER "ShaderKind_"); - MetaShaderGroup *sg = ctx->shader_groups.data + index; - s8 *columns[2]; - columns[0] = push_array(&m->scratch, s8, sg->shaders.count); - columns[1] = push_array(&m->scratch, s8, sg->shaders.count); + da_count *ids = push_array(&m->scratch, da_count, children); - Stream sb = arena_stream(m->scratch); - for (iz id = 0; id < sg->shaders.count; id++) { - stream_append_s8(&sb, s8("= ")); - stream_append_u64(&sb, offset + (u64)id); - - MetaShader *s = ctx->shaders.data + sg->shaders.data[id]; - columns[0][id] = ctx->shader_names.data[s->name_id]; - columns[1][id] = arena_stream_commit_and_reset(&m->scratch, &sb); - } + // 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_table(m, m->scratch, s8("BeamformerShaderKind_"), s8(","), columns, - (uz)sg->shaders.count, 2); - meta_end_scope(m, s8("} BeamformerShaderKind;\n")); + 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_end_scope(m, s8("} "), kind, s8(";\n")); - m->scratch = ctx->scratch; + m->scratch = ctx->scratch; - meta_begin_line(m, s8("#define BeamformerShaderKind_ComputeCount (")); - meta_push_u64(m, (u64)sg->shaders.count); - meta_end_line(m, s8(")\n")); + meta_begin_line(m, s8("#define "), kind_full, s8("ComputeCount (")); + meta_push_i64(m, children); + meta_end_line(m, s8(")\n")); + } } else { build_log_failure("failed to find Compute shader group in meta info\n"); } @@ -3616,6 +3883,10 @@ metagen_load_context(Arena *arena, char *filename) ctx->scratch = sub_arena(arena, MB(1), 16); ctx->arena = arena; + // NOTE(rnp): nil entity + *da_push(ctx->arena, &ctx->entity_names) = s8("Nil"); + da_push(ctx->arena, &ctx->entities); + MetaContext *result = ctx; ctx->filename = c_str_to_s8(filename); @@ -3626,43 +3897,39 @@ metagen_load_context(Arena *arena, char *filename) Arena scratch = ctx->scratch; MetaEntryStack entries = meta_entry_stack_from_file(ctx->arena, filename); - i32 stack_items[32]; - struct { i32 *data; iz capacity; iz count; } stack = {stack_items, countof(stack_items), 0}; - for (iz i = 0; i < entries.count; i++) { MetaEntry *e = entries.data + i; - //if (e->kind == MetaEntryKind_EndScope) depth--; - //meta_entry_print(e, depth, -1); - //if (e->kind == MetaEntryKind_BeginScope) depth++; - //continue; switch (e->kind) { - case MetaEntryKind_BeginScope:{ *da_push(&scratch, &stack) = (i32)i; }break; - case MetaEntryKind_EndScope:{ --stack.count; }break; + case MetaEntryKind_Constant:{ + meta_pack_constant(ctx, e); + }break; + case MetaEntryKind_Emit:{ i += meta_pack_emit(ctx, scratch, e, entries.count - i); }break; - case MetaEntryKind_Enumeration:{ - meta_entry_argument_expected(e, s8("kind"), s8("[id ...]")); - s8 kind = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string; - MetaEntryArgument ids = meta_entry_argument_expect(e, 1, MetaEntryArgumentKind_Array); - for (u32 id = 0; id < ids.count; id++) - meta_commit_enumeration(ctx, kind, ids.strings[id]); - }break; + case MetaEntryKind_Embed:{ meta_embed(ctx, scratch, e, entries.count - i); }break; + case MetaEntryKind_Expand:{ i += meta_expand(ctx, scratch, e, entries.count - i, 0); }break; + case MetaEntryKind_MUnion:{ meta_pack_munion(ctx, e, entries.count - i); }break; + case MetaEntryKind_ShaderGroup:{ i += meta_pack_shader_group(ctx, e, entries.count - i); }break; - case MetaEntryKind_Table:{ - i += meta_pack_table(ctx, e, entries.count - i); + + case MetaEntryKind_Enumeration: + case MetaEntryKind_Struct: + case MetaEntryKind_Table: + { + i += meta_pack_table_entity(ctx, e, entries.count - i, e->name, meta_root_entity_id(ctx)); }break; default: @@ -3672,6 +3939,128 @@ metagen_load_context(Arena *arena, char *filename) } } + // NOTE(rnp): sort enitity ids into sub arrays + { + assert(ctx->entity_kind_counts[MetaEntityKind_Nil] == 0); + + for EachNonZeroEnumValue(MetaEntityKind, it) { + if (ctx->entity_kind_counts[it]) { + ctx->entity_kind_ids[it] = push_array(ctx->arena, typeof(*ctx->entity_kind_ids[it]), ctx->entity_kind_counts[it]); + } + } + + da_count entity_counts[MetaEntityKind_Count] = {0}; + for (da_count entity = 1; entity < ctx->entities.count; entity++) { + MetaEntity *e = ctx->entities.data + entity; + da_count index = entity_counts[e->kind]++; + ctx->entity_kind_ids[e->kind][index] = da_index(e, &ctx->entities); + } + } + + // NOTE(rnp): resolve reference entities + { + for (da_count entity = 0; entity < ctx->entity_kind_counts[MetaEntityKind_Reference]; entity++) { + MetaEntity *e = ctx->entities.data + ctx->entity_kind_ids[MetaEntityKind_Reference][entity]; + da_count reference_id = meta_lookup_string_slow(ctx->entity_names.data, ctx->entity_names.count, e->reference.reference_name); + if (reference_id >= 0) + e->reference.resolved_id.value = reference_id; + } + + b32 error = 0; + for (da_count entity = 0; entity < ctx->entity_kind_counts[MetaEntityKind_Reference]; entity++) { + MetaEntity *e = ctx->entities.data + ctx->entity_kind_ids[MetaEntityKind_Reference][entity]; + MetaEntityReference *r = &e->reference; + if (e->reference.resolved_id.value == 0) { + meta_compiler_error_message(e->location, "undefined reference%s to '%.*s'\n", + r->reference_count > 1? "s" : "", + (i32)r->reference_name.len, r->reference_name.data); + if (r->reference_count > 1) + meta_compiler_message(" referenced in %d other places\n", r->reference_count - 1); + error = 1; + } + } + if (error) meta_error(); + } + + // NOTE(rnp): extract entities referenced by shaders + { + for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; + MetaShader *s = &ctx->entities.data[id].shader; + for (da_count ref = 0; ref < s->entity_reference_ids.count; ref++) { + MetaEntityReference *r = &ctx->entities.data[s->entity_reference_ids.data[ref]].reference; + meta_intern_id(ctx, &ctx->shader_entity_references, r->resolved_id.value); + } + } + } + + // 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]; + 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]; + meta_compiler_error(e->location, "struct '%.*s' references undefined type '%.*s'\n", + (i32)name.len, name.data, (i32)types[member].len, types[member].data); + } + } + } + } + } + + // NOTE(rnp): finalize base shader nonsense + { + for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { + MetaEntity *e = ctx->entities.data + ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; + if (e->shader.file.len > 0) + ctx->base_shader_count++; + } + + ctx->base_shader_ids = push_array(ctx->arena, da_count, ctx->base_shader_count); + ctx->base_shader_id_map = push_array(ctx->arena, da_count, ctx->entity_kind_counts[MetaEntityKind_Shader]); + + da_count base_shader_ids_index = 0; + for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; + if (ctx->entities.data[id].shader.file.len > 0) + ctx->base_shader_ids[base_shader_ids_index++] = id; + } + + // NOTE(rnp): first pass to resolve real shaders + for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; + if (ctx->entities.data[id].shader.file.len > 0) { + ctx->base_shader_id_map[shader] = meta_lookup_id_slow(ctx->base_shader_ids, + ctx->base_shader_count, + id); + } else { + ctx->base_shader_id_map[shader] = -1; + } + } + + // NOTE(rnp): second pass to resolve aliases + for (da_count shader = 0; shader < ctx->entity_kind_counts[MetaEntityKind_Shader]; shader++) { + da_count id = ctx->entity_kind_ids[MetaEntityKind_Shader][shader]; + if (ctx->base_shader_id_map[shader] == -1) { + if (ctx->entities.data[id].shader.kind == MetaShaderKind_Alias) { + ctx->base_shader_id_map[shader] = meta_lookup_id_slow(ctx->base_shader_ids, + ctx->base_shader_count, + ctx->entities.data[id].shader.alias_parent_id.value); + assert(ctx->base_shader_id_map[shader] != -1); + } + } + } + } + result->arena = 0; return result; } @@ -3681,10 +4070,6 @@ metagen_file_direct(Arena arena, char *filename) { MetaContext *ctx = metagen_load_context(&arena, filename); if (!ctx) return 0; - if (ctx->shaders.count || ctx->base_shaders.count || ctx->shader_groups.count) { - build_log_error("shaders not supported in file: %s\n", filename); - return 0; - } b32 result = 1; char *out; diff --git a/generated/beamformer.meta.c b/generated/beamformer.meta.c @@ -2,6 +2,17 @@ // GENERATED CODE +// NOTE: Constants (Integer) +#define BeamformerFilterSlots (4) +#define BeamformerMaxBacklogFrames (16) +#define BeamformerMaxChannelCount (256) +#define BeamformerMaxEmmissionsCount (256) +#define BeamformerMaxComputeShaderStages (16) +#define BeamformerMaxParameterBlocks (16) +#define BeamformerMaxRawDataFramesInFlight (3) + +// NOTE: Constants (Float) + typedef enum { BeamformerDecodeMode_None = 0, BeamformerDecodeMode_Hadamard = 1, @@ -22,34 +33,6 @@ typedef enum { } BeamformerSamplingMode; typedef enum { - BeamformerEmissionKind_Sine = 0, - BeamformerEmissionKind_Chirp = 1, - BeamformerEmissionKind_Count, -} BeamformerEmissionKind; - -typedef enum { - BeamformerAcquisitionKind_FORCES = 0, - BeamformerAcquisitionKind_UFORCES = 1, - BeamformerAcquisitionKind_HERCULES = 2, - BeamformerAcquisitionKind_RCA_VLS = 3, - BeamformerAcquisitionKind_RCA_TPW = 4, - BeamformerAcquisitionKind_UHERCULES = 5, - BeamformerAcquisitionKind_RACES = 6, - BeamformerAcquisitionKind_EPIC_FORCES = 7, - BeamformerAcquisitionKind_EPIC_UFORCES = 8, - BeamformerAcquisitionKind_EPIC_UHERCULES = 9, - BeamformerAcquisitionKind_Flash = 10, - BeamformerAcquisitionKind_HERO_PA = 11, - BeamformerAcquisitionKind_Count, -} BeamformerAcquisitionKind; - -typedef enum { - BeamformerContrastMode_None = 0, - BeamformerContrastMode_A1S2 = 1, - BeamformerContrastMode_Count, -} BeamformerContrastMode; - -typedef enum { BeamformerDataKind_Int16 = 0, BeamformerDataKind_Int16Complex = 1, BeamformerDataKind_Float32 = 2, @@ -60,10 +43,16 @@ typedef enum { } BeamformerDataKind; typedef enum { - BeamformerFilterKind_Kaiser = 0, - BeamformerFilterKind_MatchedChirp = 1, - BeamformerFilterKind_Count, -} BeamformerFilterKind; + BeamformerContrastMode_None = 0, + BeamformerContrastMode_A1S2 = 1, + BeamformerContrastMode_Count, +} BeamformerContrastMode; + +typedef enum { + BeamformerEmissionKind_Sine = 0, + BeamformerEmissionKind_Chirp = 1, + BeamformerEmissionKind_Count, +} BeamformerEmissionKind; typedef enum { BeamformerInterpolationMode_Nearest = 0, @@ -73,23 +62,26 @@ typedef enum { } BeamformerInterpolationMode; typedef enum { - BeamformerShaderDecodeFlags_DilateOutput = (1 << 0), - BeamformerShaderDecodeFlags_UseSharedMemory = (1 << 1), -} BeamformerShaderDecodeFlags; - -typedef enum { - BeamformerShaderFilterFlags_ComplexFilter = (1 << 0), - BeamformerShaderFilterFlags_OutputFloats = (1 << 1), - BeamformerShaderFilterFlags_Demodulate = (1 << 2), -} BeamformerShaderFilterFlags; + BeamformerFilterKind_Kaiser = 0, + BeamformerFilterKind_MatchedChirp = 1, + BeamformerFilterKind_Count, +} BeamformerFilterKind; typedef enum { - BeamformerShaderDASFlags_Fast = (1 << 0), - BeamformerShaderDASFlags_Sparse = (1 << 1), - BeamformerShaderDASFlags_CoherencyWeighting = (1 << 2), - BeamformerShaderDASFlags_SingleFocus = (1 << 3), - BeamformerShaderDASFlags_SingleOrientation = (1 << 4), -} BeamformerShaderDASFlags; + BeamformerAcquisitionKind_FORCES = 0, + BeamformerAcquisitionKind_UFORCES = 1, + BeamformerAcquisitionKind_HERCULES = 2, + BeamformerAcquisitionKind_RCA_VLS = 3, + BeamformerAcquisitionKind_RCA_TPW = 4, + BeamformerAcquisitionKind_UHERCULES = 5, + BeamformerAcquisitionKind_RACES = 6, + BeamformerAcquisitionKind_EPIC_FORCES = 7, + BeamformerAcquisitionKind_EPIC_UFORCES = 8, + BeamformerAcquisitionKind_EPIC_UHERCULES = 9, + BeamformerAcquisitionKind_Flash = 10, + BeamformerAcquisitionKind_HERO_PA = 11, + BeamformerAcquisitionKind_Count, +} BeamformerAcquisitionKind; typedef enum { BeamformerShaderKind_CudaDecode = 0, @@ -112,6 +104,79 @@ 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; u32 decode_mode; u32 input_channel_stride; u32 input_sample_stride; @@ -121,9 +186,13 @@ typedef struct { u32 output_transmit_stride; u32 to_process; u32 transmit_count; -} BeamformerShaderDecodeBakeParameters; +} BeamformerDecodeBakeParameters; typedef struct { + u32 data_kind; + u32 demodulate; + u32 complex_filter; + u32 output_floats; u32 decimation_rate; u32 filter_length; u32 input_channel_stride; @@ -135,9 +204,15 @@ typedef struct { u32 sample_count; f32 demodulation_frequency; f32 sampling_frequency; -} BeamformerShaderFilterBakeParameters; +} BeamformerFilterBakeParameters; typedef struct { + u32 data_kind; + u32 coherency_weighting; + u32 single_focus; + u32 single_orientation; + u32 fast; + u32 sparse; u32 acquisition_count; u32 acquisition_kind; u32 channel_count; @@ -151,22 +226,12 @@ typedef struct { f32 speed_of_sound; f32 time_offset; f32 transmit_angle; -} BeamformerShaderDASBakeParameters; +} BeamformerDASBakeParameters; -typedef struct { - m4 xdc_transform; - m4 voxel_transform; - v2 xdc_element_pitch; -} BeamformerShaderDASPushConstants; - -typedef struct { - union { - BeamformerShaderDecodeBakeParameters Decode; - BeamformerShaderFilterBakeParameters Filter; - BeamformerShaderDASBakeParameters DAS; - }; - u32 data_kind; - u32 flags; +typedef union { + BeamformerDecodeBakeParameters Decode; + BeamformerFilterBakeParameters Filter; + BeamformerDASBakeParameters DAS; } BeamformerShaderBakeParameters; typedef union { @@ -211,24 +276,6 @@ typedef struct { } BeamformerParameters; 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; @@ -474,43 +521,19 @@ read_only global s8 beamformer_shader_global_header_strings[] = { "#define RCAOrientation_Rows 1\n" "#define RCAOrientation_Columns 2\n" "\n"), -}; - -read_only global s8 *beamformer_shader_flag_strings[] = { - (s8 []){ - s8_comp("DilateOutput"), - s8_comp("UseSharedMemory"), - }, - (s8 []){ - s8_comp("ComplexFilter"), - s8_comp("OutputFloats"), - s8_comp("Demodulate"), - }, - (s8 []){ - s8_comp("Fast"), - s8_comp("Sparse"), - s8_comp("CoherencyWeighting"), - s8_comp("SingleFocus"), - s8_comp("SingleOrientation"), - }, - 0, - 0, - 0, -}; - -read_only global u8 beamformer_shader_flag_strings_count[] = { - 2, - 3, - 5, - 0, - 0, - 0, + s8_comp("" + "layout(std140, binding = 0) uniform PushConstants {\n" + " mat4 xdc_transform;\n" + " mat4 voxel_transform;\n" + " vec2 xdc_element_pitch;\n" + "};\n" + "\n"), }; read_only global i32 *beamformer_shader_header_vectors[] = { (i32 []){0, 1}, (i32 []){0}, - (i32 []){2, 0, 3, 4}, + (i32 []){2, 0, 3, 4, 5}, 0, 0, 0, @@ -519,7 +542,7 @@ read_only global i32 *beamformer_shader_header_vectors[] = { read_only global i32 beamformer_shader_header_vector_lengths[] = { 2, 1, - 4, + 5, 0, 0, 0, @@ -527,6 +550,9 @@ read_only global i32 beamformer_shader_header_vector_lengths[] = { read_only global s8 *beamformer_shader_bake_parameter_names[] = { (s8 []){ + s8_comp("DataKind"), + s8_comp("DilateOutput"), + s8_comp("UseSharedMemory"), s8_comp("DecodeMode"), s8_comp("InputChannelStride"), s8_comp("InputSampleStride"), @@ -538,6 +564,10 @@ read_only global s8 *beamformer_shader_bake_parameter_names[] = { s8_comp("TransmitCount"), }, (s8 []){ + s8_comp("DataKind"), + s8_comp("Demodulate"), + s8_comp("ComplexFilter"), + s8_comp("OutputFloats"), s8_comp("DecimationRate"), s8_comp("FilterLength"), s8_comp("InputChannelStride"), @@ -551,6 +581,12 @@ read_only global s8 *beamformer_shader_bake_parameter_names[] = { s8_comp("SamplingFrequency"), }, (s8 []){ + s8_comp("DataKind"), + s8_comp("CoherencyWeighting"), + s8_comp("SingleFocus"), + s8_comp("SingleOrientation"), + s8_comp("Fast"), + s8_comp("Sparse"), s8_comp("AcquisitionCount"), s8_comp("AcquisitionKind"), s8_comp("ChannelCount"), @@ -572,61 +608,17 @@ read_only global s8 *beamformer_shader_bake_parameter_names[] = { read_only global u32 beamformer_shader_bake_parameter_float_bits[] = { 0x00000000UL, - 0x00000600UL, - 0x00001fc0UL, + 0x00006000UL, + 0x0007f000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, }; -read_only global i32 beamformer_shader_bake_parameter_counts[] = { - 9, - 11, - 13, - 0, - 0, - 0, -}; - -read_only global s8 *beamformer_shader_push_constant_glsl_types[] = { - 0, - 0, - (s8 []){ - s8_comp("mat4"), - s8_comp("mat4"), - s8_comp("vec2"), - }, - 0, - 0, - 0, -}; - -read_only global s8 *beamformer_shader_push_constant_names[] = { - 0, - 0, - (s8 []){ - s8_comp("xdc_transform"), - s8_comp("voxel_transform"), - s8_comp("xdc_element_pitch"), - }, - 0, - 0, - 0, -}; - -read_only global u8 beamformer_shader_push_constant_counts[] = { - 0, - 0, - 3, - 0, - 0, - 0, -}; - -read_only global u8 beamformer_shader_push_constant_sizes[] = { - 0, - 0, - sizeof(BeamformerShaderDASPushConstants), +read_only global u8 beamformer_shader_bake_parameter_counts[] = { + 12, + 15, + 19, 0, 0, 0, diff --git a/lib/ogl_beamformer_lib.c b/lib/ogl_beamformer_lib.c @@ -240,7 +240,7 @@ beamformer_reserve_parameter_blocks(uint32_t count) { b32 result = 0; if (check_shared_memory() && - lib_error_check(count <= BeamformerMaxParameterBlockSlots, ParameterBlockOverflow)) + lib_error_check(count <= BeamformerMaxParameterBlocks, ParameterBlockOverflow)) { g_beamformer_library_context.bp->reserved_parameter_blocks = count; result = 1; @@ -365,7 +365,7 @@ beamformer_create_filter_base(BeamformerFilterParameters params, u8 filter_slot, work->kind = BeamformerWorkKind_CreateFilter; ctx->parameters = params; ctx->filter_slot = filter_slot % BeamformerFilterSlots; - ctx->parameter_block = parameter_block % BeamformerMaxParameterBlockSlots; + ctx->parameter_block = parameter_block % BeamformerMaxParameterBlocks; beamform_work_queue_push_commit(&g_beamformer_library_context.bp->external_work_queue); result = 1; } diff --git a/main_linux.c b/main_linux.c @@ -42,9 +42,9 @@ typedef struct { iptr handle; s8 name; - OSLinux_FileWatch * data; - iz count; - iz capacity; + OSLinux_FileWatch *data; + da_count count; + da_count capacity; } OSLinux_FileWatchDirectory; DA_STRUCT(OSLinux_FileWatchDirectory, OSLinux_FileWatchDirectory); @@ -148,7 +148,7 @@ function OSLinux_FileWatchDirectory * os_lookup_file_watch_directory(OSLinux_FileWatchDirectoryList *ctx, u64 hash) { OSLinux_FileWatchDirectory *result = 0; - for (iz i = 0; !result && i < ctx->count; i++) + for (da_count i = 0; !result && i < ctx->count; i++) if (ctx->data[i].hash == hash) result = ctx->data + i; return result; @@ -265,14 +265,14 @@ dispatch_file_watch_events(BeamformerInput *input) while ((rlen = read(os_linux_context.inotify_handle, mem, 4096)) > 0) { for (u8 *data = mem; data < mem + rlen; data += sizeof(*event) + event->len) { event = (struct inotify_event *)data; - for (u32 i = 0; i < fwctx->count; i++) { + for (da_count i = 0; i < fwctx->count; i++) { OSLinux_FileWatchDirectory *dir = fwctx->data + i; if (event->wd != dir->handle) continue; s8 file = c_str_to_s8(event->name); u64 hash = u64_hash_from_s8(file); - for (u32 j = 0; j < dir->count; j++) { + for (da_count j = 0; j < dir->count; j++) { OSLinux_FileWatch *fw = dir->data + j; if (fw->hash == hash) { // NOTE(rnp): avoid multiple updates in a single frame diff --git a/main_w32.c b/main_w32.c @@ -74,8 +74,8 @@ typedef struct { s8 name; OSW32_FileWatch *data; - iz count; - iz capacity; + da_count count; + da_count capacity; w32_overlapped overlapped; w32_io_completion_event event; @@ -178,7 +178,7 @@ function OSW32_FileWatchDirectory * os_lookup_file_watch_directory(OSW32_FileWatchDirectoryList *ctx, u64 hash) { OSW32_FileWatchDirectory *result = 0; - for (iz i = 0; !result && i < ctx->count; i++) + for (da_count i = 0; !result && i < ctx->count; i++) if (ctx->data[i].hash == hash) result = ctx->data + i; return result; @@ -324,7 +324,7 @@ dispatch_file_watch(BeamformerInput *input, Arena arena, u64 current_time, OSW32 s8 file_name = s16_to_s8(&arena, (s16){.data = fni->filename, .len = fni->filename_size / 2}); u64 hash = u64_hash_from_s8(file_name); - for (u32 i = 0; i < fw_dir->count; i++) { + for (da_count i = 0; i < fw_dir->count; i++) { OSW32_FileWatch *fw = fw_dir->data + i; if (fw->hash == hash) { // NOTE(rnp): avoid multiple updates in a single frame diff --git a/ui.c b/ui.c @@ -498,8 +498,8 @@ typedef struct { typedef struct Table { TableRow *data; - iz count; - iz capacity; + da_count count; + da_count capacity; /* NOTE(rnp): counted by columns */ TextAlignment *alignment; @@ -525,8 +525,8 @@ typedef struct { typedef struct { TableStackFrame *data; - iz count; - iz capacity; + da_count count; + da_count capacity; } TableStack; typedef enum { @@ -745,7 +745,7 @@ push_custom_view_title(Stream *s, Variable *var) }break; case BeamformerFrameViewKind_Indexed:{ stream_append_s8(s, s8(": Index {")); - stream_append_u64(s, *bv->cycler->cycler.state % BeamformerMaxSavedFrames); + stream_append_u64(s, *bv->cycler->cycler.state % BeamformerMaxBacklogFrames); stream_append_s8(s, s8("} [")); }break; case BeamformerFrameViewKind_3DXPlane:{ stream_append_s8(s, s8(": 3D X-Plane")); }break; @@ -1397,7 +1397,7 @@ ui_beamformer_frame_view_convert(BeamformerUI *ui, Arena *arena, Variable *view, }break; case BeamformerFrameViewKind_Indexed:{ bv->cycler = add_variable_cycler(ui, menu, arena, 0, ui->small_font, s8("Index:"), - &bv->cycler_state, 0, BeamformerMaxSavedFrames); + &bv->cycler_state, 0, BeamformerMaxBacklogFrames); }break; default:{}break; } @@ -2858,7 +2858,7 @@ draw_compute_stats_view(BeamformerUI *ui, Arena arena, Variable *view, Rect r, v assert(view->type == VT_COMPUTE_STATS_VIEW); read_only local_persist BeamformerComputePlan dummy_plan = {0}; - u32 selected_plan = ui->selected_parameter_block % BeamformerMaxParameterBlockSlots; + u32 selected_plan = ui->selected_parameter_block % BeamformerMaxParameterBlocks; BeamformerComputePlan *cp = ui->beamformer_context->compute_context.compute_plans[selected_plan]; if (!cp) cp = &dummy_plan; @@ -3299,9 +3299,9 @@ draw_ui_regions(BeamformerUI *ui, Rect window, v2 mouse) struct { struct region_frame *data; - iz count; - iz capacity; - } stack = {init, 0, ARRAY_COUNT(init)}; + da_count count; + da_count capacity; + } stack = {init, 0, countof(init)}; TempArena arena_savepoint = begin_temp_arena(&ui->arena); @@ -3442,7 +3442,10 @@ function void end_text_input(InputState *is, Variable *var) { f32 value = 0; - if (is->numeric) value = (f32)parse_f64((s8){.len = is->count, .data = is->buf}); + if (is->numeric) { + NumberConversion number = number_from_s8((s8){.len = is->count, .data = is->buf}); + value = number.F64; + } switch (var->type) { case VT_SCALED_F32:{ var->scaled_real32.val = value; }break; @@ -4093,7 +4096,7 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input, BeamformerFrame *frame_to_dr asan_poison_region(ui->arena.beg, ui->arena.end - ui->arena.beg); - u32 selected_block = ui->selected_parameter_block % BeamformerMaxParameterBlockSlots; + u32 selected_block = ui->selected_parameter_block % BeamformerMaxParameterBlocks; u32 selected_mask = 1 << selected_block; if (ctx->ui_dirty_parameter_blocks & selected_mask) { BeamformerParameterBlock *pb = beamformer_parameter_block_lock(ui->shared_memory, selected_block, 0); diff --git a/util.c b/util.c @@ -236,9 +236,9 @@ enum { DA_INITIAL_CAP = 16 }; : (s)->data + (s)->count++, 0, sizeof(*(s)->data))) function void * -da_reserve_(Arena *a, void *data, iz *capacity, iz needed, uz align, iz size) +da_reserve_(Arena *a, void *data, da_count *capacity, da_count needed, u64 align, i64 size) { - iz cap = *capacity; + da_count cap = *capacity; /* NOTE(rnp): handle both 0 initialized DAs and DAs that need to be moved (they started * on the stack or someone allocated something in the middle of the arena during usage) */ @@ -783,7 +783,7 @@ cut_rect_vertical(Rect rect, f32 at, Rect *top, Rect *bot) } } -function IntegerConversion +function NumberConversion integer_from_s8(s8 raw) { read_only local_persist alignas(64) i8 lut[64] = { @@ -793,7 +793,7 @@ integer_from_s8(s8 raw) -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; - IntegerConversion result = {.unparsed = raw}; + NumberConversion result = {.unparsed = raw}; iz i = 0; i64 scale = 1; @@ -813,7 +813,7 @@ integer_from_s8(s8 raw) i64 value = lut[Min((u8)(raw.data[i] - (u8)'0'), clamp)];\ if (value >= 0) {\ if (result.U64 > (U64_MAX - (u64)value) / radix) {\ - result.result = IntegerConversionResult_OutOfRange;\ + result.result = NumberConversionResult_OutOfRange;\ result.U64 = U64_MAX;\ return result;\ } else {\ @@ -831,27 +831,42 @@ integer_from_s8(s8 raw) #undef integer_conversion_body result.unparsed = (s8){.len = raw.len - i, .data = raw.data + i}; - result.result = IntegerConversionResult_Success; + result.result = i > 0 ? NumberConversionResult_Success : NumberConversionResult_Invalid; + result.kind = NumberConversionKind_Integer; if (scale < 0) result.U64 = 0 - result.U64; return result; } -function f64 -parse_f64(s8 s) +function NumberConversion +number_from_s8(s8 s) { - IntegerConversion integral = integer_from_s8(s); + NumberConversion result = {.unparsed = s}; + NumberConversion integer = integer_from_s8(s); + if (integer.result == NumberConversionResult_Success) { + if (integer.unparsed.len != 0 && integer.unparsed.data[0] == '.') { + s = integer.unparsed; + s.data++; + s.len--; - s = integral.unparsed; - if (*s.data == '.') { s.data++; s.len--; } - while (s.len > 0 && s.data[s.len - 1] == '0') s.len--; + while (s.len > 0 && s.data[s.len - 1] == '0') s.len--; - IntegerConversion fractional = integer_from_s8(s); + NumberConversion fractional = integer_from_s8(s); + if (fractional.result == NumberConversionResult_Success || s.len == 0) { + result.F64 = (f64)fractional.U64; - u64 power = (u64)(fractional.unparsed.data - s.data); - f64 frac = (f64)fractional.U64; - while (power > 0) { frac /= 10.0; power--; } + u64 divisor = (u64)(fractional.unparsed.data - s.data); + while (divisor > 0) { result.F64 /= 10.0; divisor--; } - f64 result = (f64)integral.S64 + frac; + result.F64 += (f64)integer.S64; + + result.result = NumberConversionResult_Success; + result.kind = NumberConversionKind_Float; + result.unparsed = fractional.unparsed; + } + } else { + result = integer; + } + } return result; } diff --git a/util.h b/util.h @@ -4,6 +4,8 @@ #include "compiler.h" +#define da_count i32 + #if COMPILER_MSVC typedef unsigned __int64 u64; typedef signed __int64 i64; @@ -106,7 +108,6 @@ typedef u64 uptr; #define str(...) str_(__VA_ARGS__) #define countof(a) (iz)(sizeof(a) / sizeof(*a)) -#define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a)) #define BETWEEN(x, a, b) ((x) >= (a) && (x) <= (b)) #define CLAMP(x, a, b) ((x) < (a) ? (a) : (x) > (b) ? (b) : (x)) #define CLAMP01(x) CLAMP(x, 0, 1) @@ -145,9 +146,9 @@ typedef u64 uptr; #define spin_wait(c) while ((c)) cpu_yield() #define DA_STRUCT(kind, name) typedef struct { \ - kind *data; \ - iz count; \ - iz capacity; \ + kind *data; \ + da_count count; \ + da_count capacity; \ } name ##List; /* NOTE(rnp): no guarantees about actually getting an element */ @@ -217,19 +218,27 @@ typedef struct { iz len; u16 *data; } s16; typedef struct { u32 cp, consumed; } UnicodeDecode; typedef enum { - IntegerConversionResult_Invalid, - IntegerConversionResult_OutOfRange, - IntegerConversionResult_Success, -} IntegerConversionResult; + NumberConversionResult_Invalid, + NumberConversionResult_OutOfRange, + NumberConversionResult_Success, +} NumberConversionResult; + +typedef enum { + NumberConversionKind_Invalid, + NumberConversionKind_Integer, + NumberConversionKind_Float, +} NumberConversionKind; typedef struct { - IntegerConversionResult result; + NumberConversionResult result; + NumberConversionKind kind; union { u64 U64; i64 S64; + f64 F64; }; s8 unparsed; -} IntegerConversion; +} NumberConversion; typedef struct { u64 start, stop; } RangeU64;