changeset 2484:ccee8dccd9cc

Add support for rendering debug windows with OpenGL in perparation for allowing Nuklear UI in them
author Michael Pavone <pavone@retrodev.com>
date Sun, 14 Apr 2024 11:40:32 -0700
parents 48ab1e3e5df5
children 59a299610662
files nuklear_ui/blastem_nuklear.c render_sdl.c
diffstat 2 files changed, 258 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/nuklear_ui/blastem_nuklear.c	Sun Mar 31 10:21:34 2024 -0700
+++ b/nuklear_ui/blastem_nuklear.c	Sun Apr 14 11:40:32 2024 -0700
@@ -1879,6 +1879,10 @@
 		if (entries[i].is_dir) {
 			continue;
 		}
+		if (startswith(entries[i].name, "extra_window.")) {
+			//skip shader used for debug windows
+			continue;
+		}
 		char *no_ext = basename_no_extension(entries[i].name);
 		uint32_t len = strlen(no_ext);
 		if (no_ext[len-1] == 'f' && no_ext[len-2] == '.') {
--- a/render_sdl.c	Sun Mar 31 10:21:34 2024 -0700
+++ b/render_sdl.c	Sun Apr 14 11:40:32 2024 -0700
@@ -29,13 +29,37 @@
 
 #define MAX_EVENT_POLL_PER_FRAME 2
 
+
+typedef struct {
+	SDL_Window *win;
+	SDL_Renderer         *renderer;
+	SDL_Texture          *sdl_texture;
+	window_close_handler on_close;
+	uint32_t             width;
+	uint32_t             height;
+#ifndef DISABLE_OPENGL
+	SDL_GLContext        *gl_context;
+	uint32_t             *texture_buf;
+	uint32_t             tex_width;
+	uint32_t             tex_height;
+	GLuint               gl_texture;
+	GLuint               vshader;
+	GLuint               fshader;
+	GLuint               program;
+	GLuint               gl_buffers[2];
+	GLint                un_texture;
+	GLint                un_width;
+	GLint                un_height;
+	GLint                at_pos;
+#endif
+} extra_window;
+
 static SDL_Window *main_window;
-static SDL_Window **extra_windows;
+static extra_window *extras;
 static SDL_Renderer *main_renderer;
-static SDL_Renderer **extra_renderers;
-static SDL_Texture  **sdl_textures;
+static SDL_Texture  *sdl_textures[FRAMEBUFFER_UI + 1];
 static window_close_handler *close_handlers;
-static uint8_t num_textures;
+static uint8_t num_extras;
 static SDL_Rect      main_clip;
 static SDL_GLContext *main_context;
 
@@ -480,10 +504,6 @@
 	if (texture_init) {
 		return;
 	}
-	if (!sdl_textures) {
-		sdl_textures= calloc(sizeof(SDL_Texture *), 3);
-		num_textures = 3;
-	}
 	texture_init = 1;
 #ifndef DISABLE_OPENGL
 	if (render_gl) {
@@ -502,14 +522,12 @@
 
 static void free_surfaces(void)
 {
-	for (int i = 0; i < num_textures; i++)
+	for (int i = 0; i <= FRAMEBUFFER_UI; i++)
 	{
 		if (sdl_textures[i]) {
 			SDL_DestroyTexture(sdl_textures[i]);
 		}
 	}
-	free(sdl_textures);
-	sdl_textures = NULL;
 	texture_init = 0;
 }
 
@@ -943,11 +961,11 @@
 			if (main_window && SDL_GetWindowID(main_window) == event->window.windowID) {
 				exit(0);
 			} else {
-				for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++)
+				for (int i = 0; i < num_extras; i++)
 				{
-					if (SDL_GetWindowID(extra_windows[i]) == event->window.windowID) {
-						if (close_handlers[i]) {
-							close_handlers[i](i + FRAMEBUFFER_USER_START);
+					if (SDL_GetWindowID(extras[i].win) == event->window.windowID) {
+						if (extras[i].on_close) {
+							extras[i].on_close(i + FRAMEBUFFER_USER_START);
 						}
 						break;
 					}
@@ -1293,8 +1311,7 @@
 
 void render_config_updated(void)
 {
-	int n = num_textures < FRAMEBUFFER_USER_START ? num_textures : FRAMEBUFFER_USER_START;
-	for (int i = 0; i < n; i++)
+	for (int i = 0; i <= FRAMEBUFFER_UI; i++)
 	{
 		if (sdl_textures[i]) {
 			SDL_DestroyTexture(sdl_textures[i]);
@@ -1473,72 +1490,143 @@
 	free(path);
 }
 
+void GLAPIENTRY gl_message_callback(GLenum source, GLenum type, GLenum id, GLenum severity, GLsizei length, const GLchar *message, const void *user)
+{
+	fprintf(stderr, "GL Message: %d, %d, %d - %s\n", source, type, severity, message);
+}
+
 uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler)
 {
 	uint8_t win_idx = 0xFF;
-	for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++)
+	for (int i = 0; i < num_extras; i++)
 	{
-		if (!extra_windows[i]) {
+		if (!extras[i].win) {
 			win_idx = i;
 			break;
 		}
 	}
 
 	if (win_idx == 0xFF) {
-		num_textures++;
-		sdl_textures = realloc(sdl_textures, num_textures * sizeof(*sdl_textures));
-		extra_windows = realloc(extra_windows, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_windows));
-		extra_renderers = realloc(extra_renderers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_renderers));
-		close_handlers = realloc(close_handlers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*close_handlers));
-		win_idx = num_textures - FRAMEBUFFER_USER_START - 1;
+		num_extras++;
+		extras = realloc(extras, num_extras * sizeof(*extras));
+		win_idx = num_extras - 1;
 	}
+	memset(&extras[win_idx], 0, sizeof(extra_window));
+	uint32_t flags = 0;
+#ifndef DISABLE_OPENGL
+	if (render_gl) {
+		flags |= SDL_WINDOW_OPENGL;
+	}
+#endif
 	int x = SDL_WINDOWPOS_UNDEFINED;
 	int y = SDL_WINDOWPOS_UNDEFINED;
 	SDL_GetWindowPosition(main_window, &x, &y);
 	if (x != SDL_WINDOWPOS_UNDEFINED) {
 		x += main_width;
 	}
-	extra_windows[win_idx] = SDL_CreateWindow(caption, x, y, width, height, 0);
-	if (!extra_windows[win_idx]) {
+	extras[win_idx].win = SDL_CreateWindow(caption, x, y, width, height, flags);
+	if (!extras[win_idx].win) {
 		goto fail_window;
 	}
-	extra_renderers[win_idx] = SDL_CreateRenderer(extra_windows[win_idx], -1, SDL_RENDERER_ACCELERATED);
-	if (!extra_renderers[win_idx]) {
-		goto fail_renderer;
+	extras[win_idx].width = width;
+	extras[win_idx].height = height;
+#ifndef DISABLE_OPENGL
+	if (render_gl) {
+		extras[win_idx].gl_context = SDL_GL_CreateContext(extras[win_idx].win);
+		SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
+		glEnable(GL_DEBUG_OUTPUT);
+		glDebugMessageCallback(gl_message_callback, NULL);
+		glGenTextures(1, &extras[win_idx].gl_texture);
+		glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		extras[win_idx].tex_width = width;
+		extras[win_idx].tex_height = height;
+		char *npot_textures = tern_find_path_default(config, "video\0npot_textures\0", (tern_val){.ptrval = "off"}, TVAL_PTR).ptrval;
+		if (strcmp(npot_textures, "on")) {
+			extras[win_idx].tex_width = nearest_pow2(width);
+			extras[win_idx].tex_height = nearest_pow2(height);
+		}
+		extras[win_idx].texture_buf = calloc(extras[win_idx].tex_width * extras[win_idx].tex_height, sizeof(uint32_t));
+		glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, extras[win_idx].tex_width, extras[win_idx].tex_height, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, extras[win_idx].texture_buf);
+		glGenBuffers(2, extras[win_idx].gl_buffers);
+		glBindBuffer(GL_ARRAY_BUFFER, extras[win_idx].gl_buffers[0]);
+		glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data_default), vertex_data_default, GL_STATIC_DRAW);
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, extras[win_idx].gl_buffers[1]);
+		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW);
+		extras[win_idx].vshader = load_shader("extra_window.v.glsl", GL_VERTEX_SHADER);
+		extras[win_idx].fshader = load_shader("extra_window.f.glsl", GL_FRAGMENT_SHADER);
+		extras[win_idx].program = glCreateProgram();
+		glAttachShader(program, extras[win_idx].vshader);
+		glAttachShader(program, extras[win_idx].fshader);
+		glLinkProgram(extras[win_idx].program);
+		GLint link_status;
+		glGetProgramiv(program, GL_LINK_STATUS, &link_status);
+		if (!link_status) {
+			fputs("Failed to link shader program\n", stderr);
+			//TODO: cleanup
+			goto sdl_renderer;
+		}
+		extras[win_idx].un_texture = glGetUniformLocation(program, "texture");
+		extras[win_idx].un_width = glGetUniformLocation(program, "width");
+		extras[win_idx].un_height = glGetUniformLocation(program, "height");
+		extras[win_idx].at_pos = glGetAttribLocation(program, "pos");
+	} else {
+sdl_renderer:
+#endif
+		extras[win_idx].renderer = SDL_CreateRenderer(extras[win_idx].win, -1, SDL_RENDERER_ACCELERATED);
+		if (!extras[win_idx].renderer) {
+			goto fail_renderer;
+		}
+		extras[win_idx].sdl_texture = SDL_CreateTexture(extras[win_idx].renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
+		if (!extras[win_idx].sdl_texture) {
+			goto fail_texture;
+		}
+#ifndef DISABLE_OPENGL
 	}
-	uint8_t texture_idx = win_idx + FRAMEBUFFER_USER_START;
-	sdl_textures[texture_idx] = SDL_CreateTexture(extra_renderers[win_idx], SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
-	if (!sdl_textures[texture_idx]) {
-		goto fail_texture;
-	}
-	close_handlers[win_idx] = close_handler;
-	return texture_idx;
+#endif
+	extras[win_idx].on_close = close_handler;
+	return win_idx + FRAMEBUFFER_USER_START;
 
 fail_texture:
-	SDL_DestroyRenderer(extra_renderers[win_idx]);
+	SDL_DestroyRenderer(extras[win_idx].renderer);
 fail_renderer:
-	SDL_DestroyWindow(extra_windows[win_idx]);
+	SDL_DestroyWindow(extras[win_idx].win);
 fail_window:
-	num_textures--;
 	return 0;
 }
 
 void render_destroy_window(uint8_t which)
 {
 	uint8_t win_idx = which - FRAMEBUFFER_USER_START;
-	//Destroying the renderers also frees the textures
-	SDL_DestroyRenderer(extra_renderers[win_idx]);
-	SDL_DestroyWindow(extra_windows[win_idx]);
+	if (extras[win_idx].renderer) {
+		//Destroying the renderers also frees the textures
+		SDL_DestroyRenderer(extras[win_idx].renderer);
+		extras[win_idx].renderer = NULL;
+	}
+#ifndef DISABLE_OPENGL
+	else {
+		SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
+		glDeleteProgram(extras[win_idx].program);
+		glDeleteShader(extras[win_idx].vshader);
+		glDeleteShader(extras[win_idx].fshader);
+		glDeleteBuffers(2, extras[win_idx].gl_buffers);
+		glDeleteTextures(1, &extras[win_idx].gl_texture);
+		SDL_GL_DeleteContext(extras[win_idx].gl_context);
+	}
+#endif
+	SDL_DestroyWindow(extras[win_idx].win);
 
-	extra_renderers[win_idx] = NULL;
-	extra_windows[win_idx] = NULL;
+	extras[win_idx].win = NULL;
 }
 
 SDL_Texture **static_images;
 uint8_t num_static;
 uint8_t render_static_image(uint8_t window, uint8_t *buffer, uint32_t size)
 {
-	
+	window -= FRAMEBUFFER_USER_START;
 	uint32_t width, height;
 	uint32_t *pixels = load_png(buffer, size, &width, &height);
 	if (!pixels) {
@@ -1559,7 +1647,7 @@
 		num_static *= 2;
 		static_images = realloc(static_images, num_static * sizeof(SDL_Texture*));
 	}
-	static_images[img_index] = SDL_CreateTexture(extra_renderers[window - FRAMEBUFFER_USER_START], SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height);
+	static_images[img_index] = SDL_CreateTexture(extras[window].renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height);
 	SDL_UpdateTexture(static_images[img_index], NULL, pixels, sizeof(uint32_t) * width);
 	free(pixels);
 	return img_index;
@@ -1567,36 +1655,70 @@
 
 void render_draw_image(uint8_t window, uint8_t image, int x, int y, int width, int height)
 {
-	SDL_Rect dst = {
-		.x = x,
-		.y = y,
-		.w = width,
-		.h = height
-	};
-	SDL_RenderCopy(extra_renderers[window - FRAMEBUFFER_USER_START], static_images[image], NULL, &dst);
+	uint8_t win_idx = window - FRAMEBUFFER_USER_START;
+	if (extras[win_idx].renderer) {
+		SDL_Rect dst = {
+			.x = x,
+			.y = y,
+			.w = width,
+			.h = height
+		};
+		SDL_RenderCopy(extras[win_idx].renderer, static_images[image], NULL, &dst);
+	}
+#ifndef DISABLE_OPENGL
+	else {
+		//TODO: implement me
+	}
+#endif
 }
 
 void render_clear_window(uint8_t window, uint8_t r, uint8_t g, uint8_t b)
 {
-	SDL_SetRenderDrawColor(extra_renderers[window - FRAMEBUFFER_USER_START], r, g, b, 255);
-	SDL_RenderClear(extra_renderers[window - FRAMEBUFFER_USER_START]);
+	uint8_t win_idx = window - FRAMEBUFFER_USER_START;
+	if (extras[win_idx].renderer) {
+		SDL_SetRenderDrawColor(extras[win_idx].renderer, r, g, b, 255);
+		SDL_RenderClear(extras[win_idx].renderer);
+	}
+#ifndef DISABLE_OPENGL
+	else {
+		SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
+		glClearColor(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
+		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	}
+#endif
 }
 
 void render_fill_rect(uint8_t window, uint8_t r, uint8_t g, uint8_t b, int x, int y, int width, int height)
 {
-	SDL_SetRenderDrawColor(extra_renderers[window - FRAMEBUFFER_USER_START], r, g, b, 255);
-	SDL_Rect dst = {
-		.x = x,
-		.y = y,
-		.w = width,
-		.h = height
-	};
-	SDL_RenderFillRect(extra_renderers[window - FRAMEBUFFER_USER_START], &dst);
+	uint8_t win_idx = window - FRAMEBUFFER_USER_START;
+	if (extras[win_idx].renderer) {
+		SDL_SetRenderDrawColor(extras[win_idx].renderer, r, g, b, 255);
+		SDL_Rect dst = {
+			.x = x,
+			.y = y,
+			.w = width,
+			.h = height
+		};
+		SDL_RenderFillRect(extras[win_idx].renderer, &dst);
+	}
+#ifndef DISABLE_OPENGL
+	else {
+		//TODO: implement me
+	}
+#endif
 }
 
 void render_window_refresh(uint8_t window)
 {
-	SDL_RenderPresent(extra_renderers[window - FRAMEBUFFER_USER_START]);
+	uint8_t win_idx = window - FRAMEBUFFER_USER_START;
+	if (extras[win_idx].renderer) {
+		SDL_RenderPresent(extras[win_idx].renderer);
+	}
+#ifndef DISABLE_OPENGL
+	else {
+		SDL_GL_SwapWindow(extras[win_idx].win);
+	}
+#endif
 }
 
 uint32_t *locked_pixels;
@@ -1620,17 +1742,28 @@
 	if (render_gl && which <= FRAMEBUFFER_EVEN) {
 		*pitch = LINEBUF_SIZE * sizeof(uint32_t);
 		return texture_buf;
+	} else if (render_gl && which >= FRAMEBUFFER_USER_START) {
+		uint8_t win_idx = which - FRAMEBUFFER_USER_START;
+		*pitch = extras[win_idx].width * sizeof(uint32_t);
+		return extras[win_idx].texture_buf;
 	} else {
 #endif
 		if (which == FRAMEBUFFER_UI && !sdl_textures[which]) {
 			sdl_textures[which] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, main_width, main_height);
 		}
-		if (which >= num_textures) {
-			warning("Request for invalid framebuffer number %d\n", which);
-			return NULL;
+		SDL_Texture *tex;
+		if (which >= FRAMEBUFFER_USER_START) {
+			uint8_t win_idx = which - FRAMEBUFFER_USER_START;
+			if (win_idx >= num_extras || !extras[win_idx].renderer) {
+				warning("Request for invalid framebuffer number %d\n", which);
+				return NULL;
+			}
+			tex = extras[win_idx].sdl_texture;
+		} else {
+			tex = sdl_textures[which];
 		}
 		uint8_t *pixels;
-		if (SDL_LockTexture(sdl_textures[which], NULL, (void **)&pixels, pitch) < 0) {
+		if (SDL_LockTexture(tex, NULL, (void **)&pixels, pitch) < 0) {
 			warning("Failed to lock texture: %s\n", SDL_GetError());
 			return NULL;
 		}
@@ -1684,28 +1817,30 @@
 		return;
 	}
 
-	last_width = width;
 	uint32_t height = which <= FRAMEBUFFER_EVEN
 		? (video_standard == VID_PAL ? 294 : 243) - (overscan_top[video_standard] + overscan_bot[video_standard])
 		: 240;
 	FILE *screenshot_file = NULL;
 	char *ext;
-	width -= overscan_left[video_standard] + overscan_right[video_standard];
-	if (screenshot_path && which == FRAMEBUFFER_ODD) {
-		screenshot_file = fopen(screenshot_path, "wb");
-		if (screenshot_file) {
+	if (which < FRAMEBUFFER_UI) {
+		last_width = width;
+		width -= overscan_left[video_standard] + overscan_right[video_standard];
+		if (screenshot_path && which == FRAMEBUFFER_ODD) {
+			screenshot_file = fopen(screenshot_path, "wb");
+			if (screenshot_file) {
 #ifndef DISABLE_ZLIB
-			ext = path_extension(screenshot_path);
+				ext = path_extension(screenshot_path);
 #endif
-			debug_message("Saving screenshot to %s\n", screenshot_path);
-		} else {
-			warning("Failed to open screenshot file %s for writing\n", screenshot_path);
+				debug_message("Saving screenshot to %s\n", screenshot_path);
+			} else {
+				warning("Failed to open screenshot file %s for writing\n", screenshot_path);
+			}
+			free(screenshot_path);
+			screenshot_path = NULL;
 		}
-		free(screenshot_path);
-		screenshot_path = NULL;
+		interlaced = last_field != which;
+		buffer += overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
 	}
-	interlaced = last_field != which;
-	buffer += overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
 #ifndef DISABLE_OPENGL
 	if (render_gl && which <= FRAMEBUFFER_EVEN) {
 		SDL_GL_MakeCurrent(main_window, main_context);
@@ -1735,6 +1870,11 @@
 			save_png24_frame(apng_file, buffer, apng, width, height, LINEBUF_SIZE*sizeof(uint32_t));
 		}
 #endif
+	} else if (render_gl && which >= FRAMEBUFFER_USER_START) {
+		uint8_t win_idx = which - FRAMEBUFFER_USER_START;
+		SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
+		glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture);
+		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, extras[win_idx].width, extras[win_idx].height, SRC_FORMAT, GL_UNSIGNED_BYTE, buffer);
 	} else {
 #endif
 		uint32_t shot_height = height;
@@ -1778,8 +1918,8 @@
 #ifndef DISABLE_OPENGL
 	}
 #endif
-	last_height = height;
 	if (which <= FRAMEBUFFER_EVEN) {
+		last_height = height;
 		render_update_display();
 	} else if (which == FRAMEBUFFER_UI) {
 		SDL_RenderCopy(main_renderer, sdl_textures[which], NULL, NULL);
@@ -1792,8 +1932,34 @@
 			need_ui_fb_resize = 0;
 		}
 	} else {
-		SDL_RenderCopy(extra_renderers[which - FRAMEBUFFER_USER_START], sdl_textures[which], NULL, NULL);
-		SDL_RenderPresent(extra_renderers[which - FRAMEBUFFER_USER_START]);
+		uint8_t win_idx = which - FRAMEBUFFER_USER_START;
+		if (extras[win_idx].renderer) {
+			SDL_RenderCopy(extras[win_idx].renderer, extras[win_idx].sdl_texture, NULL, NULL);
+			SDL_RenderPresent(extras[win_idx].renderer);
+		}
+#ifndef DISABLE_OPENGL
+		else {
+			glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+			
+			glUseProgram(extras[win_idx].program);
+			glActiveTexture(GL_TEXTURE0);
+			glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture);
+			glUniform1i(extras[win_idx].un_texture, 0);
+			
+			glUniform1f(extras[win_idx].un_width, (float)extras[win_idx].width / (float)extras[win_idx].tex_width);
+			glUniform1f(extras[win_idx].un_height, (float)extras[win_idx].height / (float)extras[win_idx].tex_height);
+			
+			glBindBuffer(GL_ARRAY_BUFFER, extras[win_idx].gl_buffers[0]);
+			glVertexAttribPointer(extras[win_idx].at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0);
+			glEnableVertexAttribArray(extras[win_idx].at_pos);
+			
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, extras[win_idx].gl_buffers[1]);
+			glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0);
+			
+			SDL_GL_SwapWindow(extras[win_idx].win);
+		}
+#endif
 	}
 	if (screenshot_file) {
 		fclose(screenshot_file);
@@ -1920,7 +2086,7 @@
 		return;
 	}
 	//TODO: Maybe fixme for render API
-	process_framebuffer(texture_buf, which, width);
+	process_framebuffer(which < FRAMEBUFFER_USER_START ? texture_buf : extras[which - FRAMEBUFFER_USER_START].texture_buf, which, width);
 }
 
 void render_video_loop(void)
@@ -2263,9 +2429,9 @@
 	if (SDL_GetWindowFlags(main_window) & SDL_WINDOW_INPUT_FOCUS) {
 		return FRAMEBUFFER_ODD;
 	}
-	for (int i = 0; i < num_textures - 2; i++)
+	for (int i = 0; i < num_extras; i++)
 	{
-		if (extra_windows[i] && (SDL_GetWindowFlags(extra_windows[i]) & SDL_WINDOW_INPUT_FOCUS)) {
+		if (extras[i].win && (SDL_GetWindowFlags(extras[i].win) & SDL_WINDOW_INPUT_FOCUS)) {
 			return FRAMEBUFFER_USER_START + i;
 		}
 	}