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