Commit: 2c765d746b92c2f5bd2443ed546abd8e2aaeb86e
Parent: 2d06c4b2b5174951a64d9b72f828b71d42958f69
Author: Randy Palamar
Date: Sat, 31 May 2025 22:24:47 -0600
core: use common path for shader reloading
Diffstat:
11 files changed, 267 insertions(+), 234 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -9,6 +9,7 @@
* - In particular we will potentially need multiple GPUComputeContexts so that we
* can overwrite one while the other is in use.
* - make use of glFenceSync to guard buffer uploads
+ * [ ]: BeamformWorkQueue -> BeamformerWorkQueue
*/
#include "beamformer.h"
@@ -267,7 +268,7 @@ compute_cursor_finished(struct compute_cursor *cursor)
}
function void
-do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformComputeFrame *frame, ComputeShaderID shader)
+do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformComputeFrame *frame, ShaderKind shader)
{
ComputeShaderCtx *csctx = &ctx->csctx;
@@ -277,9 +278,9 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformComputeFrame *frame,
u32 input_ssbo_idx = csctx->last_output_ssbo_index;
switch (shader) {
- case CS_DECODE:
- case CS_DECODE_FLOAT:
- case CS_DECODE_FLOAT_COMPLEX:
+ case ShaderKind_Decode:
+ case ShaderKind_DecodeFloat:
+ case ShaderKind_DecodeFloatComplex:{
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, csctx->raw_data_ssbo);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, csctx->rf_data_ssbos[output_ssbo_idx]);
glBindImageTexture(0, csctx->hadamard_texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8I);
@@ -288,24 +289,24 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformComputeFrame *frame,
ORONE(csctx->dec_data_dim.y / 32),
ORONE(csctx->dec_data_dim.z));
csctx->last_output_ssbo_index = !csctx->last_output_ssbo_index;
- break;
- case CS_CUDA_DECODE:
+ }break;
+ case ShaderKind_CudaDecode:{
ctx->cuda_lib.decode(0, output_ssbo_idx, 0);
csctx->last_output_ssbo_index = !csctx->last_output_ssbo_index;
- break;
- case CS_CUDA_HILBERT:
+ }break;
+ case ShaderKind_CudaHilbert:
ctx->cuda_lib.hilbert(input_ssbo_idx, output_ssbo_idx);
csctx->last_output_ssbo_index = !csctx->last_output_ssbo_index;
break;
- case CS_DEMOD:
+ case ShaderKind_Demodulate:{
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, csctx->rf_data_ssbos[input_ssbo_idx]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, csctx->rf_data_ssbos[output_ssbo_idx]);
glDispatchCompute(ORONE(csctx->dec_data_dim.x / 32),
ORONE(csctx->dec_data_dim.y / 32),
ORONE(csctx->dec_data_dim.z));
csctx->last_output_ssbo_index = !csctx->last_output_ssbo_index;
- break;
- case CS_MIN_MAX: {
+ }break;
+ case ShaderKind_MinMax:{
u32 texture = frame->frame.texture;
for (u32 i = 1; i < frame->frame.mips; i++) {
glBindImageTexture(0, texture, i - 1, GL_TRUE, 0, GL_READ_ONLY, GL_RG32F);
@@ -318,8 +319,8 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformComputeFrame *frame,
glDispatchCompute(ORONE(width / 32), ORONE(height), ORONE(depth / 32));
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
}
- } break;
- case CS_DAS: {
+ }break;
+ case ShaderKind_DASCompute:{
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, csctx->rf_data_ssbos[input_ssbo_idx]);
glBindImageTexture(0, frame->frame.texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RG32F);
glBindImageTexture(1, csctx->sparse_elements_texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16I);
@@ -354,8 +355,8 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformComputeFrame *frame,
ORONE(frame->frame.dim.z / 32));
#endif
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT|GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
- } break;
- case CS_SUM: {
+ }break;
+ case ShaderKind_Sum:{
u32 aframe_index = ctx->averaged_frame_index % ARRAY_COUNT(ctx->averaged_frames);
BeamformComputeFrame *aframe = ctx->averaged_frames + aframe_index;
aframe->ready_to_present = 0;
@@ -377,34 +378,23 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformComputeFrame *frame,
do_sum_shader(csctx, in_textures, frame_count, 1 / (f32)frame_count,
aframe->frame.texture, aframe->frame.dim);
- aframe->frame.min_coordinate = frame->frame.min_coordinate;
- aframe->frame.max_coordinate = frame->frame.max_coordinate;
- aframe->frame.compound_count = frame->frame.compound_count;
- aframe->frame.das_shader_id = frame->frame.das_shader_id;
- } break;
- default: ASSERT(0);
+ aframe->frame.min_coordinate = frame->frame.min_coordinate;
+ aframe->frame.max_coordinate = frame->frame.max_coordinate;
+ aframe->frame.compound_count = frame->frame.compound_count;
+ aframe->frame.das_shader_kind = frame->frame.das_shader_kind;
+ }break;
+ InvalidDefaultCase;
}
}
function s8
-push_compute_shader_header(Arena *a, b32 parameters, ComputeShaderID shader)
+shader_text_with_header(ShaderReloadContext *ctx, OS *os, Arena *arena, char *path)
{
- Stream sb = arena_stream(*a);
-
- stream_append_s8(&sb, s8("#version 460 core\n\n"));
-
- #define X(name, type, size, gltype, glsize, comment) "\t" #gltype " " #name #glsize "; " comment "\n"
- if (parameters) {
- stream_append_s8(&sb, s8("layout(std140, binding = 0) uniform parameters {\n"
- BEAMFORMER_PARAMS_HEAD
- BEAMFORMER_UI_PARAMS
- BEAMFORMER_PARAMS_TAIL
- "};\n\n"));
- }
- #undef X
+ Stream sb = arena_stream(*arena);
+ stream_append_s8s(&sb, s8("#version 460 core\n\n"), ctx->header);
- switch (shader) {
- case CS_DAS: {
+ switch (ctx->kind) {
+ case ShaderKind_DASCompute:{
#define X(type, id, pretty, fixed_tx) "#define DAS_ID_" #type " " #id "\n"
stream_append_s8(&sb, s8(""
"layout(local_size_x = " str(DAS_LOCAL_SIZE_X) ", "
@@ -415,58 +405,76 @@ push_compute_shader_header(Arena *a, b32 parameters, ComputeShaderID shader)
DAS_TYPES
));
#undef X
- } break;
- case CS_DECODE_FLOAT:
- case CS_DECODE_FLOAT_COMPLEX: {
- if (shader == CS_DECODE_FLOAT) stream_append_s8(&sb, s8("#define INPUT_DATA_TYPE_FLOAT\n\n"));
- else stream_append_s8(&sb, s8("#define INPUT_DATA_TYPE_FLOAT_COMPLEX\n\n"));
+ }break;
+ case ShaderKind_DecodeFloat:
+ case ShaderKind_DecodeFloatComplex:{
+ if (ctx->kind == ShaderKind_DecodeFloat)
+ stream_append_s8(&sb, s8("#define INPUT_DATA_TYPE_FLOAT\n\n"));
+ else
+ stream_append_s8(&sb, s8("#define INPUT_DATA_TYPE_FLOAT_COMPLEX\n\n"));
} /* FALLTHROUGH */
- case CS_DECODE: {
+ case ShaderKind_Decode:{
#define X(type, id, pretty) stream_append_s8(&sb, s8("#define DECODE_MODE_" #type " " #id "\n"));
DECODE_TYPES
#undef X
- } break;
- case CS_MIN_MAX: {
+ }break;
+ case ShaderKind_MinMax:{
stream_append_s8(&sb, s8("layout(location = " str(CS_MIN_MAX_MIPS_LEVEL_UNIFORM_LOC)
") uniform int u_mip_map;\n\n"));
- } break;
- case CS_SUM: {
+ }break;
+ case ShaderKind_Sum:{
stream_append_s8(&sb, s8("layout(location = " str(CS_SUM_PRESCALE_UNIFORM_LOC)
") uniform float u_sum_prescale = 1.0;\n\n"));
- } break;
- default: break;
+ }break;
+ default:{}break;
}
stream_append_s8(&sb, s8("\n#line 1\n"));
- return arena_stream_commit(a, &sb);
+
+ s8 result = arena_stream_commit(arena, &sb);
+ if (path) {
+ s8 file = os->read_whole_file(arena, path);
+ assert(file.data == result.data + result.len);
+ result.len += file.len;
+ }
+
+ return result;
}
-function b32
-reload_compute_shader(BeamformerCtx *ctx, s8 path, s8 extra, ComputeShaderReloadContext *csr, Arena tmp)
+DEBUG_EXPORT BEAMFORMER_RELOAD_SHADER_FN(beamformer_reload_shader)
{
- ComputeShaderCtx *cs = &ctx->csctx;
- b32 result = 0;
+ i32 shader_count = 1 + (src->link != 0);
+ s8 *shader_texts = push_array(&arena, s8, shader_count);
+ u32 *shader_types = push_array(&arena, u32, shader_count);
- /* NOTE: arena works as stack (since everything here is 1 byte aligned) */
- s8 header = push_compute_shader_header(&tmp, csr->needs_header, csr->shader);
- s8 shader_text = ctx->os.read_whole_file(&tmp, (c8 *)path.data);
- shader_text.data -= header.len;
- shader_text.len += header.len;
-
- if (shader_text.data == header.data) {
- Stream sb = arena_stream(tmp);
- stream_append_s8s(&sb, path, extra);
- s8 info = arena_stream_commit(&tmp, &sb);
- u32 new_program = load_shader(&ctx->os, tmp, (s8 []){shader_text},
- (u32 []){GL_COMPUTE_SHADER}, 1, info);
- if (new_program) {
- glDeleteProgram(cs->programs[csr->shader]);
- cs->programs[csr->shader] = new_program;
- glUseProgram(cs->programs[csr->shader]);
- glBindBufferBase(GL_UNIFORM_BUFFER, 0, cs->shared_ubo);
- }
+ if (src->link) {
+ shader_texts[0] = shader_text_with_header(src->link, &ctx->os, &arena, (c8 *)src->link->path.data);
+ shader_types[0] = src->link->gl_type;
+ }
+ shader_texts[shader_count - 1] = shader_text_with_header(src, &ctx->os, &arena, (c8 *)src->path.data);
+ shader_types[shader_count - 1] = src->gl_type;
+
+ u32 new_program = load_shader(&ctx->os, arena, shader_texts, shader_types, shader_count, shader_name);
+ if (new_program) {
+ glDeleteProgram(*src->shader);
+ *src->shader = new_program;
+ if (src->kind == ShaderKind_Render2D) ctx->frame_view_render_context.updated = 1;
+ }
+ return new_program != 0;
+}
+
+function b32
+reload_compute_shader(BeamformerCtx *ctx, ShaderReloadContext *src, s8 name_extra, Arena arena)
+{
+ Stream sb = arena_stream(arena);
+ stream_append_s8s(&sb, src->name, name_extra);
+ s8 name = arena_stream_commit(&arena, &sb);
+ b32 result = beamformer_reload_shader(ctx, src, arena, name);
+ if (result) {
+ glUseProgram(*src->shader);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, ctx->csctx.shared_ubo);
} else {
- Stream sb = arena_stream(tmp);
- stream_append_s8s(&sb, s8("failed to load: "), path, extra, s8("\n"));
+ sb.widx = 0;
+ stream_append_s8s(&sb, s8("failed to load: "), src->path, name_extra, s8("\n"));
ctx->os.write_file(ctx->os.error_handle, stream_to_s8(&sb));
}
@@ -485,15 +493,18 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena arena, iptr gl_co
b32 can_commit = 1;
switch (work->type) {
case BW_RELOAD_SHADER: {
- ComputeShaderReloadContext *csr = work->reload_shader_ctx;
- b32 success = reload_compute_shader(ctx, csr->path, s8(""), csr, arena);
- if (csr->shader == CS_DECODE) {
+ ShaderReloadContext *src = work->shader_reload_context;
+ b32 success = reload_compute_shader(ctx, src, s8(""), arena);
+ if (src->kind == ShaderKind_Decode) {
/* TODO(rnp): think of a better way of doing this */
- csr->shader = CS_DECODE_FLOAT_COMPLEX;
- success &= reload_compute_shader(ctx, csr->path, s8(" (F32C)"), csr, arena);
- csr->shader = CS_DECODE_FLOAT;
- success &= reload_compute_shader(ctx, csr->path, s8(" (F32)"), csr, arena);
- csr->shader = CS_DECODE;
+ src->kind = ShaderKind_DecodeFloatComplex;
+ src->shader = cs->programs + ShaderKind_DecodeFloatComplex;
+ success &= reload_compute_shader(ctx, src, s8(" (F32C)"), arena);
+ src->kind = ShaderKind_DecodeFloat;
+ src->shader = cs->programs + ShaderKind_DecodeFloat;
+ success &= reload_compute_shader(ctx, src, s8(" (F32)"), arena);
+ src->kind = ShaderKind_Decode;
+ src->shader = cs->programs + ShaderKind_Decode;
}
if (success) {
@@ -576,19 +587,19 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena arena, iptr gl_co
}
frame->in_flight = 1;
- frame->frame.min_coordinate = v4_from_f32_array(bp->output_min_coordinate);
- frame->frame.max_coordinate = v4_from_f32_array(bp->output_max_coordinate);
- frame->frame.das_shader_id = bp->das_shader_id;
- frame->frame.compound_count = bp->dec_data_dim[2];
+ frame->frame.min_coordinate = v4_from_f32_array(bp->output_min_coordinate);
+ frame->frame.max_coordinate = v4_from_f32_array(bp->output_max_coordinate);
+ frame->frame.das_shader_kind = bp->das_shader_id;
+ frame->frame.compound_count = bp->dec_data_dim[2];
b32 did_sum_shader = 0;
- u32 stage_count = sm->compute_stages_count;
- ComputeShaderID *stages = sm->compute_stages;
+ u32 stage_count = sm->compute_stages_count;
+ ComputeShaderKind *stages = sm->compute_stages;
for (u32 i = 0; i < stage_count; i++) {
- did_sum_shader |= stages[i] == CS_SUM;
+ did_sum_shader |= stages[i] == ComputeShaderKind_Sum;
frame->stats.timer_active[stages[i]] = 1;
glBeginQuery(GL_TIME_ELAPSED, frame->stats.timer_ids[stages[i]]);
- do_compute_shader(ctx, arena, frame, stages[i]);
+ do_compute_shader(ctx, arena, frame, (ShaderKind)stages[i]);
glEndQuery(GL_TIME_ELAPSED);
}
/* NOTE(rnp): block until work completes so that we can record timings */
diff --git a/beamformer.h b/beamformer.h
@@ -78,7 +78,7 @@ typedef struct {
#define CS_SUM_PRESCALE_UNIFORM_LOC 1
typedef struct {
- u32 programs[CS_LAST];
+ u32 programs[ComputeShaderKind_Count];
/* NOTE: Decoded data is only relevant in the context of a single frame. We use two
* buffers so that they can be swapped when chaining multiple compute stages */
@@ -101,19 +101,27 @@ typedef struct {
} ComputeShaderCtx;
typedef enum {
-#define X(type, id, pretty, fixed_tx) DAS_ ##type = id,
-DAS_TYPES
-#undef X
-DAS_LAST
-} DASShaderID;
+ #define X(type, id, pretty, fixed_tx) DASShaderKind_##type = id,
+ DAS_TYPES
+ #undef X
+ DASShaderKind_Count
+} DASShaderKind;
+
+typedef enum {
+ #define X(e, n, s, h, pn) ShaderKind_##e = n,
+ COMPUTE_SHADERS
+ #undef X
+ ShaderKind_Render2D,
+ ShaderKind_Count
+} ShaderKind;
typedef struct {
/* TODO(rnp): there is assumption here that each shader will occur only once
* per compute. add an insertion index and change these to hold the max number
* of executed compute stages */
- u32 timer_ids[CS_LAST];
- f32 times[CS_LAST];
- b32 timer_active[CS_LAST];
+ u32 timer_ids[ComputeShaderKind_Count];
+ f32 times[ComputeShaderKind_Count];
+ b32 timer_active[ComputeShaderKind_Count];
} ComputeShaderStats;
typedef struct BeamformFrame {
@@ -126,7 +134,7 @@ typedef struct BeamformFrame {
v4 max_coordinate;
u32 mips;
- DASShaderID das_shader_id;
+ DASShaderKind das_shader_kind;
u32 compound_count;
u32 id;
@@ -196,11 +204,15 @@ typedef struct {
BeamformerSharedMemory *shared_memory;
} BeamformerCtx;
-struct ComputeShaderReloadContext {
- BeamformerCtx *beamformer_ctx;
- s8 path;
- b32 needs_header;
- ComputeShaderID shader;
+struct ShaderReloadContext {
+ BeamformerCtx *beamformer_context;
+ s8 path;
+ s8 name;
+ s8 header;
+ u32 *shader;
+ ShaderReloadContext *link;
+ GLenum gl_type;
+ ShaderKind kind;
};
#define BEAMFORMER_FRAME_STEP_FN(name) void name(BeamformerCtx *ctx, Arena *arena, \
@@ -213,4 +225,8 @@ typedef BEAMFORMER_COMPUTE_SETUP_FN(beamformer_compute_setup_fn);
#define BEAMFORMER_COMPLETE_COMPUTE_FN(name) void name(iptr user_context, Arena arena, iptr gl_context)
typedef BEAMFORMER_COMPLETE_COMPUTE_FN(beamformer_complete_compute_fn);
+#define BEAMFORMER_RELOAD_SHADER_FN(name) b32 name(BeamformerCtx *ctx, ShaderReloadContext *src, \
+ Arena arena, s8 shader_name)
+typedef BEAMFORMER_RELOAD_SHADER_FN(beamformer_reload_shader_fn);
+
#endif /*_BEAMFORMER_H_ */
diff --git a/beamformer_parameters.h b/beamformer_parameters.h
@@ -11,22 +11,22 @@
/* X(enumarant, number, shader file name, needs header, pretty name) */
#define COMPUTE_SHADERS \
- X(CUDA_DECODE, 0, "", 0, "CUDA Decoding") \
- X(CUDA_HILBERT, 1, "", 0, "CUDA Hilbert") \
- X(DAS, 2, "das", 1, "DAS") \
- X(DECODE, 3, "decode", 1, "Decoding") \
- X(DECODE_FLOAT, 4, "", 1, "Decoding (F32)") \
- X(DECODE_FLOAT_COMPLEX, 5, "", 1, "Decoding (F32C)") \
- X(DEMOD, 6, "demod", 1, "Demodulation") \
- X(MIN_MAX, 7, "min_max", 0, "Min/Max") \
- X(SUM, 8, "sum", 0, "Sum")
+ X(CudaDecode, 0, "", 0, "CUDA Decode") \
+ X(CudaHilbert, 1, "", 0, "CUDA Hilbert") \
+ X(DASCompute, 2, "das", 1, "DAS") \
+ X(Decode, 3, "decode", 1, "Decode") \
+ X(DecodeFloat, 4, "", 1, "Decode (F32)") \
+ X(DecodeFloatComplex, 5, "", 1, "Decode (F32C)") \
+ X(Demodulate, 6, "demod", 1, "Demodulate") \
+ X(MinMax, 7, "min_max", 0, "Min/Max") \
+ X(Sum, 8, "sum", 0, "Sum")
typedef enum {
- #define X(e, n, s, h, pn) CS_ ##e = n,
+ #define X(e, n, s, h, pn) ComputeShaderKind_##e = n,
COMPUTE_SHADERS
#undef X
- CS_LAST
-} ComputeShaderID;
+ ComputeShaderKind_Count
+} ComputeShaderKind;
/* X(type, id, pretty name) */
#define DECODE_TYPES \
diff --git a/beamformer_work_queue.h b/beamformer_work_queue.h
@@ -3,7 +3,7 @@
#define _BEAMFORMER_WORK_QUEUE_H_
typedef struct BeamformComputeFrame BeamformComputeFrame;
-typedef struct ComputeShaderReloadContext ComputeShaderReloadContext;
+typedef struct ShaderReloadContext ShaderReloadContext;
typedef enum {
BW_COMPUTE,
@@ -39,7 +39,7 @@ typedef struct {
BeamformComputeFrame *frame;
BeamformerUploadContext upload_context;
BeamformOutputFrameContext output_frame_ctx;
- ComputeShaderReloadContext *reload_shader_ctx;
+ ShaderReloadContext *shader_reload_context;
void *generic;
};
/* NOTE(rnp): mostly for __external__ processes to sync on. when passed from external
@@ -84,8 +84,8 @@ typedef struct {
};
};
- ComputeShaderID compute_stages[MAX_COMPUTE_SHADER_STAGES];
- u32 compute_stages_count;
+ ComputeShaderKind compute_stages[MAX_COMPUTE_SHADER_STAGES];
+ u32 compute_stages_count;
i32 parameters_sync;
i32 parameters_head_sync;
diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c
@@ -227,10 +227,11 @@ set_beamformer_pipeline(i32 *stages, i32 stages_count)
if (stages_count <= countof(g_bp->compute_stages)) {
if (check_shared_memory()) {
g_bp->compute_stages_count = 0;
- for (i32 i = 0; i < stages_count; i++)
- if (BETWEEN(stages[i], 0, CS_LAST))
+ for (i32 i = 0; i < stages_count; i++) {
+ if (BETWEEN(stages[i], 0, ComputeShaderKind_Count)) {
g_bp->compute_stages[g_bp->compute_stages_count++] = stages[i];
-
+ }
+ }
result = g_bp->compute_stages_count == stages_count;
if (!result) {
g_lib_last_error = BF_LIB_ERR_KIND_INVALID_COMPUTE_STAGE;
diff --git a/shaders/render.glsl b/shaders/render.glsl
@@ -1,37 +0,0 @@
-/* See LICENSE for license details. */
-layout(binding = 0) uniform sampler3D u_out_data_tex;
-
-/* input: h [0,360] | s,v [0, 1] *
- * output: rgb [0,1] */
-vec3 hsv2rgb(vec3 hsv)
-{
- vec3 k = mod(vec3(5, 3, 1) + hsv.x / 60, 6);
- k = max(min(min(k, 4 - k), 1), 0);
- return hsv.z - hsv.z * hsv.y * k;
-}
-
-void main()
-{
- ivec3 out_data_dim = textureSize(u_out_data_tex, 0);
-
- //vec2 min_max = texelFetch(u_out_data_tex, ivec3(0), textureQueryLevels(u_out_data_tex) - 1).xy;
-
- /* TODO(rnp): select between x and y and specify slice */
- ivec2 coord = ivec2(fragment_texture_coordinate * vec2(out_data_dim.xz));
- ivec3 smp_coord = ivec3(coord.x, out_data_dim.y / 2, coord.y);
- float smp = length(texelFetch(u_out_data_tex, smp_coord, 0).xy);
-
- float threshold_val = pow(10.0f, u_threshold / 20.0f);
- smp = clamp(smp, 0.0f, threshold_val);
- smp = smp / threshold_val;
- smp = pow(smp, u_gamma);
-
- if (u_log_scale) {
- smp = 20 * log(smp) / log(10);
- smp = clamp(smp, -u_db_cutoff, 0) / -u_db_cutoff;
- smp = 1 - smp;
- }
-
- //v_out_colour = vec4(hsv2rgb(vec3(360 * smp, 0.8, 0.95)), 1);
- v_out_colour = vec4(smp, smp, smp, 1);
-}
diff --git a/shaders/render_2d.frag.glsl b/shaders/render_2d.frag.glsl
@@ -0,0 +1,37 @@
+/* See LICENSE for license details. */
+layout(binding = 0) uniform sampler3D u_out_data_tex;
+
+/* input: h [0,360] | s,v [0, 1] *
+ * output: rgb [0,1] */
+vec3 hsv2rgb(vec3 hsv)
+{
+ vec3 k = mod(vec3(5, 3, 1) + hsv.x / 60, 6);
+ k = max(min(min(k, 4 - k), 1), 0);
+ return hsv.z - hsv.z * hsv.y * k;
+}
+
+void main()
+{
+ ivec3 out_data_dim = textureSize(u_out_data_tex, 0);
+
+ //vec2 min_max = texelFetch(u_out_data_tex, ivec3(0), textureQueryLevels(u_out_data_tex) - 1).xy;
+
+ /* TODO(rnp): select between x and y and specify slice */
+ ivec2 coord = ivec2(texture_coordinate * vec2(out_data_dim.xz));
+ ivec3 smp_coord = ivec3(coord.x, out_data_dim.y / 2, coord.y);
+ float smp = length(texelFetch(u_out_data_tex, smp_coord, 0).xy);
+
+ float threshold_val = pow(10.0f, u_threshold / 20.0f);
+ smp = clamp(smp, 0.0f, threshold_val);
+ smp = smp / threshold_val;
+ smp = pow(smp, u_gamma);
+
+ if (u_log_scale) {
+ smp = 20 * log(smp) / log(10);
+ smp = clamp(smp, -u_db_cutoff, 0) / -u_db_cutoff;
+ smp = 1 - smp;
+ }
+
+ //v_out_colour = vec4(hsv2rgb(vec3(360 * smp, 0.8, 0.95)), 1);
+ v_out_colour = vec4(smp, smp, smp, 1);
+}
diff --git a/static.c b/static.c
@@ -11,6 +11,7 @@ global void *debug_lib;
X(beamformer_frame_step) \
X(beamformer_complete_compute) \
X(beamformer_compute_setup) \
+ X(beamformer_reload_shader) \
X(beamform_work_queue_push) \
X(beamform_work_queue_push_commit)
@@ -21,7 +22,7 @@ DEBUG_ENTRY_POINTS
function FILE_WATCH_CALLBACK_FN(debug_reload)
{
BeamformerInput *input = (BeamformerInput *)user_data;
- Stream err = arena_stream(tmp);
+ Stream err = arena_stream(arena);
/* NOTE(rnp): spin until compute thread finishes its work (we will probably
* never reload while compute is in progress but just incase). */
@@ -180,60 +181,22 @@ dump_gl_params(GLParams *gl, Arena a, OS *os)
#endif
}
-function FILE_WATCH_CALLBACK_FN(reload_render_shader)
+function FILE_WATCH_CALLBACK_FN(reload_shader)
{
- FrameViewRenderContext *ctx = (typeof(ctx))user_data;
-
- local_persist s8 vertex = s8(""
- "#version 460 core\n"
- "\n"
- "layout(location = 0) in vec2 vertex_position;\n"
- "layout(location = 1) in vec2 vertex_texture_coordinate;\n"
- "\n"
- "layout(location = 0) out vec2 fragment_texture_coordinate;\n"
- "\n"
- "void main()\n"
- "{\n"
- "\tfragment_texture_coordinate = vertex_texture_coordinate;\n"
- "\tgl_Position = vec4(vertex_position, 0, 1);\n"
- "}\n");
-
- s8 header = push_s8(&tmp, s8(""
- "#version 460 core\n\n"
- "layout(location = 0) in vec2 fragment_texture_coordinate;\n"
- "layout(location = 0) out vec4 v_out_colour;\n\n"
- "layout(location = " str(FRAME_VIEW_RENDER_DYNAMIC_RANGE_LOC) ") uniform float u_db_cutoff = 60;\n"
- "layout(location = " str(FRAME_VIEW_RENDER_THRESHOLD_LOC) ") uniform float u_threshold = 40;\n"
- "layout(location = " str(FRAME_VIEW_RENDER_GAMMA_LOC) ") uniform float u_gamma = 1;\n"
- "layout(location = " str(FRAME_VIEW_RENDER_LOG_SCALE_LOC) ") uniform bool u_log_scale;\n"
- "\n#line 1\n"));
-
- s8 fragment = os->read_whole_file(&tmp, (c8 *)path.data);
- fragment.data -= header.len;
- fragment.len += header.len;
- ASSERT(fragment.data == header.data);
- u32 new_program = load_shader(os, tmp, (s8 []){vertex, fragment},
- (u32 []){GL_VERTEX_SHADER, GL_FRAGMENT_SHADER}, 2, path);
- if (new_program) {
- glDeleteProgram(ctx->shader);
- ctx->shader = new_program;
- ctx->updated = 1;
- }
-
- return 1;
+ ShaderReloadContext *ctx = (typeof(ctx))user_data;
+ return beamformer_reload_shader(ctx->beamformer_context, ctx, arena, ctx->name);
}
-
-function FILE_WATCH_CALLBACK_FN(queue_compute_shader_reload)
+function FILE_WATCH_CALLBACK_FN(reload_shader_indirect)
{
- ComputeShaderReloadContext *csr = (typeof(csr))user_data;
- BeamformerCtx *ctx = csr->beamformer_ctx;
+ ShaderReloadContext *src = (typeof(src))user_data;
+ BeamformerCtx *ctx = src->beamformer_context;
BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue);
if (work) {
work->type = BW_RELOAD_SHADER;
- work->reload_shader_ctx = csr;
+ work->shader_reload_context = src;
beamform_work_queue_push_commit(ctx->beamform_work_queue);
- ctx->os.wake_waiters(&ctx->os.compute_worker.sync_variable);
+ os->wake_waiters(&os->compute_worker.sync_variable);
}
return 1;
}
@@ -243,7 +206,7 @@ function FILE_WATCH_CALLBACK_FN(load_cuda_lib)
CudaLib *cl = (CudaLib *)user_data;
b32 result = os_file_exists((c8 *)path.data);
if (result) {
- Stream err = arena_stream(tmp);
+ Stream err = arena_stream(arena);
stream_append_s8(&err, s8("loading CUDA lib: " OS_CUDA_LIB_NAME "\n"));
os_unload_library(cl->lib);
@@ -340,8 +303,8 @@ setup_beamformer(BeamformerCtx *ctx, Arena *memory)
ctx->shared_memory->focal_vectors_sync = 1;
/* NOTE: default compute shader pipeline */
- ctx->shared_memory->compute_stages[0] = CS_DECODE;
- ctx->shared_memory->compute_stages[1] = CS_DAS;
+ ctx->shared_memory->compute_stages[0] = ComputeShaderKind_Decode;
+ ctx->shared_memory->compute_stages[1] = ComputeShaderKind_DASCompute;
ctx->shared_memory->compute_stages_count = 2;
if (ctx->gl.vendor_id == GL_VENDOR_NVIDIA
@@ -364,14 +327,27 @@ setup_beamformer(BeamformerCtx *ctx, Arena *memory)
glEnable(GL_DEBUG_OUTPUT);
#endif
- #define X(e, sn, f, nh, pretty_name) do if (s8(f).len > 0) { \
- ComputeShaderReloadContext *csr = push_struct(memory, typeof(*csr)); \
- csr->beamformer_ctx = ctx; \
- csr->shader = sn; \
- csr->needs_header = nh; \
- csr->path = s8(static_path_join("shaders", f ".glsl")); \
- os_add_file_watch(&ctx->os, memory, csr->path, queue_compute_shader_reload, (iptr)csr); \
- queue_compute_shader_reload(&ctx->os, csr->path, (iptr)csr, *memory); \
+ #define X(name, type, size, gltype, glsize, comment) "\t" #gltype " " #name #glsize "; " comment "\n"
+ read_only local_persist s8 compute_parameters_header = s8(""
+ "layout(std140, binding = 0) uniform parameters {\n"
+ BEAMFORMER_PARAMS_HEAD
+ BEAMFORMER_UI_PARAMS
+ BEAMFORMER_PARAMS_TAIL
+ "};\n\n"
+ );
+ #undef X
+
+ #define X(e, sn, f, nh, pretty_name) do if (s8(f).len > 0) { \
+ ShaderReloadContext *src = push_struct(memory, typeof(*src)); \
+ src->beamformer_context = ctx; \
+ if (nh) src->header = compute_parameters_header; \
+ src->path = s8(static_path_join("shaders", f ".glsl")); \
+ src->name = src->path; \
+ src->shader = ctx->csctx.programs + ShaderKind_##e; \
+ src->gl_type = GL_COMPUTE_SHADER; \
+ src->kind = ShaderKind_##e; \
+ os_add_file_watch(&ctx->os, memory, src->path, reload_shader_indirect, (iptr)src); \
+ reload_shader_indirect(&ctx->os, src->path, (iptr)src, *memory); \
} while (0);
COMPUTE_SHADERS
#undef X
@@ -399,7 +375,34 @@ setup_beamformer(BeamformerCtx *ctx, Arena *memory)
glEnableVertexAttribArray(1);
glBindVertexArray(0);
- s8 render = s8(static_path_join("shaders", "render.glsl"));
- reload_render_shader(&ctx->os, render, (iptr)fvr, *memory);
- os_add_file_watch(&ctx->os, memory, render, reload_render_shader, (iptr)fvr);
+ ShaderReloadContext *render_2d = push_struct(memory, typeof(*render_2d));
+ render_2d->beamformer_context = ctx;
+ render_2d->path = s8(static_path_join("shaders", "render_2d.frag.glsl"));
+ render_2d->name = s8("shaders/render_2d.glsl");
+ render_2d->gl_type = GL_FRAGMENT_SHADER;
+ render_2d->kind = ShaderKind_Render2D;
+ render_2d->shader = &fvr->shader;
+ render_2d->header = s8(""
+ "layout(location = 0) in vec2 texture_coordinate;\n"
+ "layout(location = 0) out vec4 v_out_colour;\n\n"
+ "layout(location = " str(FRAME_VIEW_RENDER_DYNAMIC_RANGE_LOC) ") uniform float u_db_cutoff = 60;\n"
+ "layout(location = " str(FRAME_VIEW_RENDER_THRESHOLD_LOC) ") uniform float u_threshold = 40;\n"
+ "layout(location = " str(FRAME_VIEW_RENDER_GAMMA_LOC) ") uniform float u_gamma = 1;\n"
+ "layout(location = " str(FRAME_VIEW_RENDER_LOG_SCALE_LOC) ") uniform bool u_log_scale;\n"
+ "\n#line 1\n");
+ render_2d->link = push_struct(memory, typeof(*render_2d));
+ render_2d->link->gl_type = GL_VERTEX_SHADER;
+ render_2d->link->header = s8(""
+ "layout(location = 0) in vec2 v_position;\n"
+ "layout(location = 1) in vec2 v_texture_coordinate;\n"
+ "\n"
+ "layout(location = 0) out vec2 f_texture_coordinate;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ "\tf_texture_coordinate = v_texture_coordinate;\n"
+ "\tgl_Position = vec4(v_position, 0, 1);\n"
+ "}\n");
+ reload_shader(&ctx->os, render_2d->path, (iptr)render_2d, *memory);
+ os_add_file_watch(&ctx->os, memory, render_2d->path, reload_shader, (iptr)render_2d);
}
diff --git a/ui.c b/ui.c
@@ -1253,17 +1253,17 @@ lerp_v4(v4 a, v4 b, f32 t)
}
function s8
-push_das_shader_id(Stream *s, DASShaderID shader, u32 transmit_count)
+push_das_shader_kind(Stream *s, DASShaderKind shader, u32 transmit_count)
{
#define X(type, id, pretty, fixed_tx) s8(pretty),
- local_persist s8 pretty_names[DAS_LAST + 1] = {DAS_TYPES s8("Invalid")};
+ read_only local_persist s8 pretty_names[DASShaderKind_Count + 1] = {DAS_TYPES s8("Invalid")};
#undef X
#define X(type, id, pretty, fixed_tx) fixed_tx,
- local_persist u8 fixed_transmits[DAS_LAST + 1] = {DAS_TYPES 1};
+ read_only local_persist u8 fixed_transmits[DASShaderKind_Count + 1] = {DAS_TYPES 0};
#undef X
- stream_append_s8(s, pretty_names[MIN(shader, DAS_LAST)]);
- if (!fixed_transmits[MIN(shader, DAS_LAST)]) {
+ stream_append_s8(s, pretty_names[MIN(shader, DASShaderKind_Count)]);
+ if (!fixed_transmits[MIN(shader, DASShaderKind_Count)]) {
stream_append_byte(s, '-');
stream_append_u64(s, transmit_count);
}
@@ -1869,7 +1869,7 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa
{
Stream buf = arena_stream(a);
- s8 shader = push_das_shader_id(&buf, frame->das_shader_id, frame->compound_count);
+ s8 shader = push_das_shader_kind(&buf, frame->das_shader_kind, frame->compound_count);
text_spec.font = &ui->font;
text_spec.limits.size.w -= 16;
v2 txt_s = measure_text(*text_spec.font, shader);
@@ -1961,8 +1961,8 @@ draw_compute_progress_bar(BeamformerUI *ui, Arena arena, ComputeProgressBar *sta
function v2
draw_compute_stats_view(BeamformerCtx *ctx, Arena arena, ComputeShaderStats *stats, Rect r)
{
- #define X(e, n, s, h, pn) [CS_##e] = s8(pn ":"),
- local_persist s8 labels[CS_LAST] = { COMPUTE_SHADERS };
+ #define X(e, n, s, h, pn) [ComputeShaderKind_##e] = s8(pn ":"),
+ read_only local_persist s8 labels[ComputeShaderKind_Count] = { COMPUTE_SHADERS };
#undef X
BeamformerUI *ui = ctx->ui;
diff --git a/util.c b/util.c
@@ -123,7 +123,7 @@ end_temp_arena(TempArena ta)
{
Arena *a = ta.arena;
if (a) {
- ASSERT(a->beg >= ta.old_beg)
+ assert(a->beg >= ta.old_beg);
a->beg = ta.old_beg;
}
}
diff --git a/util.h b/util.h
@@ -28,15 +28,17 @@
#define DEBUG_EXPORT
#endif
#define DEBUG_DECL(a) a
- #define ASSERT(c) do { if (!(c)) debugbreak(); } while (0);
+ #define ASSERT(c) do { if (!(c)) debugbreak(); } while (0)
#else
#define DEBUG_EXPORT function
#define DEBUG_DECL(a)
#define ASSERT(c)
#endif
+#define assert ASSERT
#define INVALID_CODE_PATH ASSERT(0)
-#define INVALID_DEFAULT_CASE default: ASSERT(0) break
+#define INVALID_DEFAULT_CASE default: ASSERT(0); break
+#define InvalidDefaultCase default: assert(0); break
#define function static
#define global static
@@ -217,7 +219,7 @@ typedef struct {
b32 asleep;
} GLWorkerThreadContext;
-#define FILE_WATCH_CALLBACK_FN(name) b32 name(OS *os, s8 path, iptr user_data, Arena tmp)
+#define FILE_WATCH_CALLBACK_FN(name) b32 name(OS *os, s8 path, iptr user_data, Arena arena)
typedef FILE_WATCH_CALLBACK_FN(file_watch_callback);
typedef struct {