Reduce per OS Window VRAM usage for windows that use layered rendering, such as translucent windows.

The texture used as the intermediate rendering target is now shared between
all OS Windows instead of each OS Window having its own.

Fixes #9600
Fixes #9599
This commit is contained in:
copilot-swe-agent[bot] 2026-03-04 08:04:11 +00:00 committed by Kovid Goyal
parent 0170c2c0c6
commit f7a4bf6be2
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 32 additions and 13 deletions

View file

@ -1400,18 +1400,28 @@ start_os_window_rendering(OSWindow *os_window, Tab *tab) {
// note that during live resize rendering is done in layers
if (os_window->live_resize.in_progress) blank_os_window(os_window);
if (os_window->needs_layers) {
if (os_window->indirect_output.width != os_window->viewport_width || os_window->indirect_output.height != os_window->viewport_height) {
if (os_window->indirect_output.texture_id) free_texture(&os_window->indirect_output.texture_id);
if (os_window->indirect_output.framebuffer_id) free_framebuffer(&os_window->indirect_output.framebuffer_id);
// Ensure the global shared texture is large enough for this window
if (global_state.layers_render_texture.width < os_window->viewport_width ||
global_state.layers_render_texture.height < os_window->viewport_height) {
if (global_state.layers_render_texture.texture_id) free_texture(&global_state.layers_render_texture.texture_id);
if (global_state.layers_render_texture.framebuffer_id) free_framebuffer(&global_state.layers_render_texture.framebuffer_id);
unsigned new_w = (unsigned)MAX(global_state.layers_render_texture.width, os_window->viewport_width);
unsigned new_h = (unsigned)MAX(global_state.layers_render_texture.height, os_window->viewport_height);
setup_texture_as_render_target(new_w, new_h, &global_state.layers_render_texture.texture_id, &global_state.layers_render_texture.framebuffer_id);
global_state.layers_render_texture.width = (int)new_w;
global_state.layers_render_texture.height = (int)new_h;
global_state.layers_render_texture.texture_generation++;
}
if (os_window->indirect_output.texture_id == 0) {
os_window->indirect_output.width = os_window->viewport_width;
os_window->indirect_output.height = os_window->viewport_height;
setup_texture_as_render_target((unsigned) os_window->viewport_width, (unsigned)os_window->viewport_height, &os_window->indirect_output.texture_id, &os_window->indirect_output.framebuffer_id);
// Create per-window framebuffer if needed and attach the global texture to it
if (!os_window->indirect_output.framebuffer_id) glGenFramebuffers(1, &os_window->indirect_output.framebuffer_id);
if (os_window->indirect_output.attached_texture_generation != global_state.layers_render_texture.texture_generation) {
bind_framebuffer_for_output(os_window->indirect_output.framebuffer_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, global_state.layers_render_texture.texture_id, 0);
os_window->indirect_output.attached_texture_generation = global_state.layers_render_texture.texture_generation;
}
set_framebuffer_to_use_for_output(os_window->indirect_output.framebuffer_id);
bind_framebuffer_for_output(0);
save_viewport_using_bottom_left_origin(0, 0, os_window->indirect_output.width, os_window->indirect_output.height);
save_viewport_using_bottom_left_origin(0, 0, os_window->viewport_width, os_window->viewport_height);
clear_current_framebuffer();
draw_bg_image(os_window, tab);
}
@ -1425,8 +1435,10 @@ stop_os_window_rendering(OSWindow *os_window, Tab *tab, Window *active_window) {
bind_framebuffer_for_output(0);
bind_program(BLIT_PROGRAM);
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
glBindTexture(GL_TEXTURE_2D, os_window->indirect_output.texture_id);
glUniform4f(blit_program_layout.uniforms.src_rect, 0, 1, 1, 0);
glBindTexture(GL_TEXTURE_2D, global_state.layers_render_texture.texture_id);
float sx = global_state.layers_render_texture.width > 0 ? (float)os_window->viewport_width / (float)global_state.layers_render_texture.width : 1.f;
float sy = global_state.layers_render_texture.height > 0 ? (float)os_window->viewport_height / (float)global_state.layers_render_texture.height : 1.f;
glUniform4f(blit_program_layout.uniforms.src_rect, 0, sy, sx, 0);
glUniform4f(blit_program_layout.uniforms.dest_rect, -1, 1, 1, -1);
restore_viewport();
if (os_window->live_resize.in_progress) save_viewport_using_top_left_origin(

View file

@ -491,7 +491,6 @@ destroy_os_window_item(OSWindow *w) {
free(w->tabs); w->tabs = NULL;
free_bgimage(&w->bgimage, true);
zero_at_ptr(&w->bgimage);
if (w->indirect_output.texture_id) free_texture(&w->indirect_output.texture_id);
if (w->indirect_output.framebuffer_id) free_framebuffer(&w->indirect_output.framebuffer_id);
}
@ -507,6 +506,11 @@ remove_os_window(id_type os_window_id) {
REMOVER(global_state.os_windows, os_window_id, global_state.num_os_windows, destroy_os_window_item, global_state.capacity);
END_WITH_OS_WINDOW_REFS
update_os_window_references();
if (global_state.num_os_windows == 0) {
if (global_state.layers_render_texture.texture_id) free_texture(&global_state.layers_render_texture.texture_id);
if (global_state.layers_render_texture.framebuffer_id) free_framebuffer(&global_state.layers_render_texture.framebuffer_id);
global_state.layers_render_texture.width = 0; global_state.layers_render_texture.height = 0;
}
}
return found;
}

View file

@ -312,8 +312,7 @@ typedef struct OSWindow {
Tab *tabs;
BackgroundImage *bgimage;
struct {
uint32_t texture_id, framebuffer_id;
int width, height;
uint32_t framebuffer_id, attached_texture_generation;
} indirect_output;
unsigned int active_tab, num_tabs, capacity, last_active_tab, last_num_tabs, last_active_window_id;
bool focused_at_last_render, needs_render, needs_layers;
@ -403,6 +402,10 @@ typedef struct GlobalState {
id_type id; bool drag_started;
double x, y;
} tab_being_dragged;
struct {
uint32_t texture_id, framebuffer_id, texture_generation;
int width, height;
} layers_render_texture;
} GlobalState;
extern GlobalState global_state;