static.c (12211B)
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(beamform_work_queue_push) \ 14 X(beamform_work_queue_push_commit) 15 16 #define X(name) static name ##_fn *name; 17 DEBUG_ENTRY_POINTS 18 #undef X 19 20 static FILE_WATCH_CALLBACK_FN(debug_reload) 21 { 22 BeamformerInput *input = (BeamformerInput *)user_data; 23 Stream err = arena_stream(&tmp); 24 25 /* NOTE(rnp): spin until compute thread finishes its work (we will probably 26 * never reload while compute is in progress but just incase). */ 27 while (!atomic_load(&os->compute_worker.asleep)); 28 29 os_unload_library(debug_lib); 30 debug_lib = os_load_library(OS_DEBUG_LIB_NAME, OS_DEBUG_LIB_TEMP_NAME, &err); 31 32 #define X(name) name = os_lookup_dynamic_symbol(debug_lib, #name, &err); 33 DEBUG_ENTRY_POINTS 34 #undef X 35 36 stream_append_s8(&err, s8("Reloaded Main Executable\n")); 37 os->write_file(os->stderr, stream_to_s8(&err)); 38 39 input->executable_reloaded = 1; 40 41 return 1; 42 } 43 44 static void 45 debug_init(OS *os, iptr input, Arena *arena) 46 { 47 os->add_file_watch(os, arena, s8(OS_DEBUG_LIB_NAME), debug_reload, input); 48 debug_reload(os, (s8){0}, input, *arena); 49 50 Arena tmp = *arena; 51 Stream err = arena_stream(&tmp); 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_s8(err, s8("Unknown GL Vendor: ")); 117 stream_append_s8(err, c_str_to_s8(vendor)); 118 stream_append_byte(err, '\n'); 119 os_fatal(stream_to_s8(err)); 120 break; 121 } 122 123 glGetIntegerv(GL_MAJOR_VERSION, &gl->version_major); 124 glGetIntegerv(GL_MINOR_VERSION, &gl->version_minor); 125 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl->max_2d_texture_dim); 126 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gl->max_3d_texture_dim); 127 glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &gl->max_ssbo_size); 128 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gl->max_ubo_size); 129 glGetIntegerv(GL_MAX_SERVER_WAIT_TIMEOUT, &gl->max_server_wait_time); 130 131 /* NOTE(rnp): sometimes GL_MINOR_VERSION doesn't actually report the drivers 132 * supported version. Since at this point GL has been fully loaded we can 133 * check that at least one of the GL 4.5 function pointers are available */ 134 if (gl->version_minor < 5 && glCreateBuffers) 135 gl->version_minor = 5; 136 } 137 138 static void 139 validate_gl_requirements(GLParams *gl, Arena a) 140 { 141 Stream s = arena_stream(&a); 142 143 if (gl->max_ubo_size < sizeof(BeamformerParameters)) { 144 stream_append_s8(&s, s8("GPU must support UBOs of at least ")); 145 stream_append_i64(&s, sizeof(BeamformerParameters)); 146 stream_append_s8(&s, s8(" bytes!\n")); 147 } 148 149 if (gl->version_major < 4 || (gl->version_major == 4 && gl->version_minor < 5)) 150 stream_append_s8(&s, s8("Only OpenGL Versions 4.5 or newer are supported!\n")); 151 152 if (s.widx) os_fatal(stream_to_s8(&s)); 153 } 154 155 static void 156 dump_gl_params(GLParams *gl, Arena a, OS *os) 157 { 158 (void)gl; (void)a; 159 #ifdef _DEBUG 160 Stream s = arena_stream(&a); 161 stream_append_s8(&s, s8("---- GL Parameters ----\n")); 162 switch (gl->vendor_id) { 163 case GL_VENDOR_AMD: stream_append_s8(&s, s8("Vendor: AMD\n")); break; 164 case GL_VENDOR_ARM: stream_append_s8(&s, s8("Vendor: ARM\n")); break; 165 case GL_VENDOR_INTEL: stream_append_s8(&s, s8("Vendor: Intel\n")); break; 166 case GL_VENDOR_NVIDIA: stream_append_s8(&s, s8("Vendor: nVidia\n")); break; 167 } 168 stream_append_s8(&s, s8("Version: ")); 169 stream_append_i64(&s, gl->version_major); 170 stream_append_byte(&s, '.'); 171 stream_append_i64(&s, gl->version_minor); 172 stream_append_s8(&s, s8("\nMax 1D/2D Texture Dimension: ")); 173 stream_append_i64(&s, gl->max_2d_texture_dim); 174 stream_append_s8(&s, s8("\nMax 3D Texture Dimension: ")); 175 stream_append_i64(&s, gl->max_3d_texture_dim); 176 stream_append_s8(&s, s8("\nMax SSBO Size: ")); 177 stream_append_i64(&s, gl->max_ssbo_size); 178 stream_append_s8(&s, s8("\nMax UBO Size: ")); 179 stream_append_i64(&s, gl->max_ubo_size); 180 stream_append_s8(&s, s8("\nMax Server Wait Time [ns]: ")); 181 stream_append_i64(&s, gl->max_server_wait_time); 182 stream_append_s8(&s, s8("\n-----------------------\n")); 183 os->write_file(os->stderr, stream_to_s8(&s)); 184 #endif 185 } 186 187 static FILE_WATCH_CALLBACK_FN(reload_render_shader) 188 { 189 FragmentShaderCtx *ctx = (FragmentShaderCtx *)user_data; 190 Shader updated_fs = LoadShader(0, (c8 *)path.data); 191 192 if (updated_fs.id) { 193 UnloadShader(ctx->shader); 194 LABEL_GL_OBJECT(GL_PROGRAM, updated_fs.id, s8("Render Shader")); 195 ctx->shader = updated_fs; 196 ctx->db_cutoff_id = GetShaderLocation(updated_fs, "u_db_cutoff"); 197 ctx->threshold_id = GetShaderLocation(updated_fs, "u_threshold"); 198 ctx->updated = 1; 199 } 200 201 return 1; 202 } 203 204 205 static FILE_WATCH_CALLBACK_FN(queue_compute_shader_reload) 206 { 207 ComputeShaderReloadContext *csr = (typeof(csr))user_data; 208 BeamformerCtx *ctx = csr->beamformer_ctx; 209 BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue); 210 if (work) { 211 work->type = BW_RELOAD_SHADER; 212 work->reload_shader_ctx = csr; 213 beamform_work_queue_push_commit(ctx->beamform_work_queue); 214 ctx->os.wake_thread(ctx->os.compute_worker.sync_handle); 215 } 216 return 1; 217 } 218 219 static FILE_WATCH_CALLBACK_FN(load_cuda_lib) 220 { 221 CudaLib *cl = (CudaLib *)user_data; 222 b32 result = os_file_exists((c8 *)path.data); 223 if (result) { 224 Stream err = arena_stream(&tmp); 225 226 stream_append_s8(&err, s8("loading CUDA lib: " OS_CUDA_LIB_NAME "\n")); 227 os_unload_library(cl->lib); 228 cl->lib = os_load_library((c8 *)path.data, OS_CUDA_LIB_TEMP_NAME, &err); 229 #define X(name) cl->name = os_lookup_dynamic_symbol(cl->lib, #name, &err); 230 CUDA_LIB_FNS 231 #undef X 232 233 os->write_file(os->stderr, stream_to_s8(&err)); 234 } 235 236 #define X(name) if (!cl->name) cl->name = name ## _stub; 237 CUDA_LIB_FNS 238 #undef X 239 240 return result; 241 } 242 243 244 #define GLFW_VISIBLE 0x00020004 245 void glfwWindowHint(i32, i32); 246 iptr glfwCreateWindow(i32, i32, char *, iptr, iptr); 247 void glfwMakeContextCurrent(iptr); 248 249 static OS_THREAD_ENTRY_POINT_FN(compute_worker_thread_entry_point) 250 { 251 GLWorkerThreadContext *ctx = (GLWorkerThreadContext *)_ctx; 252 253 glfwMakeContextCurrent(ctx->window_handle); 254 ctx->gl_context = os_get_native_gl_context(ctx->window_handle); 255 256 for (;;) { 257 ctx->asleep = 1; 258 os_sleep_thread(ctx->sync_handle); 259 ctx->asleep = 0; 260 beamformer_complete_compute(ctx->user_context, ctx->arena, ctx->gl_context); 261 } 262 263 unreachable(); 264 265 return 0; 266 } 267 268 static void 269 setup_beamformer(BeamformerCtx *ctx, Arena *memory) 270 { 271 ctx->window_size = (uv2){.w = 1280, .h = 840}; 272 273 SetConfigFlags(FLAG_VSYNC_HINT|FLAG_WINDOW_ALWAYS_RUN); 274 InitWindow(ctx->window_size.w, ctx->window_size.h, "OGL Beamformer"); 275 /* NOTE: do this after initing so that the window starts out floating in tiling wm */ 276 SetWindowState(FLAG_WINDOW_RESIZABLE); 277 SetWindowMinSize(840, ctx->window_size.h); 278 279 /* NOTE: Gather information about the GPU */ 280 get_gl_params(&ctx->gl, &ctx->error_stream); 281 dump_gl_params(&ctx->gl, *memory, &ctx->os); 282 validate_gl_requirements(&ctx->gl, *memory); 283 284 glfwWindowHint(GLFW_VISIBLE, 0); 285 iptr raylib_window_handle = (iptr)GetPlatformWindowHandle(); 286 GLWorkerThreadContext *worker = &ctx->os.compute_worker; 287 worker->window_handle = glfwCreateWindow(320, 240, "", 0, raylib_window_handle); 288 worker->sync_handle = os_create_sync_object(memory); 289 worker->handle = os_create_thread(*memory, (iptr)worker, s8("[compute]"), 290 compute_worker_thread_entry_point); 291 /* TODO(rnp): we should lock this down after we have something working */ 292 worker->user_context = (iptr)ctx; 293 294 glfwMakeContextCurrent(raylib_window_handle); 295 296 ctx->beamform_work_queue = push_struct(memory, BeamformWorkQueue); 297 298 ctx->averaged_frames[0].id = 0; 299 ctx->averaged_frames[1].id = 1; 300 301 ctx->params = os_open_shared_memory_area(OS_SMEM_NAME, sizeof(*ctx->params)); 302 /* TODO: properly handle this? */ 303 ASSERT(ctx->params); 304 305 /* NOTE: default compute shader pipeline */ 306 ctx->params->compute_stages[0] = CS_DECODE; 307 ctx->params->compute_stages[1] = CS_DAS; 308 ctx->params->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) if (!ctx->cuda_lib.name) ctx->cuda_lib.name = 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 /* NOTE: allocate space for Uniform Buffer but don't send anything yet */ 331 glCreateBuffers(1, &ctx->csctx.shared_ubo); 332 glNamedBufferStorage(ctx->csctx.shared_ubo, sizeof(BeamformerParameters), 0, GL_DYNAMIC_STORAGE_BIT); 333 LABEL_GL_OBJECT(GL_BUFFER, ctx->csctx.shared_ubo, s8("Beamformer_Parameters")); 334 335 #define X(e, sn, f, nh, pretty_name) do if (s8(f).len > 0) { \ 336 ComputeShaderReloadContext *csr = push_struct(memory, typeof(*csr)); \ 337 csr->beamformer_ctx = ctx; \ 338 csr->label = s8("CS_" #e); \ 339 csr->shader = sn; \ 340 csr->needs_header = nh; \ 341 csr->path = s8(static_path_join("shaders", f ".glsl")); \ 342 os_add_file_watch(&ctx->os, memory, csr->path, queue_compute_shader_reload, (iptr)csr); \ 343 queue_compute_shader_reload(&ctx->os, csr->path, (iptr)csr, *memory); \ 344 } while (0); 345 COMPUTE_SHADERS 346 #undef X 347 os_wake_thread(worker->sync_handle); 348 349 s8 render = s8(static_path_join("shaders", "render.glsl")); 350 reload_render_shader(&ctx->os, render, (iptr)&ctx->fsctx, *memory); 351 os_add_file_watch(&ctx->os, memory, render, reload_render_shader, (iptr)&ctx->fsctx); 352 353 ctx->ready_for_rf = 1; 354 }