diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 055506d1c..6d7b9bb9b 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -689,7 +689,7 @@ render(monotonic_t now, bool input_read) { if (!w->fonts_data) { log_error("No fonts data found for window id: %llu", w->id); continue; } if (prepare_to_render_os_window(w, now, &active_window_id, &active_window_bg, &num_visible_windows, &all_windows_have_same_bg)) needs_render = true; if (w->last_active_window_id != active_window_id || w->last_active_tab != w->active_tab || w->focused_at_last_render != w->is_focused) needs_render = true; - if (w->render_calls < 3 && w->bgimage != NULL) needs_render = true; + if (w->render_calls < 3 && w->bgimage.texture_id) needs_render = true; if (needs_render) render_os_window(w, now, active_window_id, active_window_bg, num_visible_windows, all_windows_have_same_bg); } last_render_at = now; diff --git a/kitty/graphics.h b/kitty/graphics.h index b9abcbd19..4c62cbb37 100644 --- a/kitty/graphics.h +++ b/kitty/graphics.h @@ -59,6 +59,7 @@ typedef struct { uint32_t texture_id; unsigned int height, width; uint8_t* bitmap; + bool load_failed, needs_free; } BackgroundImage; typedef struct { diff --git a/kitty/shaders.c b/kitty/shaders.c index 21e40a001..5ac7cfc23 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -349,7 +349,7 @@ draw_bg(int program, OSWindow *w) { glUniform1f(glGetUniformLocation(program_id(program), "width"), (float)(w->window_width)); glActiveTexture(GL_TEXTURE0 + BGIMAGE_UNIT); - glBindTexture(GL_TEXTURE_2D, w->bgimage->texture_id); + glBindTexture(GL_TEXTURE_2D, w->bgimage.texture_id); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); unbind_vertex_array(); @@ -433,7 +433,7 @@ draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWind if (OPT(background_opacity) != 0.0) glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); - if (screen->grman->num_of_below_refs || w->bgimage != NULL) { + if (screen->grman->num_of_below_refs || w->bgimage.texture_id) { draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_below_refs); bind_program(CELL_BG_PROGRAM); // draw background for non-default bg cells @@ -595,10 +595,10 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL ); #undef SCALE if (os_window->is_semi_transparent) { - if (screen->grman->count || os_window->bgimage != NULL) draw_cells_interleaved_premult(vao_idx, gvao_idx, screen, os_window); + if (screen->grman->count || os_window->bgimage.texture_id) draw_cells_interleaved_premult(vao_idx, gvao_idx, screen, os_window); else draw_cells_simple(vao_idx, gvao_idx, screen); } else { - if (screen->grman->num_of_negative_refs || screen->grman->num_of_below_refs || os_window->bgimage != NULL) draw_cells_interleaved(vao_idx, gvao_idx, screen, os_window); + if (screen->grman->num_of_negative_refs || screen->grman->num_of_below_refs || os_window->bgimage.texture_id) draw_cells_interleaved(vao_idx, gvao_idx, screen, os_window); else draw_cells_simple(vao_idx, gvao_idx, screen); } } @@ -642,7 +642,7 @@ create_border_vao(void) { void draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_buf, bool rect_data_is_dirty, uint32_t viewport_width, uint32_t viewport_height, color_type active_window_bg, unsigned int num_visible_windows, bool all_windows_have_same_bg, OSWindow *w) { - if (w->bgimage != NULL) { + if (w->bgimage.texture_id) { glEnable(GL_BLEND); BLEND_ONTO_OPAQUE; draw_bg((OPT(background_image_layout) == TILING || OPT(background_image_layout) == MIRRORED) ? BGIMAGE_TILED_PROGRAM : BGIMAGE_PROGRAM, w); @@ -670,7 +670,7 @@ draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *rect_bu unbind_vertex_array(); unbind_program(); } - if (w->bgimage != NULL) glDisable(GL_BLEND); + if (w->bgimage.texture_id) glDisable(GL_BLEND); } // }}} diff --git a/kitty/state.c b/kitty/state.c index dac1535cc..2c7ddc559 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -84,16 +84,9 @@ add_os_window() { bool wants_bg = OPT(background_image) && OPT(background_image)[0] != 0; if (wants_bg) { - bool has_bg; - has_bg = global_state.bgimage != NULL; - - if (!has_bg) { - BackgroundImage* bgimage = calloc(1, sizeof(BackgroundImage)); + if (!global_state.bgimage.texture_id && !global_state.bgimage.load_failed) { size_t size; - - has_bg = png_path_to_bitmap(OPT(background_image), &bgimage->bitmap, &bgimage->width, &bgimage->height, &size); - if (has_bg) { - bgimage->texture_id = 0; + if (png_path_to_bitmap(OPT(background_image), &global_state.bgimage.bitmap, &global_state.bgimage.width, &global_state.bgimage.height, &size)) { RepeatStrategy r; switch (OPT(background_image_layout)) { case SCALED: @@ -104,14 +97,16 @@ add_os_window() { default: r = REPEAT_DEFAULT; break; } - send_image_to_gpu(&bgimage->texture_id, bgimage->bitmap, bgimage->width, - bgimage->height, false, true, OPT(background_image_linear), r); - ans->bgimage = bgimage; - global_state.bgimage = bgimage; - } - } else { - // Reusing already loaded bgimage - ans->bgimage = global_state.bgimage; + global_state.bgimage.texture_id = 0; + send_image_to_gpu(&global_state.bgimage.texture_id, global_state.bgimage.bitmap, global_state.bgimage.width, + global_state.bgimage.height, false, true, OPT(background_image_linear), r); + global_state.bgimage.needs_free = true; + free(global_state.bgimage.bitmap); global_state.bgimage.bitmap = NULL; + } else global_state.bgimage.load_failed = true; + } + if (global_state.bgimage.texture_id) { + memcpy(&ans->bgimage, &global_state.bgimage, sizeof(global_state.bgimage)); + ans->bgimage.needs_free = false; } } @@ -293,6 +288,9 @@ destroy_os_window_item(OSWindow *w) { remove_vao(w->tab_bar_render_data.vao_idx); remove_vao(w->gvao_idx); free(w->tabs); w->tabs = NULL; + if (w->bgimage.needs_free) { + free(w->bgimage.bitmap); free_texture(&w->bgimage.texture_id); + } } bool @@ -960,6 +958,13 @@ finalize(void) { if (detached_windows.windows) free(detached_windows.windows); detached_windows.capacity = 0; if (OPT(background_image)) free(OPT(background_image)); + if (global_state.bgimage.needs_free) { + free(global_state.bgimage.bitmap); + // we leak the texture here since it is not guaranteed + // that freeing the texture will work during shutdown and + // the GPU driver should take care of it when the OpenGL context is + // destroyed. + } } bool diff --git a/kitty/state.h b/kitty/state.h index 9cb43c104..01a1faf75 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -144,7 +144,7 @@ typedef struct { int viewport_width, viewport_height, window_width, window_height; double viewport_x_ratio, viewport_y_ratio; Tab *tabs; - BackgroundImage *bgimage; + BackgroundImage bgimage; unsigned int active_tab, num_tabs, capacity, last_active_tab, last_num_tabs, last_active_window_id; bool focused_at_last_render, needs_render; ScreenRenderData tab_bar_render_data; @@ -178,7 +178,7 @@ typedef struct { id_type os_window_id_counter, tab_id_counter, window_id_counter; PyObject *boss; - BackgroundImage *bgimage; + BackgroundImage bgimage; OSWindow *os_windows; size_t num_os_windows, capacity; OSWindow *callback_os_window;