static.c (13806B)
1 /* See LICENSE for license details. */ 2 #ifndef _DEBUG 3 4 #include "beamformer.c" 5 #define debug_init(...) 6 7 #else 8 static 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(beamform_work_queue_push) \ 15 X(beamform_work_queue_push_commit) 16 17 #define X(name) static name ##_fn *name; 18 DEBUG_ENTRY_POINTS 19 #undef X 20 21 static FILE_WATCH_CALLBACK_FN(debug_reload) 22 { 23 BeamformerInput *input = (BeamformerInput *)user_data; 24 Stream err = arena_stream(&tmp); 25 26 /* NOTE(rnp): spin until compute thread finishes its work (we will probably 27 * never reload while compute is in progress but just incase). */ 28 while (!atomic_load(&os->compute_worker.asleep)); 29 30 os_unload_library(debug_lib); 31 debug_lib = os_load_library(OS_DEBUG_LIB_NAME, OS_DEBUG_LIB_TEMP_NAME, &err); 32 33 #define X(name) name = os_lookup_dynamic_symbol(debug_lib, #name, &err); 34 DEBUG_ENTRY_POINTS 35 #undef X 36 37 stream_append_s8(&err, s8("Reloaded Main Executable\n")); 38 os->write_file(os->stderr, stream_to_s8(&err)); 39 40 input->executable_reloaded = 1; 41 42 return 1; 43 } 44 45 static void 46 debug_init(OS *os, iptr input, Arena *arena) 47 { 48 os->add_file_watch(os, arena, s8(OS_DEBUG_LIB_NAME), debug_reload, input); 49 debug_reload(os, (s8){0}, input, *arena); 50 51 Arena tmp = *arena; 52 Stream err = arena_stream(&tmp); 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->stderr, stream_to_s8(&err)); 67 } 68 69 #endif /* _DEBUG */ 70 71 #define static_path_join(a, b) (a OS_PATH_SEPERATOR b) 72 73 struct gl_debug_ctx { 74 Stream stream; 75 OS *os; 76 }; 77 78 static 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->stderr, stream_to_s8(e)); 96 stream_reset(e, 0); 97 } 98 99 static 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_s8(err, s8("Unknown GL Vendor: ")); 118 stream_append_s8(err, c_str_to_s8(vendor)); 119 stream_append_byte(err, '\n'); 120 os_fatal(stream_to_s8(err)); 121 } 122 123 #define X(glname, name, suffix) glGetIntegerv(GL_##glname, &gl->name); 124 GL_PARAMETERS 125 #undef X 126 127 /* NOTE(rnp): sometimes GL_MINOR_VERSION doesn't actually report the drivers 128 * supported version. Since at this point GL has been fully loaded we can 129 * check that at least one of the GL 4.5 function pointers are available */ 130 if (gl->version_minor < 5 && glCreateBuffers) 131 gl->version_minor = 5; 132 } 133 134 static void 135 validate_gl_requirements(GLParams *gl, Arena a) 136 { 137 Stream s = arena_stream(&a); 138 139 if (gl->max_ubo_size < sizeof(BeamformerParameters)) { 140 stream_append_s8(&s, s8("GPU must support UBOs of at least ")); 141 stream_append_i64(&s, sizeof(BeamformerParameters)); 142 stream_append_s8(&s, s8(" bytes!\n")); 143 } 144 145 if (gl->version_major < 4 || (gl->version_major == 4 && gl->version_minor < 5)) 146 stream_append_s8(&s, s8("Only OpenGL Versions 4.5 or newer are supported!\n")); 147 148 if (s.widx) os_fatal(stream_to_s8(&s)); 149 } 150 151 static void 152 dump_gl_params(GLParams *gl, Arena a, OS *os) 153 { 154 (void)gl; (void)a; 155 #ifdef _DEBUG 156 s8 vendor = s8("vendor:"); 157 iz max_width = vendor.len; 158 #define X(glname, name, suffix) if (s8(#name).len > max_width) max_width = s8(#name ":").len; 159 GL_PARAMETERS 160 #undef X 161 max_width++; 162 163 Stream s = arena_stream(&a); 164 stream_append_s8(&s, s8("---- GL Parameters ----\n")); 165 stream_append_s8(&s, vendor); 166 stream_pad(&s, ' ', max_width - vendor.len); 167 switch (gl->vendor_id) { 168 case GL_VENDOR_AMD: stream_append_s8(&s, s8("AMD\n")); break; 169 case GL_VENDOR_ARM: stream_append_s8(&s, s8("ARM\n")); break; 170 case GL_VENDOR_INTEL: stream_append_s8(&s, s8("Intel\n")); break; 171 case GL_VENDOR_NVIDIA: stream_append_s8(&s, s8("nVidia\n")); break; 172 } 173 174 #define X(glname, name, suffix) \ 175 stream_append_s8(&s, s8(#name ":")); \ 176 stream_pad(&s, ' ', max_width - s8(#name ":").len); \ 177 stream_append_i64(&s, gl->name); \ 178 stream_append_s8(&s, s8(suffix)); \ 179 stream_append_byte(&s, '\n'); 180 GL_PARAMETERS 181 #undef X 182 stream_append_s8(&s, s8("-----------------------\n")); 183 os->write_file(os->stderr, stream_to_s8(&s)); 184 #endif 185 } 186 187 function FILE_WATCH_CALLBACK_FN(reload_render_shader) 188 { 189 FrameViewRenderContext *ctx = (typeof(ctx))user_data; 190 191 local_persist s8 vertex = s8("" 192 "#version 460 core\n" 193 "\n" 194 "layout(location = 0) in vec2 vertex_position;\n" 195 "layout(location = 1) in vec2 vertex_texture_coordinate;\n" 196 "\n" 197 "layout(location = 0) out vec2 fragment_texture_coordinate;\n" 198 "\n" 199 "void main()\n" 200 "{\n" 201 "\tfragment_texture_coordinate = vertex_texture_coordinate;\n" 202 "\tgl_Position = vec4(vertex_position, 0, 1);\n" 203 "}\n"); 204 205 Arena *a = &tmp; 206 s8 header = {.data = a->beg}; 207 push_s8(a, s8("#version 460 core\n\n")); 208 push_s8(a, s8("layout(location = 0) in vec2 fragment_texture_coordinate;\n")); 209 push_s8(a, s8("layout(location = 0) out vec4 v_out_colour;\n\n")); 210 push_s8(a, s8("layout(location = " str(FRAME_VIEW_RENDER_DYNAMIC_RANGE_LOC) ") uniform float u_db_cutoff = 60;\n")); 211 push_s8(a, s8("layout(location = " str(FRAME_VIEW_RENDER_THRESHOLD_LOC) ") uniform float u_threshold = 40;\n")); 212 push_s8(a, s8("layout(location = " str(FRAME_VIEW_RENDER_GAMMA_LOC) ") uniform float u_gamma = 1;\n")); 213 push_s8(a, s8("layout(location = " str(FRAME_VIEW_RENDER_LOG_SCALE_LOC) ") uniform bool u_log_scale;\n")); 214 push_s8(a, s8("\n#line 1\n")); 215 header.len = a->beg - header.data; 216 217 s8 fragment = os->read_whole_file(a, (c8 *)path.data); 218 fragment.data -= header.len; 219 fragment.len += header.len; 220 ASSERT(fragment.data == header.data); 221 u32 new_program = load_shader(os, tmp, 0, vertex, fragment, (s8){0}, path, s8("Render Shader")); 222 if (new_program) { 223 glDeleteProgram(ctx->shader); 224 ctx->shader = new_program; 225 ctx->updated = 1; 226 } 227 228 return 1; 229 } 230 231 232 static FILE_WATCH_CALLBACK_FN(queue_compute_shader_reload) 233 { 234 ComputeShaderReloadContext *csr = (typeof(csr))user_data; 235 BeamformerCtx *ctx = csr->beamformer_ctx; 236 BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue); 237 if (work) { 238 work->type = BW_RELOAD_SHADER; 239 work->reload_shader_ctx = csr; 240 beamform_work_queue_push_commit(ctx->beamform_work_queue); 241 ctx->os.wake_waiters(&ctx->os.compute_worker.sync_variable); 242 } 243 return 1; 244 } 245 246 static FILE_WATCH_CALLBACK_FN(load_cuda_lib) 247 { 248 CudaLib *cl = (CudaLib *)user_data; 249 b32 result = os_file_exists((c8 *)path.data); 250 if (result) { 251 Stream err = arena_stream(&tmp); 252 253 stream_append_s8(&err, s8("loading CUDA lib: " OS_CUDA_LIB_NAME "\n")); 254 os_unload_library(cl->lib); 255 cl->lib = os_load_library((c8 *)path.data, OS_CUDA_LIB_TEMP_NAME, &err); 256 #define X(name) cl->name = os_lookup_dynamic_symbol(cl->lib, #name, &err); 257 CUDA_LIB_FNS 258 #undef X 259 260 os->write_file(os->stderr, stream_to_s8(&err)); 261 } 262 263 #define X(name) if (!cl->name) cl->name = name ## _stub; 264 CUDA_LIB_FNS 265 #undef X 266 267 return result; 268 } 269 270 271 #define GLFW_VISIBLE 0x00020004 272 void glfwWindowHint(i32, i32); 273 iptr glfwCreateWindow(i32, i32, char *, iptr, iptr); 274 void glfwMakeContextCurrent(iptr); 275 276 static OS_THREAD_ENTRY_POINT_FN(compute_worker_thread_entry_point) 277 { 278 GLWorkerThreadContext *ctx = (GLWorkerThreadContext *)_ctx; 279 280 glfwMakeContextCurrent(ctx->window_handle); 281 ctx->gl_context = os_get_native_gl_context(ctx->window_handle); 282 283 beamformer_compute_setup(ctx->user_context, ctx->arena, ctx->gl_context); 284 285 for (;;) { 286 for (;;) { 287 i32 current = atomic_load(&ctx->sync_variable); 288 if (current && atomic_swap(&ctx->sync_variable, 0) == current) 289 break; 290 291 ctx->asleep = 1; 292 os_wait_on_value(&ctx->sync_variable, current, -1); 293 ctx->asleep = 0; 294 } 295 beamformer_complete_compute(ctx->user_context, ctx->arena, ctx->gl_context); 296 } 297 298 unreachable(); 299 300 return 0; 301 } 302 303 static void 304 setup_beamformer(BeamformerCtx *ctx, Arena *memory) 305 { 306 ctx->window_size = (uv2){.w = 1280, .h = 840}; 307 308 SetConfigFlags(FLAG_VSYNC_HINT|FLAG_WINDOW_ALWAYS_RUN); 309 InitWindow(ctx->window_size.w, ctx->window_size.h, "OGL Beamformer"); 310 /* NOTE: do this after initing so that the window starts out floating in tiling wm */ 311 SetWindowState(FLAG_WINDOW_RESIZABLE); 312 SetWindowMinSize(840, ctx->window_size.h); 313 314 /* NOTE: Gather information about the GPU */ 315 get_gl_params(&ctx->gl, &ctx->error_stream); 316 dump_gl_params(&ctx->gl, *memory, &ctx->os); 317 validate_gl_requirements(&ctx->gl, *memory); 318 319 glfwWindowHint(GLFW_VISIBLE, 0); 320 iptr raylib_window_handle = (iptr)GetPlatformWindowHandle(); 321 GLWorkerThreadContext *worker = &ctx->os.compute_worker; 322 worker->window_handle = glfwCreateWindow(320, 240, "", 0, raylib_window_handle); 323 worker->handle = os_create_thread(*memory, (iptr)worker, s8("[compute]"), 324 compute_worker_thread_entry_point); 325 /* TODO(rnp): we should lock this down after we have something working */ 326 worker->user_context = (iptr)ctx; 327 328 glfwMakeContextCurrent(raylib_window_handle); 329 330 ctx->beamform_work_queue = push_struct(memory, BeamformWorkQueue); 331 332 ctx->shared_memory = os_open_shared_memory_area(OS_SMEM_NAME, BEAMFORMER_SHARED_MEMORY_SIZE); 333 if (!ctx->shared_memory) 334 os_fatal(s8("Get more ram lol\n")); 335 /* TODO(rnp): refactor - this is annoying */ 336 ctx->shared_memory->parameters_sync = 1; 337 ctx->shared_memory->parameters_head_sync = 1; 338 ctx->shared_memory->parameters_ui_sync = 1; 339 ctx->shared_memory->raw_data_sync = 1; 340 ctx->shared_memory->channel_mapping_sync = 1; 341 ctx->shared_memory->sparse_elements_sync = 1; 342 ctx->shared_memory->focal_vectors_sync = 1; 343 344 /* NOTE: default compute shader pipeline */ 345 ctx->shared_memory->compute_stages[0] = CS_DECODE; 346 ctx->shared_memory->compute_stages[1] = CS_DAS; 347 ctx->shared_memory->compute_stages_count = 2; 348 349 if (ctx->gl.vendor_id == GL_VENDOR_NVIDIA 350 && load_cuda_lib(&ctx->os, s8(OS_CUDA_LIB_NAME), (iptr)&ctx->cuda_lib, *memory)) 351 { 352 os_add_file_watch(&ctx->os, memory, s8(OS_CUDA_LIB_NAME), load_cuda_lib, 353 (iptr)&ctx->cuda_lib); 354 } else { 355 #define X(name) if (!ctx->cuda_lib.name) ctx->cuda_lib.name = name ## _stub; 356 CUDA_LIB_FNS 357 #undef X 358 } 359 360 /* NOTE: set up OpenGL debug logging */ 361 struct gl_debug_ctx *gl_debug_ctx = push_struct(memory, typeof(*gl_debug_ctx)); 362 gl_debug_ctx->stream = stream_alloc(memory, 1024); 363 gl_debug_ctx->os = &ctx->os; 364 glDebugMessageCallback(gl_debug_logger, gl_debug_ctx); 365 #ifdef _DEBUG 366 glEnable(GL_DEBUG_OUTPUT); 367 #endif 368 369 #define X(e, sn, f, nh, pretty_name) do if (s8(f).len > 0) { \ 370 ComputeShaderReloadContext *csr = push_struct(memory, typeof(*csr)); \ 371 csr->beamformer_ctx = ctx; \ 372 csr->label = s8("CS_" #e); \ 373 csr->shader = sn; \ 374 csr->needs_header = nh; \ 375 csr->path = s8(static_path_join("shaders", f ".glsl")); \ 376 os_add_file_watch(&ctx->os, memory, csr->path, queue_compute_shader_reload, (iptr)csr); \ 377 queue_compute_shader_reload(&ctx->os, csr->path, (iptr)csr, *memory); \ 378 } while (0); 379 COMPUTE_SHADERS 380 #undef X 381 os_wake_waiters(&worker->sync_variable); 382 383 FrameViewRenderContext *fvr = &ctx->frame_view_render_context; 384 glGenFramebuffers(1, &fvr->framebuffer); 385 LABEL_GL_OBJECT(GL_FRAMEBUFFER, fvr->framebuffer, s8("Frame View Render Framebuffer")); 386 f32 vertices[] = { 387 -1, 1, 0, 0, 388 -1, -1, 0, 1, 389 1, -1, 1, 1, 390 -1, 1, 0, 0, 391 1, -1, 1, 1, 392 1, 1, 1, 0, 393 }; 394 glGenVertexArrays(1, &fvr->vao); 395 glBindVertexArray(fvr->vao); 396 glGenBuffers(1, &fvr->vbo); 397 glBindBuffer(GL_ARRAY_BUFFER, fvr->vbo); 398 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 399 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 4 * sizeof(f32), 0); 400 glEnableVertexAttribArray(0); 401 glVertexAttribPointer(1, 2, GL_FLOAT, 0, 4 * sizeof(f32), (void *)(2 * sizeof(f32))); 402 glEnableVertexAttribArray(1); 403 glBindVertexArray(0); 404 405 s8 render = s8(static_path_join("shaders", "render.glsl")); 406 reload_render_shader(&ctx->os, render, (iptr)fvr, *memory); 407 os_add_file_watch(&ctx->os, memory, render, reload_render_shader, (iptr)fvr); 408 }