Commit: 134cfd438bceb0745fa7ba38b110654067a2e16a
Parent: 2cfaa5b99e70e408789879ec12b2c0b9383d218b
Author: Randy Palamar
Date: Sun, 10 Nov 2024 21:51:47 -0700
use file watcher for reloading shaders
also embed the vertex shader directly in the source. That shader
is not really likely to change so it is more robust for for it to
be directly embedded.
Diffstat:
D | vert_for_rects.glsl | | | 18 | ------------------ |
M | vtgl.c | | | 174 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
2 files changed, 105 insertions(+), 87 deletions(-)
diff --git a/vert_for_rects.glsl b/vert_for_rects.glsl
@@ -1,18 +0,0 @@
-#version 430 core
-
-layout(location = 0) in vec2 vertex_position;
-layout(location = 1) in vec2 vertex_texture_coordinate;
-layout(location = 2) in vec4 vertex_colour;
-
-layout(location = 0) out vec2 fragment_texture_coordinate;
-layout(location = 1) out vec4 fragment_colour;
-
-layout(location = 0) uniform mat4 u_Pmat;
-
-void main()
-{
- fragment_texture_coordinate = vertex_texture_coordinate;
- fragment_colour = vertex_colour;
-
- gl_Position = u_Pmat * vec4(vertex_position, 0.0, 1.0);
-}
diff --git a/vtgl.c b/vtgl.c
@@ -15,6 +15,32 @@ static u32 get_gpu_glyph_index(Arena, GLCtx *, FontAtlas *, u32, u32, enum face_
#define REVERSE_VIDEO_MASK (Colour){.r = 0xff, .g = 0xff, .b = 0xff}.rgba
+#define VERTEX_SHADER_TEXT \
+"#version 430 core\n" \
+"\n" \
+"layout(location = 0) in vec2 vertex_position;\n" \
+"layout(location = 1) in vec2 vertex_texture_coordinate;\n" \
+"layout(location = 2) in vec4 vertex_colour;\n" \
+"\n" \
+"layout(location = 0) out vec2 fragment_texture_coordinate;\n" \
+"layout(location = 1) out vec4 fragment_colour;\n" \
+"\n" \
+"layout(location = 0) uniform mat4 u_Pmat;\n" \
+"\n" \
+"void main()\n" \
+"{\n" \
+" fragment_texture_coordinate = vertex_texture_coordinate;\n" \
+" fragment_colour = vertex_colour;\n" \
+"\n" \
+" gl_Position = u_Pmat * vec4(vertex_position, 0.0, 1.0);\n" \
+"}\n"
+
+typedef struct {
+ TerminalMemory *memory;
+ s8 info;
+ u32 stage;
+} shader_reload_ctx;
+
static u32
compile_shader(Arena a, u32 type, s8 shader)
{
@@ -84,87 +110,69 @@ update_uniforms(GLCtx *gl, enum shader_stages stage)
}
}
-static void
-check_shaders(GLCtx *gl, Arena a, Stream *err, PlatformAPI *platform)
+static PLATFORM_FILE_WATCH_CALLBACK_FN(reload_shader)
{
- static s8 fs_name[SHADER_COUNT] = {
- [SHADER_RENDER] = s8("frag_render.glsl"),
- [SHADER_RECTS] = s8("frag_for_rects.glsl"),
- [SHADER_POST] = s8("frag_post.glsl"),
- };
- static s8 vs_name[SHADER_COUNT] = {
- [SHADER_RENDER] = s8("vert_for_rects.glsl"),
- [SHADER_RECTS] = s8("vert_for_rects.glsl"),
- [SHADER_POST] = s8("vert_for_rects.glsl"),
- };
+ shader_reload_ctx *ctx = user_ctx;
+ PlatformAPI *platform = &ctx->memory->platform_api;
+ Term *t = ctx->memory->memory;
+ Arena a = t->arena_for_frame;
+ Stream *err = &t->error_stream;
+
+ b32 success = 1;
+
+ FileStats fs_stats = platform->get_file_stats(path);
+ Stream fs_text = stream_alloc(&a, fs_stats.size);
+ success &= platform->read_file(path, &fs_text, fs_stats.size);
+
+ if (success) {
+ u32 program = program_from_shader_text(s8(VERTEX_SHADER_TEXT), stream_to_s8(&fs_text), a);
+ if (program) {
+ glDeleteProgram(t->gl.programs[ctx->stage]);
+ t->gl.programs[ctx->stage] = program;
+ update_uniforms(&t->gl, ctx->stage);
+ stream_push_s8(err, ctx->info);
+ }
+ }
- static struct {
- s8 name;
- b32 update_uniforms;
- } map[SHADER_COUNT] = {
- [SHADER_RENDER] = {.name = s8("Render"), .update_uniforms = 0},
- [SHADER_RECTS] = {.name = s8("Rects"), .update_uniforms = 0},
- [SHADER_POST] = {.name = s8("Post"), .update_uniforms = 1},
- };
+ if (err->widx) {
+ os_write_err_msg(stream_to_s8(err));
+ err->widx = 0;
+ }
+}
+
+static s8 fs_name[SHADER_COUNT] = {
+ [SHADER_RENDER] = s8("frag_render.glsl"),
+ [SHADER_RECTS] = s8("frag_for_rects.glsl"),
+ [SHADER_POST] = s8("frag_post.glsl"),
+};
+
+static void
+reload_all_shaders(TerminalMemory *memory)
+{
+ PlatformAPI *platform = &memory->platform_api;
+ Term *t = memory->memory;
- /* TODO: this is nasty but will be cleaned up with a file watcher */
- Stream vs_path = stream_alloc(&a, 4 * KILOBYTE);
- stream_push_s8(&vs_path, g_shader_path_prefix);
- if (vs_path.widx && vs_path.buf[vs_path.widx - 1] != platform->path_separator)
- stream_push_byte(&vs_path, platform->path_separator);
+ TempArena temp_memory = begin_temp_arena(&t->arena_for_frame);
- Stream fs_path = stream_alloc(&a, 4 * KILOBYTE);
+ Stream fs_path = stream_alloc(&t->arena_for_frame, 4 * KILOBYTE);
stream_push_s8(&fs_path, g_shader_path_prefix);
if (fs_path.widx && fs_path.buf[fs_path.widx - 1] != platform->path_separator)
stream_push_byte(&fs_path, platform->path_separator);
- u32 fs_sidx = fs_path.widx;
- u32 vs_sidx = vs_path.widx;
- for (u32 i = 0; i < SHADER_COUNT; i++) {
- fs_path.widx = fs_sidx;
- vs_path.widx = vs_sidx;
+ shader_reload_ctx ctx = {0};
+ ctx.memory = memory;
+ i32 sidx = fs_path.widx;
+ for (u32 i = 0; i < SHADER_COUNT; i++) {
stream_push_s8(&fs_path, fs_name[i]);
stream_push_byte(&fs_path, 0);
- stream_push_s8(&vs_path, vs_name[i]);
- stream_push_byte(&vs_path, 0);
-
- FileStats fs_test = platform->get_file_stats(fs_path.buf);
- FileStats vs_test = platform->get_file_stats(vs_path.buf);
-
- if ((fs_test.timestamp <= gl->fs_stats[i].timestamp) &&
- (vs_test.timestamp <= gl->vs_stats[i].timestamp))
- continue;
-
- b32 success = 1;
-
- Stream vs_text = stream_alloc(&a, vs_test.size);
- success &= platform->read_file(vs_path.buf, &vs_text, vs_test.size);
-
- Stream fs_text = stream_alloc(&a, fs_test.size);
- success &= platform->read_file(fs_path.buf, &fs_text, fs_test.size);
-
- if (success) {
- stream_push_s8s(err, 3, (s8 []){s8("Reloading "), map[i].name, s8(" Shader!\n")});
- gl->vs_stats[i] = vs_test;
- gl->fs_stats[i] = fs_test;
-
- u32 program = program_from_shader_text(stream_to_s8(&vs_text),
- stream_to_s8(&fs_text), a);
- if (!program)
- continue;
- glDeleteProgram(gl->programs[i]);
- gl->programs[i] = program;
- if (map[i].update_uniforms)
- update_uniforms(gl, i);
- stream_push_s8s(err, 2, (s8 []){map[i].name, s8(" Program Updated!\n")});
- }
+ ctx.stage = i;
+ reload_shader(fs_path.buf, &ctx);
+ fs_path.widx = sidx;
}
- if (err->widx) {
- os_write_err_msg(stream_to_s8(err));
- err->widx = 0;
- }
+ os_write_err_msg(s8("Reloaded Shaders\n"));
+ end_temp_arena(temp_memory);
}
static v4
@@ -961,6 +969,30 @@ DEBUG_EXPORT VTGL_INITIALIZE_FN(vtgl_initialize)
.y = cs.y * requested_cells.y + 2 * g_term_margin.y,
};
+ shader_reload_ctx *shader_ctxs = alloc(&a, shader_reload_ctx, SHADER_COUNT);
+
+ s8 shader_infos[SHADER_COUNT] = {
+ [SHADER_POST] = s8("Post Processing Shader Reloaded!\n"),
+ [SHADER_RECTS] = s8("UI Shader Reloaded!\n"),
+ [SHADER_RENDER] = s8("Render Shader Reloaded!\n"),
+ };
+
+ for (u32 i = 0; i < SHADER_COUNT; i++) {
+ Stream path = arena_stream(a);
+ stream_push_s8(&path, g_shader_path_prefix);
+ if (path.widx && path.buf[path.widx - 1] != memory->platform_api.path_separator)
+ stream_push_byte(&path, memory->platform_api.path_separator);
+
+ shader_reload_ctx *src = shader_ctxs + i;
+ src->info = shader_infos[i];
+ src->stage = i;
+ src->memory = memory;
+ stream_push_s8(&path, fs_name[i]);
+ stream_push_byte(&path, 0);
+ memory->platform_api.add_file_watch(path.buf, reload_shader, src);
+ a.beg = path.buf + path.widx;
+ }
+
t->size = (uv2){.x = 1, .y = 1};
t->error_stream = stream_alloc(&a, MEGABYTE / 4);
t->saved_title = stream_alloc(&a, 16 * KILOBYTE);
@@ -1040,6 +1072,8 @@ DEBUG_EXPORT VTGL_INITIALIZE_FN(vtgl_initialize)
glActiveTexture(GL_TEXTURE0);
+ reload_all_shaders(memory);
+
return requested_size;
}
@@ -1061,7 +1095,9 @@ DEBUG_EXPORT VTGL_FRAME_STEP_FN(vtgl_frame_step)
t->temp_arena = begin_temp_arena(&t->arena_for_frame);
- check_shaders(&t->gl, t->arena_for_frame, &t->error_stream, &memory->platform_api);
+ if (input->executable_reloaded) {
+ reload_all_shaders(memory);
+ }
if (!equal_iv2(input->window_size, t->gl.window_size))
t->gl.flags |= NEEDS_RESIZE;