static.c (9993B)
1 /* See LICENSE for license details. */ 2 static struct { 3 s8 label; 4 s8 path; 5 b32 needs_header; 6 } compute_shaders[CS_LAST] = { 7 #define X(e, n, s, h, pn) [CS_##e] = {s8(#e), s8("shaders/" s ".glsl"), h}, 8 COMPUTE_SHADERS 9 #undef X 10 }; 11 12 #ifndef _DEBUG 13 14 #include "beamformer.c" 15 #define do_debug(...) 16 17 #else 18 static void *debug_lib; 19 20 static beamformer_frame_step_fn *beamformer_frame_step; 21 22 static void 23 do_debug(Stream *error_stream) 24 { 25 static f32 updated_time; 26 FileStats test_stats = os_get_file_stats(OS_DEBUG_LIB_NAME); 27 if (test_stats.filesize > 32 && test_stats.timestamp > updated_time) { 28 os_unload_library(debug_lib); 29 debug_lib = os_load_library(OS_DEBUG_LIB_NAME, OS_DEBUG_LIB_TEMP_NAME, error_stream); 30 beamformer_frame_step = os_lookup_dynamic_symbol(debug_lib, "beamformer_frame_step", error_stream); 31 updated_time = test_stats.timestamp; 32 } 33 } 34 35 #endif /* _DEBUG */ 36 37 static void 38 gl_debug_logger(u32 src, u32 type, u32 id, u32 lvl, i32 len, const char *msg, const void *userctx) 39 { 40 (void)src; (void)type; (void)id; 41 42 Stream *e = (Stream *)userctx; 43 stream_append_s8(e, s8("[GL DEBUG ")); 44 switch (lvl) { 45 case GL_DEBUG_SEVERITY_HIGH: stream_append_s8(e, s8("HIGH]: ")); break; 46 case GL_DEBUG_SEVERITY_MEDIUM: stream_append_s8(e, s8("MEDIUM]: ")); break; 47 case GL_DEBUG_SEVERITY_LOW: stream_append_s8(e, s8("LOW]: ")); break; 48 case GL_DEBUG_SEVERITY_NOTIFICATION: stream_append_s8(e, s8("NOTIFICATION]: ")); break; 49 default: stream_append_s8(e, s8("INVALID]: ")); break; 50 } 51 stream_append_s8(e, (s8){.len = len, .data = (u8 *)msg}); 52 stream_append_byte(e, '\n'); 53 os_write_err_msg(stream_to_s8(e)); 54 e->widx = 0; 55 } 56 57 static void 58 get_gl_params(GLParams *gl, Stream *err) 59 { 60 char *vendor = (char *)glGetString(GL_VENDOR); 61 if (!vendor) { 62 stream_append_s8(err, s8("Failed to determine GL Vendor\n")); 63 os_fatal(stream_to_s8(err)); 64 } 65 switch (vendor[0]) { 66 case 'A': gl->vendor_id = GL_VENDOR_AMD; break; 67 case 'I': gl->vendor_id = GL_VENDOR_INTEL; break; 68 case 'N': gl->vendor_id = GL_VENDOR_NVIDIA; break; 69 /* NOTE(rnp): freedreno - might need different handling on win32 but this is fine for now */ 70 case 'f': gl->vendor_id = GL_VENDOR_ARM; break; 71 default: 72 stream_append_s8(err, s8("Unknown GL Vendor: ")); 73 stream_append_s8(err, cstr_to_s8(vendor)); 74 stream_append_byte(err, '\n'); 75 os_fatal(stream_to_s8(err)); 76 break; 77 } 78 79 glGetIntegerv(GL_MAJOR_VERSION, &gl->version_major); 80 glGetIntegerv(GL_MINOR_VERSION, &gl->version_minor); 81 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl->max_2d_texture_dim); 82 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gl->max_3d_texture_dim); 83 glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &gl->max_ssbo_size); 84 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gl->max_ubo_size); 85 } 86 87 static void 88 validate_gl_requirements(GLParams *gl) 89 { 90 ASSERT(gl->max_ubo_size >= sizeof(BeamformerParameters)); 91 /* NOTE: nVidia's driver seems to misreport the version */ 92 b32 invalid = 0; 93 if (gl->version_major < 4) 94 invalid = 1; 95 96 switch (gl->vendor_id) { 97 case GL_VENDOR_AMD: 98 case GL_VENDOR_ARM: 99 case GL_VENDOR_INTEL: 100 if (gl->version_major == 4 && gl->version_minor < 5) 101 invalid = 1; 102 break; 103 case GL_VENDOR_NVIDIA: 104 if (gl->version_major == 4 && gl->version_minor < 3) 105 invalid = 1; 106 break; 107 } 108 109 if (invalid) 110 os_fatal(s8("Only OpenGL Versions 4.5 or newer are supported!\n")); 111 } 112 113 static void 114 dump_gl_params(GLParams *gl, Arena a) 115 { 116 (void)gl; (void)a; 117 #ifdef _DEBUG 118 Stream s = arena_stream(&a); 119 stream_append_s8(&s, s8("---- GL Parameters ----\n")); 120 switch (gl->vendor_id) { 121 case GL_VENDOR_AMD: stream_append_s8(&s, s8("Vendor: AMD\n")); break; 122 case GL_VENDOR_ARM: stream_append_s8(&s, s8("Vendor: ARM\n")); break; 123 case GL_VENDOR_INTEL: stream_append_s8(&s, s8("Vendor: Intel\n")); break; 124 case GL_VENDOR_NVIDIA: stream_append_s8(&s, s8("Vendor: nVidia\n")); break; 125 } 126 stream_append_s8(&s, s8("Version: ")); 127 stream_append_i64(&s, gl->version_major); 128 stream_append_byte(&s, '.'); 129 stream_append_i64(&s, gl->version_minor); 130 stream_append_s8(&s, s8("\nMax 1D/2D Texture Dimension: ")); 131 stream_append_i64(&s, gl->max_2d_texture_dim); 132 stream_append_s8(&s, s8("\nMax 3D Texture Dimension: ")); 133 stream_append_i64(&s, gl->max_3d_texture_dim); 134 stream_append_s8(&s, s8("\nMax SSBO Size: ")); 135 stream_append_i64(&s, gl->max_ssbo_size); 136 stream_append_s8(&s, s8("\nMax UBO Size: ")); 137 stream_append_i64(&s, gl->max_ubo_size); 138 stream_append_s8(&s, s8("\n-----------------------\n")); 139 if (!s.errors) 140 os_write_err_msg(stream_to_s8(&s)); 141 #endif 142 } 143 144 static u32 145 compile_shader(Arena a, u32 type, s8 shader) 146 { 147 u32 sid = glCreateShader(type); 148 glShaderSource(sid, 1, (const char **)&shader.data, (int *)&shader.len); 149 glCompileShader(sid); 150 151 i32 res = 0; 152 glGetShaderiv(sid, GL_COMPILE_STATUS, &res); 153 154 char *stype; 155 switch (type) { 156 case GL_COMPUTE_SHADER: stype = "Compute"; break; 157 case GL_FRAGMENT_SHADER: stype = "Fragment"; break; 158 } 159 160 if (res == GL_FALSE) { 161 TraceLog(LOG_WARNING, "SHADER: [ID %u] %s shader failed to compile", sid, stype); 162 i32 len = 0; 163 glGetShaderiv(sid, GL_INFO_LOG_LENGTH, &len); 164 s8 err = s8alloc(&a, len); 165 glGetShaderInfoLog(sid, len, (int *)&err.len, (char *)err.data); 166 TraceLog(LOG_WARNING, "SHADER: [ID %u] Compile error: %s", sid, (char *)err.data); 167 glDeleteShader(sid); 168 } else { 169 TraceLog(LOG_INFO, "SHADER: [ID %u] %s shader compiled successfully", sid, stype); 170 } 171 172 return sid; 173 } 174 175 static void 176 reload_shaders(BeamformerCtx *ctx, Arena a) 177 { 178 ComputeShaderCtx *csctx = &ctx->csctx; 179 s8 header_in_arena = push_s8(&a, s8(COMPUTE_SHADER_HEADER)); 180 for (u32 i = 0; i < ARRAY_COUNT(csctx->programs); i++) { 181 FileStats fs = os_get_file_stats((char *)compute_shaders[i].path.data); 182 if (fs.filesize <= 0) 183 continue; 184 185 Arena tmp = a; 186 s8 shader_text = os_read_file(&tmp, (char *)compute_shaders[i].path.data, fs.filesize); 187 if (shader_text.len == -1) { 188 stream_append_s8(&ctx->error_stream, s8("failed to read shader: ")); 189 stream_append_s8(&ctx->error_stream, compute_shaders[i].path); 190 stream_append_byte(&ctx->error_stream, '\n'); 191 /* TODO: maybe we don't need to fail here */ 192 os_fatal(stream_to_s8(&ctx->error_stream)); 193 } 194 /* NOTE: arena works as stack (since everything here is 1 byte aligned) */ 195 if (compute_shaders[i].needs_header) { 196 shader_text.data -= header_in_arena.len; 197 shader_text.len += header_in_arena.len; 198 ASSERT(shader_text.data == header_in_arena.data); 199 } 200 201 u32 shader_id = compile_shader(tmp, GL_COMPUTE_SHADER, shader_text); 202 203 if (shader_id) { 204 glDeleteProgram(csctx->programs[i]); 205 csctx->programs[i] = rlLoadComputeShaderProgram(shader_id); 206 glUseProgram(csctx->programs[i]); 207 glBindBufferBase(GL_UNIFORM_BUFFER, 0, csctx->shared_ubo); 208 LABEL_GL_OBJECT(GL_PROGRAM, csctx->programs[i], compute_shaders[i].label); 209 } 210 211 glDeleteShader(shader_id); 212 } 213 214 #define X(idx, name) csctx->name##_id = glGetUniformLocation(csctx->programs[idx], "u_" #name); 215 CS_UNIFORMS 216 #undef X 217 218 Shader updated_fs = LoadShader(NULL, "shaders/render.glsl"); 219 if (updated_fs.id != rlGetShaderIdDefault()) { 220 UnloadShader(ctx->fsctx.shader); 221 LABEL_GL_OBJECT(GL_PROGRAM, updated_fs.id, s8("Render")); 222 ctx->fsctx.shader = updated_fs; 223 ctx->fsctx.db_cutoff_id = GetShaderLocation(updated_fs, "u_db_cutoff"); 224 ctx->fsctx.threshold_id = GetShaderLocation(updated_fs, "u_threshold"); 225 } 226 } 227 228 static void 229 validate_cuda_lib(CudaLib *cl) 230 { 231 #define X(name) if (!cl->name) cl->name = name ## _stub; 232 CUDA_LIB_FNS 233 #undef X 234 } 235 236 static void 237 check_and_load_cuda_lib(CudaLib *cl, Stream *error_stream) 238 { 239 FileStats current = os_get_file_stats(OS_CUDA_LIB_NAME); 240 if (cl->timestamp == current.timestamp || current.filesize < 32) 241 return; 242 243 TraceLog(LOG_INFO, "Loading CUDA lib: %s", OS_CUDA_LIB_NAME); 244 245 cl->timestamp = current.timestamp; 246 os_unload_library(cl->lib); 247 cl->lib = os_load_library(OS_CUDA_LIB_NAME, OS_CUDA_LIB_TEMP_NAME, error_stream); 248 #define X(name) cl->name = os_lookup_dynamic_symbol(cl->lib, #name, error_stream); 249 CUDA_LIB_FNS 250 #undef X 251 validate_cuda_lib(cl); 252 } 253 254 static void 255 setup_beamformer(BeamformerCtx *ctx, Arena temp_memory) 256 { 257 ctx->window_size = (uv2){.w = 1280, .h = 840}; 258 259 SetConfigFlags(FLAG_VSYNC_HINT); 260 InitWindow(ctx->window_size.w, ctx->window_size.h, "OGL Beamformer"); 261 /* NOTE: do this after initing so that the window starts out floating in tiling wm */ 262 SetWindowState(FLAG_WINDOW_RESIZABLE); 263 SetWindowMinSize(INFO_COLUMN_WIDTH * 2, ctx->window_size.h); 264 265 /* NOTE: Gather information about the GPU */ 266 get_gl_params(&ctx->gl, &ctx->error_stream); 267 dump_gl_params(&ctx->gl, temp_memory); 268 validate_gl_requirements(&ctx->gl); 269 270 ctx->fsctx.db = -50.0f; 271 ctx->fsctx.threshold = 40.0f; 272 273 ctx->params = os_open_shared_memory_area(OS_SMEM_NAME, sizeof(*ctx->params)); 274 /* TODO: properly handle this? */ 275 ASSERT(ctx->params); 276 277 /* NOTE: default compute shader pipeline */ 278 ctx->params->compute_stages[0] = CS_HADAMARD; 279 ctx->params->compute_stages[1] = CS_DAS; 280 ctx->params->compute_stages[2] = CS_MIN_MAX; 281 ctx->params->compute_stages_count = 3; 282 283 /* NOTE: make sure function pointers are valid even if we are not using the cuda lib */ 284 validate_cuda_lib(&ctx->cuda_lib); 285 286 /* NOTE: set up OpenGL debug logging */ 287 glDebugMessageCallback(gl_debug_logger, &ctx->error_stream); 288 #ifdef _DEBUG 289 glEnable(GL_DEBUG_OUTPUT); 290 #endif 291 292 /* NOTE: allocate space for Uniform Buffer but don't send anything yet */ 293 glCreateBuffers(1, &ctx->csctx.shared_ubo); 294 glNamedBufferStorage(ctx->csctx.shared_ubo, sizeof(BeamformerParameters), 0, GL_DYNAMIC_STORAGE_BIT); 295 LABEL_GL_OBJECT(GL_BUFFER, ctx->csctx.shared_ubo, s8("Beamformer_Parameters")); 296 297 glGenQueries(ARRAY_COUNT(ctx->csctx.timer_fences) * CS_LAST, (u32 *)ctx->csctx.timer_ids); 298 glGenQueries(ARRAY_COUNT(ctx->partial_compute_ctx.timer_ids), ctx->partial_compute_ctx.timer_ids); 299 300 reload_shaders(ctx, temp_memory); 301 }