ogl_beamforming

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

beamformer_internal.h (20510B)


      1 /* See LICENSE for license details. */
      2 #ifndef BEAMFORMER_INTERNAL_H
      3 #define BEAMFORMER_INTERNAL_H
      4 
      5 #include "beamformer.h"
      6 
      7 #include "util.h"
      8 #include "opengl.h"
      9 
     10 #include "generated/beamformer.c"
     11 #include "generated/beamformer_core.c"
     12 #include "generated/beamformer_shader_data.c"
     13 
     14 #include "external/raylib/src/raylib.h"
     15 #include "external/raylib/src/rlgl.h"
     16 
     17 #define beamformer_info(s) str8("[info] " s "\n")
     18 
     19 #define os_path_separator() (str8){.data = &os_system_info()->path_separator_byte, .length = 1}
     20 
     21 typedef struct { u64 value[1]; } VulkanHandle;
     22 
     23 typedef enum {
     24 	VulkanTimeline_Graphics,
     25 	VulkanTimeline_Compute,
     26 	VulkanTimeline_Transfer,
     27 	VulkanTimeline_Count,
     28 } VulkanTimeline;
     29 
     30 typedef enum {
     31 	VulkanShaderKind_Vertex,
     32 	VulkanShaderKind_Mesh,
     33 	VulkanShaderKind_Fragment,
     34 	VulkanShaderKind_Compute,
     35 	VulkanShaderKind_Count,
     36 } VulkanShaderKind;
     37 
     38 typedef enum {
     39 	VulkanImageUsage_None,
     40 	VulkanImageUsage_Colour,
     41 	VulkanImageUsage_DepthStencil,
     42 	VulkanImageUsage_Count,
     43 } VulkanImageUsage;
     44 
     45 typedef enum {
     46 	VulkanUsageFlag_ImageSampling       = 1 << 0,
     47 	VulkanUsageFlag_HostReadWrite       = 1 << 1, // NOTE: not valid on images
     48 	/* NOTE: uses:
     49 	 * - image-image copy operations
     50 	 * - buffer-buffer copy operations
     51 	 */
     52 	VulkanUsageFlag_TransferSource      = 1 << 2,
     53 	VulkanUsageFlag_TransferDestination = 1 << 3,
     54 } VulkanUsageFlags;
     55 
     56 typedef struct {
     57 	VulkanShaderKind kind;
     58 	i32              specialization_struct_id;
     59 	void            *specialization_data;
     60 	str8             text;
     61 	str8             name;
     62 } VulkanPipelineCreateInfo;
     63 
     64 typedef struct {
     65 	VulkanHandle handle;
     66 	u64          gpu_pointer;
     67 	i64          size;
     68 
     69 	// NOTE: only used for render models
     70 	u64          index_count;
     71 } GPUBuffer;
     72 
     73 typedef struct {
     74 	VulkanHandle image;
     75 	u32          width;
     76 	u32          height;
     77 	u32          samples;
     78 	u32          mip_map_levels;
     79 	// TODO(rnp): this is only here for importing from OpenGL, move it back into handle later
     80 	u64          memory_size;
     81 } GPUImage;
     82 
     83 typedef enum {
     84 	GPUVendor_AMD      = 0x1002,
     85 	GPUVendor_NVIDIA   = 0x10DE,
     86 	GPUVendor_Qualcomm = 0x5143,
     87 	GPUVendor_Intel    = 0x8086,
     88 } GPUVendor;
     89 
     90 typedef struct {
     91 	str8      name;
     92 	GPUVendor vendor;
     93 
     94 	f32 timestamp_period_ns;
     95 
     96 	u32 max_compute_shared_memory_size;
     97 	u16 max_msaa_samples;
     98 	u16 subgroup_size;
     99 
    100 	b32 cooperative_matrix;
    101 
    102 	u32 max_image_dimension_2D;
    103 	// NOTE(rnp): vulkan compute will output to a buffer so this won't be relevant
    104 	u32 max_image_dimension_3D;
    105 
    106 	u64 gpu_heap_size;
    107 	u64 gpu_heap_used;
    108 } GPUInfo;
    109 
    110 typedef struct {
    111 	i64               size;
    112 	VulkanUsageFlags  flags;
    113 
    114 	// NOTE(rnp): only required if buffer will be used on multiple timelines
    115 	VulkanTimeline   *timelines_used;
    116 	u32               timeline_count;
    117 
    118 	OSHandle         *export;
    119 
    120 	str8              label;
    121 } GPUBufferAllocateInfo;
    122 
    123 typedef struct {
    124 	GPUBuffer *gpu_buffer;
    125 	u64        offset;
    126 	u64        size;
    127 } GPUMemoryBarrierInfo;
    128 
    129 typedef struct {
    130 	GPUBuffer model;
    131 	u32       vertex_count;
    132 	u32       normals_offset;
    133 } RenderModel;
    134 
    135 typedef struct {
    136 	BeamformerShaderResourceKind kind;
    137 	VulkanHandle                 handle;
    138 	u32                          slot;
    139 } BeamformerShaderResourceInfo;
    140 
    141 #include "threads.c"
    142 #include "util_os_ui.c"
    143 #include "util_os.c"
    144 
    145 ///////////////////////////
    146 // NOTE: vulkan layer API
    147 DEBUG_IMPORT void vk_load(OSLibrary vulkan, Arena *memory, Stream *error);
    148 
    149 DEBUG_IMPORT GPUInfo *vk_gpu_info(void);
    150 
    151 DEBUG_IMPORT void vk_buffer_allocate(GPUBuffer *, GPUBufferAllocateInfo *info);
    152 DEBUG_IMPORT void vk_buffer_release(GPUBuffer *);
    153 DEBUG_IMPORT void vk_buffer_range_upload(GPUBuffer *, void *data, u64 offset, u64 size, b32 non_temporal);
    154 DEBUG_IMPORT void vk_buffer_range_download(void *output, GPUBuffer *, u64 source_offset, u64 size, b32 non_temporal);
    155 DEBUG_IMPORT u64  vk_round_up_to_sync_size(u64, u64 min);
    156 
    157 // NOTE: images are 2D only, any other use case should just use a buffer and index in the shader
    158 DEBUG_IMPORT void vk_image_allocate(GPUImage *, u32 width, u32 height, u32 mips, u32 samples, VulkanImageUsage usage, VulkanUsageFlags flags, OSHandle *export, str8 label);
    159 DEBUG_IMPORT void vk_image_release(GPUImage *);
    160 
    161 DEBUG_IMPORT void vk_render_model_allocate(GPUBuffer *, void *indices, u64 index_count, u64 model_size, str8 label);
    162 DEBUG_IMPORT void vk_render_model_range_upload(GPUBuffer *, void *data, u64 offset, u64 size, b32 non_temporal);
    163 DEBUG_IMPORT void vk_render_model_release(GPUBuffer *);
    164 
    165 DEBUG_IMPORT void vk_bind_shader_resources(BeamformerShaderResourceInfo *infos, u64 info_count);
    166 
    167 /* NOTE: Pipelines do not have bindings. Data should be passed using push constants.
    168  * In particular the push constants should contain pointers to gpu memory using the
    169  * BufferDeviceAddress extension. */
    170 // TODO(rnp): change this to accept SPIR-V directly and accept BakeParameters as specialization data
    171 DEBUG_IMPORT VulkanHandle vk_pipeline(VulkanPipelineCreateInfo *infos, u32 count, u32 push_constants_size);
    172 DEBUG_IMPORT b32          vk_pipeline_valid(VulkanHandle);
    173 DEBUG_IMPORT void         vk_pipeline_release(VulkanHandle);
    174 
    175 DEBUG_IMPORT b32 vk_buffer_needs_sync(GPUBuffer *);
    176 
    177 DEBUG_IMPORT VulkanHandle vk_create_semaphore(OSHandle *export);
    178 
    179 DEBUG_IMPORT b32          vk_host_wait_timeline(VulkanTimeline timeline, u64 value, u64 timeout_ns);
    180 DEBUG_IMPORT u64          vk_host_signal_timeline(VulkanTimeline timeline);
    181 
    182 DEBUG_IMPORT VulkanHandle vk_command_begin(VulkanTimeline timeline);
    183 DEBUG_IMPORT void         vk_command_bind_pipeline(VulkanHandle command, VulkanHandle pipeline);
    184 DEBUG_IMPORT void         vk_command_buffer_memory_barriers(VulkanHandle command, GPUMemoryBarrierInfo *barriers, u64 count);
    185 DEBUG_IMPORT void         vk_command_clear_buffer(VulkanHandle command, GPUBuffer *buffer, u64 offset, u64 size, u32 clear_word);
    186 DEBUG_IMPORT void         vk_command_dispatch_compute(VulkanHandle command, uv3 dispatch);
    187 DEBUG_IMPORT void         vk_command_push_constants(VulkanHandle command, u32 offset, u32 size, void *values);
    188 DEBUG_IMPORT void         vk_command_timestamp(VulkanHandle command);
    189 DEBUG_IMPORT void         vk_command_wait_timeline(VulkanHandle command, VulkanTimeline timeline, u64 value);
    190 // NOTE: extra semaphores only exist for synchronization with OpenGL and will be removed in the future
    191 DEBUG_IMPORT u64          vk_command_end(VulkanHandle command, VulkanHandle wait_semaphore, VulkanHandle finished_semaphore);
    192 
    193 DEBUG_IMPORT void         vk_command_begin_rendering(VulkanHandle command, GPUImage *restrict colour, GPUImage *restrict depth, GPUImage *restrict resolve);
    194 DEBUG_IMPORT void         vk_command_draw(VulkanHandle command, GPUBuffer *model);
    195 DEBUG_IMPORT void         vk_command_scissor(VulkanHandle command, u32 width, u32 height, u32 x_offset, u32 y_offset);
    196 DEBUG_IMPORT void         vk_command_viewport(VulkanHandle command, f32 width, f32 height, f32 x_offset, f32 y_offset, f32 min_depth, f32 max_depth);
    197 DEBUG_IMPORT void         vk_command_end_rendering(VulkanHandle command);
    198 
    199 DEBUG_IMPORT void         vk_command_copy_buffer(VulkanHandle command, GPUBuffer *restrict destination, GPUBuffer *restrict source, u64 source_offset, i64 size);
    200 
    201 // NOTE: returns array of valid timestamps + 1, first element is the count.
    202 //       Calling thread may stall until results available.
    203 DEBUG_IMPORT u64 *        vk_command_read_timestamps(VulkanTimeline timeline, Arena *arena);
    204 
    205 #if BEAMFORMER_RENDERDOC_HOOKS
    206 DEBUG_IMPORT void *       vk_renderdoc_instance_handle(void);
    207 
    208 DEBUG_IMPORT renderdoc_start_frame_capture_fn       *start_frame_capture;
    209 DEBUG_IMPORT renderdoc_set_capture_path_template_fn *set_capture_path_template;
    210 DEBUG_IMPORT renderdoc_end_frame_capture_fn         *end_frame_capture;
    211 #define start_renderdoc_capture()  do { \
    212 	if (set_capture_path_template) set_capture_path_template("captures/ogl.rdc"); \
    213 	if (start_frame_capture)       start_frame_capture(vk_renderdoc_instance_handle(), 0); \
    214 } while(0)
    215 #define end_renderdoc_capture()   if (end_frame_capture)   end_frame_capture(vk_renderdoc_instance_handle(), 0)
    216 #define renderdoc_attached(...)   (start_frame_capture != 0)
    217 
    218 #else
    219 #define start_renderdoc_capture(...)
    220 #define end_renderdoc_capture(...)
    221 #define renderdoc_attached(...) (0)
    222 #endif
    223 
    224 ///////////////////////////////
    225 // NOTE: CUDA Library Bindings
    226 
    227 #define cuda_supported() (cuda_init != cuda_init_stub)
    228 #define CUDA_INIT_FN(name) void name(u32 *input_dims, u32 *decoded_dims)
    229 typedef CUDA_INIT_FN(cuda_init_fn);
    230 CUDA_INIT_FN(cuda_init_stub) {}
    231 
    232 #define CUDA_REGISTER_BUFFERS_FN(name) void name(u32 *rf_data_ssbos, u32 rf_buffer_count, u32 raw_data_ssbo)
    233 typedef CUDA_REGISTER_BUFFERS_FN(cuda_register_buffers_fn);
    234 CUDA_REGISTER_BUFFERS_FN(cuda_register_buffers_stub) {}
    235 
    236 #define CUDA_HILBERT_FN(name) void name(u32 input_buffer_idx, u32 output_buffer_idx)
    237 typedef CUDA_HILBERT_FN(cuda_hilbert_fn);
    238 CUDA_HILBERT_FN(cuda_hilbert_stub) {}
    239 
    240 #define CUDA_SET_CHANNEL_MAPPING_FN(name) void name(i16 *channel_mapping)
    241 typedef CUDA_SET_CHANNEL_MAPPING_FN(cuda_set_channel_mapping_fn);
    242 CUDA_SET_CHANNEL_MAPPING_FN(cuda_set_channel_mapping_stub) {}
    243 
    244 #define CUDALibraryProcedureList \
    245 	X(hilbert,             "cuda_hilbert")             \
    246 	X(init,                "init_cuda_configuration")  \
    247 	X(register_buffers,    "register_cuda_buffers")    \
    248 	X(set_channel_mapping, "cuda_set_channel_mapping")
    249 
    250 #define X(name, ...) DEBUG_IMPORT cuda_## name ##_fn *cuda_## name;
    251 CUDALibraryProcedureList
    252 #undef X
    253 
    254 /////////////////////////////////////
    255 // NOTE: Core Beamformer Definitions
    256 
    257 #include "beamformer_compute_stats.c"
    258 #include "beamformer_shared_memory.c"
    259 
    260 typedef struct {
    261 	BeamformerFilterParameters parameters;
    262 	f32                        time_delay;
    263 	i32                        length;
    264 	GPUBuffer                  buffer;
    265 } BeamformerFilter;
    266 
    267 // X(kind, format, elements)
    268 #define BEAMFORMER_COMPUTE_ARRAY_PARAMETERS_LIST \
    269 	X(Hadamard,                    f16, BeamformerMaxChannelCount * BeamformerMaxChannelCount) \
    270 	X(FocalVectors,                v2,  BeamformerMaxChannelCount) \
    271 	X(SparseElements,              i16, BeamformerMaxChannelCount) \
    272 	X(TransmitReceiveOrientations, u16, BeamformerMaxChannelCount) \
    273 
    274 typedef enum {
    275 	#define X(k, ...) BeamformerComputeArrayParameterKind_##k,
    276 	BEAMFORMER_COMPUTE_ARRAY_PARAMETERS_LIST
    277 	#undef X
    278 	BeamformerComputeArrayParameterKind_Count
    279 } BeamformerComputeArrayParameterKind;
    280 
    281 // NOTE(rnp): only used to calculate offsets, never used directly
    282 #define X(name, type, elements) alignas(64) type name[elements];
    283 typedef struct {BEAMFORMER_COMPUTE_ARRAY_PARAMETERS_LIST} BeamformerComputeArrayParameters;
    284 #undef X
    285 
    286 typedef struct {
    287 	uv3 layout;
    288 	uv3 dispatch;
    289 	u32 compile_flags;
    290 	BeamformerDataKind input_data_kind;
    291 	BeamformerDataKind output_data_kind;
    292 	BeamformerShaderBakeParameters bake;
    293 } BeamformerShaderDescriptor;
    294 
    295 typedef struct BeamformerComputePlan BeamformerComputePlan;
    296 struct BeamformerComputePlan {
    297 	BeamformerComputePipeline pipeline;
    298 
    299 	VulkanHandle vulkan_pipelines[BeamformerMaxComputeShaderStages];
    300 
    301 	u32 first_image_shader_index;
    302 	u32 channel_count;
    303 	u32 raw_channel_byte_stride;
    304 
    305 	u32 dirty_programs;
    306 
    307 	BeamformerAcquisitionKind acquisition_kind;
    308 	u32                       acquisition_count;
    309 	BeamformerContrastMode    contrast_mode;
    310 
    311 	u32 rf_size;
    312 	i32 hadamard_order;
    313 	b32 iq_pipeline;
    314 
    315 	m4  ui_voxel_transform;
    316 	// NOTE(rnp): final voxel transform determining frame dimensions
    317 	m4  voxel_transform;
    318 	// NOTE(rnp): final voxel transform used for beamforming
    319 	m4  das_voxel_transform;
    320 
    321 	iv3 output_points;
    322 	i32 average_frames;
    323 
    324 	// TODO(rnp): specialization constants
    325 	v2  xdc_element_pitch;
    326 	m4  xdc_transform;
    327 
    328 	GPUBuffer array_parameters;
    329 
    330 	BeamformerFilter filters[BeamformerFilterSlots];
    331 
    332 	u128 shader_hashes[BeamformerMaxComputeShaderStages];
    333 	BeamformerShaderDescriptor shader_descriptors[BeamformerMaxComputeShaderStages];
    334 
    335 	BeamformerComputePlan *next;
    336 };
    337 
    338 typedef struct {
    339 	u64 upload_complete_values[BeamformerMaxRawDataFramesInFlight];
    340 	u64 compute_complete_values[BeamformerMaxRawDataFramesInFlight];
    341 
    342 	GPUBuffer buffer;
    343 
    344 	u32 active_rf_size;
    345 
    346 	u64 timestamp;
    347 
    348 	u64 insertion_index;
    349 	u64 compute_index;
    350 } BeamformerRFBuffer;
    351 
    352 typedef struct {
    353 	BeamformerComputeStatsTable table;
    354 	f32 average_times[BeamformerShaderKind_Count];
    355 
    356 	u64 last_rf_timer_count;
    357 	f32 rf_time_delta_average;
    358 
    359 	u32 latest_frame_index;
    360 	u32 latest_rf_index;
    361 } ComputeShaderStats;
    362 
    363 /* TODO(rnp): maybe this also gets used for CPU timing info as well */
    364 typedef enum {
    365 	ComputeTimingInfoKind_ComputeFrameBegin,
    366 	ComputeTimingInfoKind_ComputeFrameEnd,
    367 	ComputeTimingInfoKind_Shader,
    368 	ComputeTimingInfoKind_RF_Data,
    369 } ComputeTimingInfoKind;
    370 
    371 typedef struct {
    372 	u64 timer_count;
    373 	ComputeTimingInfoKind kind;
    374 	union {
    375 		struct {
    376 			static_assert(BeamformerShaderKind_Count <= U16_MAX, "");
    377 			u16 shader;
    378 			u16 shader_slot;
    379 		};
    380 	};
    381 } ComputeTimingInfo;
    382 
    383 typedef struct {
    384 	u32 write_index;
    385 	u32 read_index;
    386 	b32 compute_frame_active;
    387 
    388 	u32                  in_flight_shader_count;
    389 	BeamformerShaderKind in_flight_shader_ids[BeamformerMaxComputeShaderStages];
    390 
    391 	ComputeTimingInfo buffer[4096];
    392 } ComputeTimingTable;
    393 
    394 typedef struct {
    395 	BeamformerRFBuffer      *rf_buffer;
    396 	BeamformerSharedMemory  *shared_memory;
    397 	i64                      shared_memory_size;
    398 	ComputeTimingTable      *compute_timing_table;
    399 	i32                     *compute_worker_sync;
    400 } BeamformerUploadThreadContext;
    401 
    402 typedef struct {
    403 	u64 buffer_offset;
    404 	u64 timeline_valid_value;
    405 
    406 	/* NOTE: for use when displaying either prebeamformed frames or on the current frame
    407 	 * when we intend to recompute on the next frame */
    408 	m4  voxel_transform;
    409 
    410 	iv3 points;
    411 
    412 	u32                       id;
    413 	u32                       compound_count;
    414 	u32                       parameter_block;
    415 	BeamformerDataKind        data_kind;
    416 	BeamformerAcquisitionKind acquisition_kind;
    417 	BeamformerContrastMode    contrast_mode;
    418 	BeamformerViewPlaneTag    view_plane_tag;
    419 } BeamformerFrame;
    420 
    421 /* NOTE(rnp): backing storage for beamformed frames. The amount of backlog frames
    422 * is dependant on the currently requested output size. */
    423 typedef struct {
    424 	GPUBuffer   buffer[1];
    425 
    426 	u64         next_offset;
    427 	u64         counter;
    428 
    429 	BeamformerFrame frames[BeamformerMaxBacklogFrames];
    430 } BeamformerFrameBacklog;
    431 
    432 typedef struct {
    433 	BeamformerRFBuffer rf_buffer;
    434 
    435 	BeamformerComputePlan *compute_plans[BeamformerMaxParameterBlocks];
    436 	BeamformerComputePlan *compute_plan_freelist;
    437 
    438 	/* NOTE(rnp): used to ping pong data between compute stages.
    439 	 *
    440 	 * Allocate one extra slot for DAS output to allow overlap with the next
    441 	 * channel chunk batch. To obtain optimal overlap we need 2 extra slots
    442 	 * and we need to ping pong submissions between queues. This is not
    443 	 * implemented so we only do 1 extra slot for now.
    444 	 */
    445 	#define PING_PONG_BUFFER_SLOTS (2 + 1)
    446 	GPUBuffer ping_pong_buffer;
    447 	OSHandle  ping_pong_export_handle;
    448 	u32       ping_pong_input_index;
    449 
    450 	f32 processing_progress;
    451 	b32 processing_compute;
    452 
    453 	BeamformerFrameBacklog backlog;
    454 } BeamformerComputeContext;
    455 
    456 typedef struct {
    457 	OSThread handle;
    458 
    459 	Arena arena;
    460 	iptr  user_context;
    461 	i32   sync_variable;
    462 	b32   awake;
    463 } GLWorkerThreadContext;
    464 
    465 typedef struct {
    466 	str8                 name;
    467 	BeamformerRegisters *registers;
    468 } BeamformerCommand;
    469 
    470 typedef struct BeamformerRegistersNode BeamformerRegistersNode;
    471 struct BeamformerRegistersNode {
    472 	BeamformerRegistersNode *next;
    473 	BeamformerRegisters      v;
    474 };
    475 
    476 typedef struct BeamformerCommandNode BeamformerCommandNode;
    477 struct BeamformerCommandNode {
    478 	BeamformerCommandNode *next;
    479 	BeamformerCommandNode *prev;
    480 	BeamformerCommand      command;
    481 };
    482 
    483 typedef struct {
    484 	BeamformerCommandNode *first;
    485 	BeamformerCommandNode *last;
    486 	u64                    count;
    487 } BeamformerCommandList;
    488 
    489 typedef enum {
    490 	BeamformerState_Uninitialized = 0,
    491 	BeamformerState_Running,
    492 	BeamformerState_ShouldClose,
    493 	BeamformerState_Terminated,
    494 } BeamformerState;
    495 
    496 typedef enum {
    497 	RulerState_None,
    498 	RulerState_Start,
    499 	RulerState_Hold,
    500 	RulerState_Count,
    501 } RulerState;
    502 
    503 typedef struct {
    504 	v3 start;
    505 	v3 end;
    506 	RulerState state;
    507 } Ruler;
    508 
    509 typedef struct {
    510 	f32 t;
    511 	f32 scale;
    512 } BeamformerUIBlinker;
    513 
    514 #define BEAMFORMER_FRAME_VIEW_KIND_LIST \
    515 	X(Latest,   "Latest")     \
    516 	X(3DXPlane, "3D X-Plane") \
    517 	X(Copy,     "Copy")       \
    518 
    519 typedef enum {
    520 	#define X(kind, ...) BeamformerFrameViewKind_##kind,
    521 	BEAMFORMER_FRAME_VIEW_KIND_LIST
    522 	#undef X
    523 	BeamformerFrameViewKind_Count,
    524 } BeamformerFrameViewKind;
    525 
    526 typedef struct BeamformerFrameView BeamformerFrameView;
    527 struct BeamformerFrameView {
    528 	BeamformerFrameViewKind kind;
    529 	b32 dirty;
    530 
    531 	// NOTE(rnp): for FrameViewKindCopy
    532 	GPUBuffer copy_buffer;
    533 
    534 	GPUImage colour_image;
    535 	// NOTE(rnp): temporary, on w32 we must hold onto this when importing vulkan data to OpenGL
    536 	OSHandle export_handle;
    537 	u32      memory_object;
    538 	u32      texture;
    539 
    540 	b32 log_scale;
    541 	f32 threshold;
    542 	f32 dynamic_range;
    543 	f32 gamma;
    544 
    545 	union {
    546 		/* BeamformerFrameViewKind_Latest/BeamformerFrameViewKind_Copy */
    547 		struct {
    548 			b32   scale_bar_active[2];
    549 			Ruler ruler;
    550 			BeamformerViewPlaneTag view_plane;
    551 			BeamformerFrame frame;
    552 		};
    553 
    554 		/* BeamformerFrameViewKind_3DXPlane */
    555 		struct {
    556 			f32 hot_t[BeamformerViewPlaneTag_Count];
    557 			//b32 plane_active[BeamformerViewPlaneTag_Count];
    558 			b32 plane_active[BeamformerViewPlaneTag_Count - 2];
    559 			i32 plane_drag_index;
    560 			f32 rotation;
    561 			b32 demo;
    562 			v3  hit_start_point;
    563 			v3  hit_test_point;
    564 		};
    565 	};
    566 
    567 	BeamformerFrameView *prev, *next;
    568 };
    569 
    570 typedef struct BeamformerUIPanel BeamformerUIPanel;
    571 struct BeamformerUIPanel {
    572 	BeamformerUIPanel *parent;
    573 	BeamformerUIPanel *last_child;
    574 	BeamformerUIPanel *first_child;
    575 	BeamformerUIPanel *previous_sibling;
    576 	BeamformerUIPanel *next_sibling;
    577 
    578 	u64 child_count;
    579 
    580 	BeamformerPanelKind kind;
    581 	union {
    582 		BeamformerFrameView *frame_view;
    583 
    584 		BeamformerUIPanel *tab_focus;
    585 
    586 		BeamformerUIBlinker compute_stats_broken_shader_blinker;
    587 		BeamformerUIBlinker live_imaging_save_button_blinker;
    588 
    589 		struct {
    590 			u32 parameter_block;
    591 			b16 expand_coordinate[2];
    592 		} parameter_listing;
    593 
    594 		struct {
    595 			Axis2 axis;
    596 			f32   fraction;
    597 		} split;
    598 	} u;
    599 };
    600 
    601 typedef struct {
    602 	BeamformerState state;
    603 
    604 	iv2 window_size;
    605 
    606 	Arena  arena;
    607 	Arena  ui_backing_store;
    608 	void  *ui;
    609 	u32    ui_dirty_parameter_blocks;
    610 
    611 	u64       frame_timestamp;
    612 	u64       frame_index;
    613 	Arena     frame_arenas[2];
    614 	TempArena frame_arena_savepoints[2];
    615 
    616 	BeamformerUIPanel *auto_live_control_panel;
    617 	u64                live_imaging_active_frame;
    618 	b32                live_imaging_active;
    619 
    620 	BeamformerRegistersNode  base_registers;
    621 	BeamformerRegistersNode *registers;
    622 
    623 	BeamformerCommandList command_queues[2];
    624 
    625 	Stream error_stream;
    626 
    627 	BeamformerSharedMemory *shared_memory;
    628 	i64                     shared_memory_size;
    629 
    630 	BeamformerFrame *latest_frame;
    631 
    632 	// TODO(rnp): track elsewhere
    633 	b32 render_shader_updated;
    634 
    635 	/* NOTE: this will only be used when we are averaging */
    636 	u32             averaged_frame_index;
    637 	BeamformerFrame averaged_frames[2];
    638 
    639 	GLWorkerThreadContext  upload_worker;
    640 	GLWorkerThreadContext  compute_worker;
    641 
    642 	BeamformerComputeContext compute_context;
    643 
    644 	ComputeShaderStats compute_shader_stats[1];
    645 	ComputeTimingTable compute_timing_table[1];
    646 
    647 	BeamformWorkQueue  beamform_work_queue[1];
    648 
    649 	// TODO(rnp): this should go to the UI eventually
    650 	OSWindow main_window;
    651 } BeamformerCtx;
    652 #define BeamformerContextMemory(m) (BeamformerCtx *)align_pointer_up((m), alignof(BeamformerCtx));
    653 
    654 typedef enum {
    655 	BeamformerFileReloadKind_ComputeInternalShader,
    656 	BeamformerFileReloadKind_ComputeShader,
    657 	BeamformerFileReloadKind_RenderShader,
    658 } BeamformerFileReloadKind;
    659 
    660 typedef struct {
    661 	BeamformerShaderKind shader;
    662 	VulkanHandle *       pipeline;
    663 } BeamformerShaderReloadData;
    664 
    665 typedef struct {
    666 	BeamformerShaderKind  shader;
    667 	VulkanShaderKind      shader_kind;
    668 
    669 	// NOTE(rnp): based on BakeShaders compile time value
    670 	str8                  filename_or_data;
    671 
    672 	BeamformerShaderDescriptor *shader_descriptor;
    673 
    674 	uv3 layout;
    675 } BeamformerShaderReloadInfo;
    676 
    677 typedef struct {
    678 	BeamformerFileReloadKind kind;
    679 	union {
    680 		BeamformerShaderReloadData shader_reload;
    681 	};
    682 } BeamformerFileReloadContext;
    683 
    684 #define BEAMFORMER_COMPLETE_COMPUTE_FN(name) void name(BeamformerCtx *ctx, Arena *arena)
    685 typedef BEAMFORMER_COMPLETE_COMPUTE_FN(beamformer_complete_compute_fn);
    686 
    687 #define BEAMFORMER_RF_UPLOAD_FN(name) void name(BeamformerUploadThreadContext *ctx)
    688 typedef BEAMFORMER_RF_UPLOAD_FN(beamformer_rf_upload_fn);
    689 
    690 #define BEAMFORMER_DEBUG_UI_DEINIT_FN(name) void name(BeamformerCtx *ctx)
    691 typedef BEAMFORMER_DEBUG_UI_DEINIT_FN(beamformer_debug_ui_deinit_fn);
    692 
    693 #endif /* BEAMFORMER_INTERNAL_H */