static.c (14344B)
1 /* See LICENSE for license details. */ 2 #ifndef _DEBUG 3 4 #include "beamformer.c" 5 #define debug_init(...) 6 7 #else 8 global void *debug_lib; 9 10 #define DEBUG_ENTRY_POINTS \ 11 X(beamformer_frame_step) \ 12 X(beamformer_complete_compute) \ 13 X(beamformer_compute_setup) \ 14 X(beamformer_reload_shader) \ 15 X(beamform_work_queue_push) \ 16 X(beamform_work_queue_push_commit) 17 18 #define X(name) global name ##_fn *name; 19 DEBUG_ENTRY_POINTS 20 #undef X 21 22 function FILE_WATCH_CALLBACK_FN(debug_reload) 23 { 24 BeamformerInput *input = (BeamformerInput *)user_data; 25 Stream err = arena_stream(arena); 26 27 /* NOTE(rnp): spin until compute thread finishes its work (we will probably 28 * never reload while compute is in progress but just incase). */ 29 while (!atomic_load(&os->compute_worker.asleep)); 30 31 os_unload_library(debug_lib); 32 debug_lib = os_load_library(OS_DEBUG_LIB_NAME, OS_DEBUG_LIB_TEMP_NAME, &err); 33 34 #define X(name) name = os_lookup_dynamic_symbol(debug_lib, #name, &err); 35 DEBUG_ENTRY_POINTS 36 #undef X 37 38 stream_append_s8(&err, s8("Reloaded Main Executable\n")); 39 os->write_file(os->error_handle, stream_to_s8(&err)); 40 41 input->executable_reloaded = 1; 42 43 return 1; 44 } 45 46 function void 47 debug_init(OS *os, iptr input, Arena *arena) 48 { 49 os->add_file_watch(os, arena, s8(OS_DEBUG_LIB_NAME), debug_reload, input); 50 debug_reload(os, s8(""), input, *arena); 51 52 Stream err = arena_stream(*arena); 53 void *rdoc = os_get_module(OS_RENDERDOC_SONAME, 0); 54 if (rdoc) { 55 renderdoc_get_api_fn *get_api = os_lookup_dynamic_symbol(rdoc, "RENDERDOC_GetAPI", &err); 56 if (get_api) { 57 RenderDocAPI *api = 0; 58 if (get_api(10600, (void **)&api)) { 59 os->start_frame_capture = RENDERDOC_START_FRAME_CAPTURE(api); 60 os->end_frame_capture = RENDERDOC_END_FRAME_CAPTURE(api); 61 stream_append_s8(&err, s8("loaded: " OS_RENDERDOC_SONAME "\n")); 62 } 63 } 64 } 65 66 os->write_file(os->error_handle, stream_to_s8(&err)); 67 } 68 69 #endif /* _DEBUG */ 70 71 #define static_path_join(a, b) (a OS_PATH_SEPARATOR b) 72 73 struct gl_debug_ctx { 74 Stream stream; 75 OS *os; 76 }; 77 78 function void 79 gl_debug_logger(u32 src, u32 type, u32 id, u32 lvl, i32 len, const char *msg, const void *userctx) 80 { 81 (void)src; (void)type; (void)id; 82 83 struct gl_debug_ctx *ctx = (struct gl_debug_ctx *)userctx; 84 Stream *e = &ctx->stream; 85 stream_append_s8(e, s8("[GL DEBUG ")); 86 switch (lvl) { 87 case GL_DEBUG_SEVERITY_HIGH: stream_append_s8(e, s8("HIGH]: ")); break; 88 case GL_DEBUG_SEVERITY_MEDIUM: stream_append_s8(e, s8("MEDIUM]: ")); break; 89 case GL_DEBUG_SEVERITY_LOW: stream_append_s8(e, s8("LOW]: ")); break; 90 case GL_DEBUG_SEVERITY_NOTIFICATION: stream_append_s8(e, s8("NOTIFICATION]: ")); break; 91 default: stream_append_s8(e, s8("INVALID]: ")); break; 92 } 93 stream_append(e, (char *)msg, len); 94 stream_append_byte(e, '\n'); 95 ctx->os->write_file(ctx->os->error_handle, stream_to_s8(e)); 96 stream_reset(e, 0); 97 } 98 99 function void 100 get_gl_params(GLParams *gl, Stream *err) 101 { 102 char *vendor = (char *)glGetString(GL_VENDOR); 103 if (!vendor) { 104 stream_append_s8(err, s8("Failed to determine GL Vendor\n")); 105 os_fatal(stream_to_s8(err)); 106 } 107 /* TODO(rnp): str prefix of */ 108 switch (vendor[0]) { 109 case 'A': gl->vendor_id = GL_VENDOR_AMD; break; 110 case 'I': gl->vendor_id = GL_VENDOR_INTEL; break; 111 case 'N': gl->vendor_id = GL_VENDOR_NVIDIA; break; 112 /* NOTE(rnp): freedreno */ 113 case 'f': gl->vendor_id = GL_VENDOR_ARM; break; 114 /* NOTE(rnp): Microsoft Corporation - weird win32 thing (microsoft is just using mesa for the driver) */ 115 case 'M': gl->vendor_id = GL_VENDOR_ARM; break; 116 default: 117 stream_append_s8s(err, s8("Unknown GL Vendor: "), c_str_to_s8(vendor), s8("\n")); 118 os_fatal(stream_to_s8(err)); 119 } 120 121 #define X(glname, name, suffix) glGetIntegerv(GL_##glname, &gl->name); 122 GL_PARAMETERS 123 #undef X 124 125 /* NOTE(rnp): sometimes GL_MINOR_VERSION doesn't actually report the drivers 126 * supported version. Since at this point GL has been fully loaded we can 127 * check that at least one of the GL 4.5 function pointers are available */ 128 if (gl->version_minor < 5 && glCreateBuffers) 129 gl->version_minor = 5; 130 } 131 132 function void 133 validate_gl_requirements(GLParams *gl, Arena a) 134 { 135 Stream s = arena_stream(a); 136 137 if (gl->max_ubo_size < sizeof(BeamformerParameters)) { 138 stream_append_s8(&s, s8("GPU must support UBOs of at least ")); 139 stream_append_i64(&s, sizeof(BeamformerParameters)); 140 stream_append_s8(&s, s8(" bytes!\n")); 141 } 142 143 if (gl->version_major < 4 || (gl->version_major == 4 && gl->version_minor < 5)) 144 stream_append_s8(&s, s8("Only OpenGL Versions 4.5 or newer are supported!\n")); 145 146 if (s.widx) os_fatal(stream_to_s8(&s)); 147 } 148 149 function void 150 dump_gl_params(GLParams *gl, Arena a, OS *os) 151 { 152 (void)gl; (void)a; 153 #ifdef _DEBUG 154 s8 vendor = s8("vendor:"); 155 iz max_width = vendor.len; 156 #define X(glname, name, suffix) if (s8(#name).len > max_width) max_width = s8(#name ":").len; 157 GL_PARAMETERS 158 #undef X 159 max_width++; 160 161 Stream s = arena_stream(a); 162 stream_append_s8s(&s, s8("---- GL Parameters ----\n"), vendor); 163 stream_pad(&s, ' ', max_width - vendor.len); 164 switch (gl->vendor_id) { 165 case GL_VENDOR_AMD: stream_append_s8(&s, s8("AMD\n")); break; 166 case GL_VENDOR_ARM: stream_append_s8(&s, s8("ARM\n")); break; 167 case GL_VENDOR_INTEL: stream_append_s8(&s, s8("Intel\n")); break; 168 case GL_VENDOR_NVIDIA: stream_append_s8(&s, s8("nVidia\n")); break; 169 } 170 171 #define X(glname, name, suffix) \ 172 stream_append_s8(&s, s8(#name ":")); \ 173 stream_pad(&s, ' ', max_width - s8(#name ":").len); \ 174 stream_append_i64(&s, gl->name); \ 175 stream_append_s8(&s, s8(suffix)); \ 176 stream_append_byte(&s, '\n'); 177 GL_PARAMETERS 178 #undef X 179 stream_append_s8(&s, s8("-----------------------\n")); 180 os->write_file(os->error_handle, stream_to_s8(&s)); 181 #endif 182 } 183 184 function FILE_WATCH_CALLBACK_FN(reload_shader) 185 { 186 ShaderReloadContext *ctx = (typeof(ctx))user_data; 187 return beamformer_reload_shader(ctx->beamformer_context, ctx, arena, ctx->name); 188 } 189 190 function FILE_WATCH_CALLBACK_FN(reload_shader_indirect) 191 { 192 ShaderReloadContext *src = (typeof(src))user_data; 193 BeamformerCtx *ctx = src->beamformer_context; 194 BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue); 195 if (work) { 196 work->type = BW_RELOAD_SHADER; 197 work->shader_reload_context = src; 198 beamform_work_queue_push_commit(ctx->beamform_work_queue); 199 os->wake_waiters(&os->compute_worker.sync_variable); 200 } 201 return 1; 202 } 203 204 function FILE_WATCH_CALLBACK_FN(load_cuda_lib) 205 { 206 CudaLib *cl = (CudaLib *)user_data; 207 b32 result = os_file_exists((c8 *)path.data); 208 if (result) { 209 Stream err = arena_stream(arena); 210 211 stream_append_s8(&err, s8("loading CUDA lib: " OS_CUDA_LIB_NAME "\n")); 212 os_unload_library(cl->lib); 213 cl->lib = os_load_library((c8 *)path.data, OS_CUDA_LIB_TEMP_NAME, &err); 214 #define X(name, symname) cl->name = os_lookup_dynamic_symbol(cl->lib, symname, &err); 215 CUDA_LIB_FNS 216 #undef X 217 218 os->write_file(os->error_handle, stream_to_s8(&err)); 219 } 220 221 #define X(name, symname) if (!cl->name) cl->name = cuda_ ## name ## _stub; 222 CUDA_LIB_FNS 223 #undef X 224 225 return result; 226 } 227 228 229 #define GLFW_VISIBLE 0x00020004 230 void glfwWindowHint(i32, i32); 231 iptr glfwCreateWindow(i32, i32, char *, iptr, iptr); 232 void glfwMakeContextCurrent(iptr); 233 234 function OS_THREAD_ENTRY_POINT_FN(compute_worker_thread_entry_point) 235 { 236 GLWorkerThreadContext *ctx = (GLWorkerThreadContext *)_ctx; 237 238 glfwMakeContextCurrent(ctx->window_handle); 239 ctx->gl_context = os_get_native_gl_context(ctx->window_handle); 240 241 beamformer_compute_setup(ctx->user_context, ctx->arena, ctx->gl_context); 242 243 for (;;) { 244 for (;;) { 245 i32 current = atomic_load(&ctx->sync_variable); 246 if (current && atomic_swap(&ctx->sync_variable, 0) == current) 247 break; 248 249 ctx->asleep = 1; 250 os_wait_on_value(&ctx->sync_variable, current, -1); 251 ctx->asleep = 0; 252 } 253 beamformer_complete_compute(ctx->user_context, ctx->arena, ctx->gl_context); 254 } 255 256 unreachable(); 257 258 return 0; 259 } 260 261 function void 262 setup_beamformer(BeamformerCtx *ctx, Arena *memory) 263 { 264 ctx->window_size = (uv2){.w = 1280, .h = 840}; 265 266 SetConfigFlags(FLAG_VSYNC_HINT|FLAG_WINDOW_ALWAYS_RUN); 267 InitWindow(ctx->window_size.w, ctx->window_size.h, "OGL Beamformer"); 268 /* NOTE: do this after initing so that the window starts out floating in tiling wm */ 269 SetWindowState(FLAG_WINDOW_RESIZABLE); 270 SetWindowMinSize(840, ctx->window_size.h); 271 272 /* NOTE: Gather information about the GPU */ 273 get_gl_params(&ctx->gl, &ctx->error_stream); 274 dump_gl_params(&ctx->gl, *memory, &ctx->os); 275 validate_gl_requirements(&ctx->gl, *memory); 276 277 glfwWindowHint(GLFW_VISIBLE, 0); 278 iptr raylib_window_handle = (iptr)GetPlatformWindowHandle(); 279 GLWorkerThreadContext *worker = &ctx->os.compute_worker; 280 worker->window_handle = glfwCreateWindow(320, 240, "", 0, raylib_window_handle); 281 worker->handle = os_create_thread(*memory, (iptr)worker, s8("[compute]"), 282 compute_worker_thread_entry_point); 283 /* TODO(rnp): we should lock this down after we have something working */ 284 worker->user_context = (iptr)ctx; 285 286 glfwMakeContextCurrent(raylib_window_handle); 287 288 ctx->beamform_work_queue = push_struct(memory, BeamformWorkQueue); 289 290 ctx->shared_memory = os_create_shared_memory_area(OS_SHARED_MEMORY_NAME, BEAMFORMER_SHARED_MEMORY_SIZE); 291 if (!ctx->shared_memory) 292 os_fatal(s8("Get more ram lol\n")); 293 mem_clear(ctx->shared_memory, 0, sizeof(*ctx->shared_memory)); 294 295 ctx->shared_memory->version = BEAMFORMER_PARAMETERS_VERSION; 296 /* TODO(rnp): refactor - this is annoying */ 297 ctx->shared_memory->parameters_sync = 1; 298 ctx->shared_memory->parameters_head_sync = 1; 299 ctx->shared_memory->parameters_ui_sync = 1; 300 ctx->shared_memory->raw_data_sync = 1; 301 ctx->shared_memory->channel_mapping_sync = 1; 302 ctx->shared_memory->sparse_elements_sync = 1; 303 ctx->shared_memory->focal_vectors_sync = 1; 304 305 /* NOTE: default compute shader pipeline */ 306 ctx->shared_memory->compute_stages[0] = ComputeShaderKind_Decode; 307 ctx->shared_memory->compute_stages[1] = ComputeShaderKind_DASCompute; 308 ctx->shared_memory->compute_stages_count = 2; 309 310 if (ctx->gl.vendor_id == GL_VENDOR_NVIDIA 311 && load_cuda_lib(&ctx->os, s8(OS_CUDA_LIB_NAME), (iptr)&ctx->cuda_lib, *memory)) 312 { 313 os_add_file_watch(&ctx->os, memory, s8(OS_CUDA_LIB_NAME), load_cuda_lib, 314 (iptr)&ctx->cuda_lib); 315 } else { 316 #define X(name, symname) if (!ctx->cuda_lib.name) ctx->cuda_lib.name = cuda_ ## name ## _stub; 317 CUDA_LIB_FNS 318 #undef X 319 } 320 321 /* NOTE: set up OpenGL debug logging */ 322 struct gl_debug_ctx *gl_debug_ctx = push_struct(memory, typeof(*gl_debug_ctx)); 323 gl_debug_ctx->stream = stream_alloc(memory, 1024); 324 gl_debug_ctx->os = &ctx->os; 325 glDebugMessageCallback(gl_debug_logger, gl_debug_ctx); 326 #ifdef _DEBUG 327 glEnable(GL_DEBUG_OUTPUT); 328 #endif 329 330 #define X(name, type, size, gltype, glsize, comment) "\t" #gltype " " #name #glsize "; " comment "\n" 331 read_only local_persist s8 compute_parameters_header = s8("" 332 "layout(std140, binding = 0) uniform parameters {\n" 333 BEAMFORMER_PARAMS_HEAD 334 BEAMFORMER_UI_PARAMS 335 BEAMFORMER_PARAMS_TAIL 336 "};\n\n" 337 ); 338 #undef X 339 340 #define X(e, sn, f, nh, pretty_name) do if (s8(f).len > 0) { \ 341 ShaderReloadContext *src = push_struct(memory, typeof(*src)); \ 342 src->beamformer_context = ctx; \ 343 if (nh) src->header = compute_parameters_header; \ 344 src->path = s8(static_path_join("shaders", f ".glsl")); \ 345 src->name = src->path; \ 346 src->shader = ctx->csctx.programs + ShaderKind_##e; \ 347 src->gl_type = GL_COMPUTE_SHADER; \ 348 src->kind = ShaderKind_##e; \ 349 src->link = src; \ 350 os_add_file_watch(&ctx->os, memory, src->path, reload_shader_indirect, (iptr)src); \ 351 reload_shader_indirect(&ctx->os, src->path, (iptr)src, *memory); \ 352 } while (0); 353 COMPUTE_SHADERS 354 #undef X 355 os_wake_waiters(&worker->sync_variable); 356 357 FrameViewRenderContext *fvr = &ctx->frame_view_render_context; 358 glGenFramebuffers(1, &fvr->framebuffer); 359 LABEL_GL_OBJECT(GL_FRAMEBUFFER, fvr->framebuffer, s8("Frame View Render Framebuffer")); 360 f32 vertices[] = { 361 -1, 1, 0, 0, 362 -1, -1, 0, 1, 363 1, -1, 1, 1, 364 -1, 1, 0, 0, 365 1, -1, 1, 1, 366 1, 1, 1, 0, 367 }; 368 glGenVertexArrays(1, &fvr->vao); 369 glBindVertexArray(fvr->vao); 370 glGenBuffers(1, &fvr->vbo); 371 glBindBuffer(GL_ARRAY_BUFFER, fvr->vbo); 372 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 373 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 4 * sizeof(f32), 0); 374 glEnableVertexAttribArray(0); 375 glVertexAttribPointer(1, 2, GL_FLOAT, 0, 4 * sizeof(f32), (void *)(2 * sizeof(f32))); 376 glEnableVertexAttribArray(1); 377 glBindVertexArray(0); 378 379 ShaderReloadContext *render_2d = push_struct(memory, typeof(*render_2d)); 380 render_2d->beamformer_context = ctx; 381 render_2d->path = s8(static_path_join("shaders", "render_2d.frag.glsl")); 382 render_2d->name = s8("shaders/render_2d.glsl"); 383 render_2d->gl_type = GL_FRAGMENT_SHADER; 384 render_2d->kind = ShaderKind_Render2D; 385 render_2d->shader = &fvr->shader; 386 render_2d->header = s8("" 387 "layout(location = 0) in vec2 texture_coordinate;\n" 388 "layout(location = 0) out vec4 v_out_colour;\n\n" 389 "layout(location = " str(FRAME_VIEW_RENDER_DYNAMIC_RANGE_LOC) ") uniform float u_db_cutoff = 60;\n" 390 "layout(location = " str(FRAME_VIEW_RENDER_THRESHOLD_LOC) ") uniform float u_threshold = 40;\n" 391 "layout(location = " str(FRAME_VIEW_RENDER_GAMMA_LOC) ") uniform float u_gamma = 1;\n" 392 "layout(location = " str(FRAME_VIEW_RENDER_LOG_SCALE_LOC) ") uniform bool u_log_scale;\n" 393 "\n#line 1\n"); 394 render_2d->link = push_struct(memory, typeof(*render_2d)); 395 render_2d->link->gl_type = GL_VERTEX_SHADER; 396 render_2d->link->link = render_2d; 397 render_2d->link->header = s8("" 398 "layout(location = 0) in vec2 v_position;\n" 399 "layout(location = 1) in vec2 v_texture_coordinate;\n" 400 "\n" 401 "layout(location = 0) out vec2 f_texture_coordinate;\n" 402 "\n" 403 "void main()\n" 404 "{\n" 405 "\tf_texture_coordinate = v_texture_coordinate;\n" 406 "\tgl_Position = vec4(v_position, 0, 1);\n" 407 "}\n"); 408 reload_shader(&ctx->os, render_2d->path, (iptr)render_2d, *memory); 409 os_add_file_watch(&ctx->os, memory, render_2d->path, reload_shader, (iptr)render_2d); 410 }