Commit: 9ba075f585cbbe92375a653b80b8206af4b0890c
Parent: 5232c4700ed13bd370bba4300d754cdc00beadb1
Author: Randy Palamar
Date: Sat, 26 Apr 2025 09:00:05 -0600
debug: ensure render thread is running valid code when hot reloading
Diffstat:
M | os_linux_common.c | | | 4 | +--- |
M | os_linux_x11.c | | | 33 | ++++++++++++++++----------------- |
M | util.h | | | 7 | +++++-- |
M | vtgl.c | | | 158 | ++----------------------------------------------------------------------------- |
M | vtgl.h | | | 13 | +++++++++---- |
M | vtgl_static.c | | | 166 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
6 files changed, 198 insertions(+), 183 deletions(-)
diff --git a/os_linux_common.c b/os_linux_common.c
@@ -61,9 +61,7 @@ typedef __attribute__((aligned(16))) u8 statx_buffer[256];
#define TIOCSPTLCK 0x40045431 /* (un)lock pty */
#define TIOCGPTN 0x80045430 /* get pty number */
-#ifndef VERSION
-#define VERSION "unknown"
-#endif
+#define OS_PATH_SEPERATOR "/"
#define OS_MAP_READ PROT_READ
#define OS_MAP_PRIVATE MAP_PRIVATE
diff --git a/os_linux_x11.c b/os_linux_x11.c
@@ -21,20 +21,27 @@ i32 XPending(void *display);
#define do_debug(...)
#include "vtgl.c"
#else
-#include <dlfcn.h>
-
-#define DEBUG_LIB_NAME "./vtgl.so"
-
#define DEBUG_LIB_FUNCTIONS \
- X(vtgl_active_selection) \
- X(vtgl_handle_keys) \
- X(vtgl_frame_step) \
- X(vtgl_render_thread_entry)
+ X(vtgl_active_selection) \
+ X(vtgl_frame_step) \
+ X(vtgl_handle_keys) \
+ X(vtgl_render_frame)
#define X(name) global name ## _fn *name;
DEBUG_LIB_FUNCTIONS
#undef X
+#include "config.h"
+#include "font.c"
+#endif
+
+#include "vtgl_static.c"
+
+#ifdef _DEBUG
+#include <dlfcn.h>
+
+#define DEBUG_LIB_NAME "./vtgl.so"
+
function OS_FILE_WATCH_CALLBACK_FN(debug_reload_library)
{
PlatformCtx *ctx = user_ctx;
@@ -42,8 +49,7 @@ function OS_FILE_WATCH_CALLBACK_FN(debug_reload_library)
if (ctx->input.executable_reloaded)
return;
- /* NOTE(rnp): spin until render thread finishes its work */
- //while (!ctx->render_stack->thread_asleep);
+ vtgl_wait_complete_work(&ctx->memory);
ctx->input.executable_reloaded = 1;
s8 nl = s8("\n");
@@ -68,15 +74,8 @@ function OS_FILE_WATCH_CALLBACK_FN(debug_reload_library)
stream_reset(&ctx->error_stream, 0);
}
-#include "config.h"
-#include "font.c"
-
#endif /* _DEBUG */
-#define OS_PATH_SEPERATOR "/"
-
-#include "vtgl_static.c"
-
function void
glfw_error_callback(int code, const char *desc)
{
diff --git a/util.h b/util.h
@@ -480,8 +480,7 @@ typedef struct {
Arena arena;
/* TODO(rnp): cleanup */
- TerminalInput *input;
- TerminalMemory *memory;
+ TerminalInput *input;
iptr window;
iv2 monitor_size;
@@ -492,6 +491,8 @@ typedef struct {
i32 *sync;
ShaderReloadContext shader_reload_contexts[SID_LAST];
+
+ b32 running;
} RenderThreadContext;
typedef enum {
@@ -544,6 +545,8 @@ typedef struct {
OS *os;
} Term;
+#define LABEL_GL_OBJECT(type, id, s) {s8 _s = (s); glObjectLabel(type, id, _s.len, (c8 *)_s.data);}
+
global f32 dt_for_frame;
#endif /* _UTIL_H_ */
diff --git a/vtgl.c b/vtgl.c
@@ -23,8 +23,6 @@
#include "font.c"
#include "terminal.c"
-#define LABEL_GL_OBJECT(type, id, s) {s8 _s = (s); glObjectLabel(type, id, _s.len, (c8 *)_s.data);}
-
#define REVERSE_VIDEO_MASK (Colour){.r = 0xff, .g = 0xff, .b = 0xff}.rgba
#define VERTEX_SHADER_TEXT \
@@ -1003,63 +1001,14 @@ handle_interactions(Term *t, TerminalInput *input, OS *os)
}
}
-function void
-gl_debug_logger(u32 src, u32 type, u32 id, u32 lvl, i32 len, const char *msg, const void *data)
-{
- (void)src; (void)type; (void)id;
-
- Stream *err = (Stream *)data;
- stream_push_s8(err, s8("[GL Error "));
- switch (lvl) {
- case GL_DEBUG_SEVERITY_HIGH: stream_push_s8(err, s8("HIGH]: ")); break;
- case GL_DEBUG_SEVERITY_MEDIUM: stream_push_s8(err, s8("MEDIUM]: ")); break;
- case GL_DEBUG_SEVERITY_LOW: stream_push_s8(err, s8("LOW]: ")); break;
- case GL_DEBUG_SEVERITY_NOTIFICATION: stream_push_s8(err, s8("NOTIFICATION]: ")); break;
- default: stream_push_s8(err, s8("INVALID]: ")); break;
- }
- stream_push_s8(err, (s8){.len = len, .data = (u8 *)msg});
- stream_push_byte(err, '\n');
- os_write_err_msg(stream_to_s8(err));
- stream_reset(err, 0);
-}
-
-function u32
-gen_2D_texture(iv2 size, u32 format, u32 filter, u32 *rgba)
-{
- /* TODO: logging */
- u32 result;
- glGenTextures(1, &result);
- glBindTexture(GL_TEXTURE_2D, result);
- glTexImage2D(GL_TEXTURE_2D, 0, format, size.w, size.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
- return result;
-}
-
-function b32
-try_wait_sync(i32 *sync, i32 timeout_ms, os_wait_on_value_fn *os_wait_on_value)
-{
- b32 result = 0;
- for (;;) {
- i32 current = atomic_load(sync);
- if (current && atomic_cas(sync, ¤t, 0)) {
- result = 1;
- break;
- }
- if (!timeout_ms || !os_wait_on_value(sync, 0, timeout_ms))
- break;
- }
- return result;
-}
-
-function void
-vtgl_render_frame(OS *os, RenderThreadContext *ctx, TerminalMemory *memory,
- TerminalInput *input, Arena arena)
+DEBUG_EXPORT VTGL_RENDER_FRAME_FN(vtgl_render_frame)
{
BEGIN_TIMED_BLOCK();
Term *t = memory->memory;
+ RenderThreadContext *ctx = &t->render_thread;
+ Arena arena = ctx->arena;
dt_for_frame = input->dt;
WorkQueueWork *work = work_queue_pop(&ctx->work_queue);
@@ -1152,107 +1101,6 @@ vtgl_render_frame(OS *os, RenderThreadContext *ctx, TerminalMemory *memory,
END_TIMED_BLOCK();
}
-function void
-vtgl_render_thread_initialize(OS *os, RenderThreadContext *ctx)
-{
- os->gl_make_context_current(ctx->window);
-
- ctx->error_stream = stream_alloc(&ctx->arena, KB(1));
-
- Arena a = ctx->arena;
-
- glDebugMessageCallback(gl_debug_logger, &ctx->error_stream);
- glEnable(GL_DEBUG_OUTPUT);
- /* NOTE: shut up useless shader compilation statistics */
- glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
- GL_DEBUG_SEVERITY_NOTIFICATION,
- 0, 0, GL_FALSE);
-
- glGenVertexArrays(1, &ctx->gl.vao);
- glBindVertexArray(ctx->gl.vao);
-
- glGenBuffers(ARRAY_COUNT(ctx->gl.vbos), ctx->gl.vbos);
-
- RenderPushBuffer *rpb = 0;
- /* NOTE: vertex position buffer */
- glBindBuffer(GL_ARRAY_BUFFER, ctx->gl.vbos[0]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(rpb->positions), 0, GL_DYNAMIC_DRAW);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, 0);
-
- /* NOTE: vertex texture coordinate buffer */
- glBindBuffer(GL_ARRAY_BUFFER, ctx->gl.vbos[1]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(rpb->texture_coordinates), 0, GL_DYNAMIC_DRAW);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
-
- /* NOTE: vertex colour buffer */
- glBindBuffer(GL_ARRAY_BUFFER, ctx->gl.vbos[2]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(rpb->colours), 0, GL_DYNAMIC_DRAW);
- glEnableVertexAttribArray(2);
- glVertexAttribPointer(2, 4, GL_FLOAT, 0, 0, 0);
-
- /* NOTE: fill in element index buffer */
- i32 *element_indices = alloc(&a, i32, 6 * ARRAY_COUNT(rpb->positions));
- for (i32 i = 0, j = 0; i < 6 * ARRAY_COUNT(rpb->positions); i += 6, j++) {
- element_indices[i + 0] = 4 * j;
- element_indices[i + 1] = 4 * j + 1;
- element_indices[i + 2] = 4 * j + 2;
- element_indices[i + 3] = 4 * j;
- element_indices[i + 4] = 4 * j + 2;
- element_indices[i + 5] = 4 * j + 3;
- }
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ctx->gl.vbos[4]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * ARRAY_COUNT(rpb->positions) * sizeof(i32),
- element_indices, GL_STATIC_DRAW);
-
- ctx->gl.glyph_bitmap_tex = gen_2D_texture(ctx->gl.glyph_bitmap_dim, GL_RGBA, GL_NEAREST, 0);
- /* NOTE: set pixel 0,0 to white (tile 0,0 is reserved). We can use this texture for
- * drawing glyphs from the font cache or for drawing plain rectangles */
- u32 white = 0xFFFFFFFF;
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &white);
- LABEL_GL_OBJECT(GL_TEXTURE, ctx->gl.glyph_bitmap_tex, s8("Glyph_Bitmap"));
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
-
- /* NOTE: Generate an intermediate framebuffer for rendering to. This
- * allows for additional post processing via a second shader stage */
- glGenFramebuffers(1, &ctx->gl.fb);
- glBindFramebuffer(GL_FRAMEBUFFER, ctx->gl.fb);
-
- ctx->gl.fb_tex_unit = 1;
- glActiveTexture(GL_TEXTURE0 + ctx->gl.fb_tex_unit);
- iv2 ws = ctx->monitor_size;
- ctx->gl.fb_tex = gen_2D_texture(ws, GL_RGBA, GL_NEAREST, 0);
- glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ctx->gl.fb_tex, 0);
- LABEL_GL_OBJECT(GL_TEXTURE, ctx->gl.fb_tex, s8("Framebuffer_Texture"));
-
- glGenBuffers(1, &ctx->gl.render_shader_ubo);
- glBindBuffer(GL_UNIFORM_BUFFER, ctx->gl.render_shader_ubo);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(ShaderParameters), 0, GL_DYNAMIC_DRAW);
- glBindBufferBase(GL_UNIFORM_BUFFER, 0, ctx->gl.render_shader_ubo);
- LABEL_GL_OBJECT(GL_BUFFER, ctx->gl.render_shader_ubo, s8("ShaderParameters"));
-
- glActiveTexture(GL_TEXTURE0);
-}
-
-DEBUG_EXPORT OS_THREAD_ENTRY_POINT_FN(vtgl_render_thread_entry)
-{
- RenderThreadContext *ctx = (RenderThreadContext *)context;
-
- vtgl_render_thread_initialize(os, ctx);
- for (;;) {
- try_wait_sync(sync, -1, os->wait_on_value);
- vtgl_render_frame(os, ctx, ctx->memory, ctx->input, ctx->arena);
- os->gl_swap_buffers(ctx->window);
- }
- return 0;
-}
-
DEBUG_EXPORT VTGL_ACTIVE_SELECTION_FN(vtgl_active_selection)
{
Term *t = memory->memory;
diff --git a/vtgl.h b/vtgl.h
@@ -2,6 +2,10 @@
#ifndef _VTGL_H_
#define _VTGL_H_
+#ifndef VERSION
+#define VERSION "unknown"
+#endif
+
#include <stddef.h>
#include <stdint.h>
@@ -276,7 +280,7 @@ typedef struct {
u8 ended_down;
} ButtonState;
-typedef struct TerminalInput {
+typedef struct {
ButtonState keys[INPUT_KEY_COUNT];
iv2 window_size;
@@ -299,7 +303,7 @@ typedef struct TerminalInput {
f32 dt;
} TerminalInput;
-typedef struct TerminalMemory {
+typedef struct {
u64 memory_size;
void *memory;
@@ -313,6 +317,9 @@ typedef struct TerminalMemory {
#define VTGL_FRAME_STEP_FN(name) void name(OS *os, TerminalMemory *memory, TerminalInput *input)
typedef VTGL_FRAME_STEP_FN(vtgl_frame_step_fn);
+#define VTGL_RENDER_FRAME_FN(name) void name(OS *os, TerminalMemory *memory, TerminalInput *input)
+typedef VTGL_RENDER_FRAME_FN(vtgl_render_frame_fn);
+
#define VTGL_ACTIVE_SELECTION_FN(name) Range name(TerminalMemory *memory, Stream *out)
typedef VTGL_ACTIVE_SELECTION_FN(vtgl_active_selection_fn);
@@ -321,8 +328,6 @@ typedef VTGL_ACTIVE_SELECTION_FN(vtgl_active_selection_fn);
InputModifier modifiers)
typedef VTGL_HANDLE_KEYS_FN(vtgl_handle_keys_fn);
-typedef OS_THREAD_ENTRY_POINT_FN(vtgl_render_thread_entry_fn);
-
#include "util.h"
#include "util.c"
diff --git a/vtgl_static.c b/vtgl_static.c
@@ -3,6 +3,16 @@
#define static_path_join(a, b) (a OS_PATH_SEPERATOR b)
+#ifdef _DEBUG
+/* NOTE(rnp): spins until render thread finishes its work */
+function void
+vtgl_wait_complete_work(TerminalMemory *memory)
+{
+ RenderThreadContext *ctx = &((Term *)memory->memory)->render_thread;
+ while (ctx->running);
+}
+#endif
+
function OS_FILE_WATCH_CALLBACK_FN(queue_shader_reload)
{
ShaderReloadContext *src = user_ctx;
@@ -14,6 +24,159 @@ function OS_FILE_WATCH_CALLBACK_FN(queue_shader_reload)
}
}
+function void
+gl_debug_logger(u32 src, u32 type, u32 id, u32 lvl, i32 len, const char *msg, const void *data)
+{
+ (void)src; (void)type; (void)id;
+
+ Stream *err = (Stream *)data;
+ stream_push_s8(err, s8("[GL Error "));
+ switch (lvl) {
+ case GL_DEBUG_SEVERITY_HIGH: stream_push_s8(err, s8("HIGH]: ")); break;
+ case GL_DEBUG_SEVERITY_MEDIUM: stream_push_s8(err, s8("MEDIUM]: ")); break;
+ case GL_DEBUG_SEVERITY_LOW: stream_push_s8(err, s8("LOW]: ")); break;
+ case GL_DEBUG_SEVERITY_NOTIFICATION: stream_push_s8(err, s8("NOTIFICATION]: ")); break;
+ default: stream_push_s8(err, s8("INVALID]: ")); break;
+ }
+ stream_push_s8(err, (s8){.len = len, .data = (u8 *)msg});
+ stream_push_byte(err, '\n');
+ os_write_err_msg(stream_to_s8(err));
+ stream_reset(err, 0);
+}
+
+function u32
+gen_2D_texture(iv2 size, u32 format, u32 filter, u32 *rgba)
+{
+ /* TODO: logging */
+ u32 result;
+ glGenTextures(1, &result);
+ glBindTexture(GL_TEXTURE_2D, result);
+ glTexImage2D(GL_TEXTURE_2D, 0, format, size.w, size.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+ return result;
+}
+
+function b32
+try_wait_sync(i32 *sync, i32 timeout_ms, os_wait_on_value_fn *os_wait_on_value)
+{
+ b32 result = 0;
+ for (;;) {
+ i32 current = atomic_load(sync);
+ if (current && atomic_cas(sync, ¤t, 0)) {
+ result = 1;
+ break;
+ }
+ if (!timeout_ms || !os_wait_on_value(sync, 0, timeout_ms))
+ break;
+ }
+ return result;
+}
+
+
+function void
+vtgl_render_thread_initialize(OS *os, RenderThreadContext *ctx)
+{
+ os->gl_make_context_current(ctx->window);
+
+ ctx->error_stream = stream_alloc(&ctx->arena, KB(1));
+
+ Arena a = ctx->arena;
+
+ glDebugMessageCallback(gl_debug_logger, &ctx->error_stream);
+ glEnable(GL_DEBUG_OUTPUT);
+ /* NOTE: shut up useless shader compilation statistics */
+ glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
+ GL_DEBUG_SEVERITY_NOTIFICATION,
+ 0, 0, GL_FALSE);
+
+ glGenVertexArrays(1, &ctx->gl.vao);
+ glBindVertexArray(ctx->gl.vao);
+
+ glGenBuffers(ARRAY_COUNT(ctx->gl.vbos), ctx->gl.vbos);
+
+ RenderPushBuffer *rpb = 0;
+ /* NOTE: vertex position buffer */
+ glBindBuffer(GL_ARRAY_BUFFER, ctx->gl.vbos[0]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(rpb->positions), 0, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, 0);
+
+ /* NOTE: vertex texture coordinate buffer */
+ glBindBuffer(GL_ARRAY_BUFFER, ctx->gl.vbos[1]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(rpb->texture_coordinates), 0, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
+
+ /* NOTE: vertex colour buffer */
+ glBindBuffer(GL_ARRAY_BUFFER, ctx->gl.vbos[2]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(rpb->colours), 0, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(2);
+ glVertexAttribPointer(2, 4, GL_FLOAT, 0, 0, 0);
+
+ /* NOTE: fill in element index buffer */
+ i32 *element_indices = alloc(&a, i32, 6 * ARRAY_COUNT(rpb->positions));
+ for (i32 i = 0, j = 0; i < 6 * ARRAY_COUNT(rpb->positions); i += 6, j++) {
+ element_indices[i + 0] = 4 * j;
+ element_indices[i + 1] = 4 * j + 1;
+ element_indices[i + 2] = 4 * j + 2;
+ element_indices[i + 3] = 4 * j;
+ element_indices[i + 4] = 4 * j + 2;
+ element_indices[i + 5] = 4 * j + 3;
+ }
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ctx->gl.vbos[4]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * ARRAY_COUNT(rpb->positions) * sizeof(i32),
+ element_indices, GL_STATIC_DRAW);
+
+ ctx->gl.glyph_bitmap_tex = gen_2D_texture(ctx->gl.glyph_bitmap_dim, GL_RGBA, GL_NEAREST, 0);
+ /* NOTE: set pixel 0,0 to white (tile 0,0 is reserved). We can use this texture for
+ * drawing glyphs from the font cache or for drawing plain rectangles */
+ u32 white = 0xFFFFFFFF;
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &white);
+ LABEL_GL_OBJECT(GL_TEXTURE, ctx->gl.glyph_bitmap_tex, s8("Glyph_Bitmap"));
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+
+ /* NOTE: Generate an intermediate framebuffer for rendering to. This
+ * allows for additional post processing via a second shader stage */
+ glGenFramebuffers(1, &ctx->gl.fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, ctx->gl.fb);
+
+ ctx->gl.fb_tex_unit = 1;
+ glActiveTexture(GL_TEXTURE0 + ctx->gl.fb_tex_unit);
+ iv2 ws = ctx->monitor_size;
+ ctx->gl.fb_tex = gen_2D_texture(ws, GL_RGBA, GL_NEAREST, 0);
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ctx->gl.fb_tex, 0);
+ LABEL_GL_OBJECT(GL_TEXTURE, ctx->gl.fb_tex, s8("Framebuffer_Texture"));
+
+ glGenBuffers(1, &ctx->gl.render_shader_ubo);
+ glBindBuffer(GL_UNIFORM_BUFFER, ctx->gl.render_shader_ubo);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(ShaderParameters), 0, GL_DYNAMIC_DRAW);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, ctx->gl.render_shader_ubo);
+ LABEL_GL_OBJECT(GL_BUFFER, ctx->gl.render_shader_ubo, s8("ShaderParameters"));
+
+ glActiveTexture(GL_TEXTURE0);
+}
+
+function OS_THREAD_ENTRY_POINT_FN(vtgl_render_thread_entry)
+{
+ TerminalMemory *memory = (TerminalMemory *)context;
+ RenderThreadContext *ctx = &((Term *)memory->memory)->render_thread;
+ vtgl_render_thread_initialize(os, ctx);
+ for (;;) {
+ ctx->running = 0;
+ try_wait_sync(sync, -1, os->wait_on_value);
+ ctx->running = 1;
+ vtgl_render_frame(os, memory, ctx->input);
+ os->gl_swap_buffers(ctx->window);
+ }
+ return 0;
+}
+
function iv2
vtgl_initialize(OS *os, TerminalMemory *memory, TerminalInput *input, void *window, iptr child,
iv2 requested_cells, iv2 monitor_size)
@@ -40,7 +203,6 @@ vtgl_initialize(OS *os, TerminalMemory *memory, TerminalInput *input, void *wind
RenderThreadContext *rtc = &t->render_thread;
rtc->arena = sub_arena(&a, MB(8));
rtc->input = input;
- rtc->memory = memory;
rtc->window = (iptr)window;
rtc->monitor_size = monitor_size;
rtc->gl.glyph_bitmap_dim = monitor_size;
@@ -73,7 +235,7 @@ vtgl_initialize(OS *os, TerminalMemory *memory, TerminalInput *input, void *wind
}
os->gl_make_context_current(0);
- rtc->sync = os->spawn_thread(os, vtgl_render_thread_entry, "[render]", (iptr)rtc);
+ rtc->sync = os->spawn_thread(os, vtgl_render_thread_entry, "[render]", (iptr)memory);
t->size = (iv2){.x = 1, .y = 1};
t->state |= TS_NEEDS_RESIZE;