diff --git a/kitty/fonts.c b/kitty/fonts.c index 347337efd..5d5058c18 100644 --- a/kitty/fonts.c +++ b/kitty/fonts.c @@ -12,6 +12,7 @@ #include "emoji.h" #include "unicode-data.h" #include "glyph-cache.h" +#include "kitty-uthash.h" #define MISSING_GLYPH (NUM_UNDERLINE_STYLES + 2) #define MAX_NUM_EXTRA_GLYPHS_PUA 4u diff --git a/kitty/graphics.c b/kitty/graphics.c index 402fb326a..738eeba3d 100644 --- a/kitty/graphics.c +++ b/kitty/graphics.c @@ -5,6 +5,8 @@ * Distributed under terms of the GPL3 license. */ +#define GRAPHICS_INTERNAL_APIS +#include "kitty-uthash.h" #include "graphics.h" #include "state.h" #include "disk-cache.h" @@ -859,13 +861,13 @@ is_cell_image(const ImageRef *self) { return self->virtual_ref_id != 0; } // - `columns` - the number of columns we want to display // - `rows` - the number of rows we want to display // - `cell` - the size of a screen cell -Image *grman_put_cell_image(GraphicsManager *self, uint32_t screen_row, +void grman_put_cell_image(GraphicsManager *self, uint32_t screen_row, uint32_t screen_col, uint32_t image_id, uint32_t placement_id, uint32_t img_col, uint32_t img_row, uint32_t columns, uint32_t rows, CellPixelSize cell) { Image *img = img_by_client_id(self, image_id); - if (img == NULL) return NULL; + if (img == NULL) return; ImageRef *virt_img_ref = NULL; if (placement_id) { @@ -886,7 +888,7 @@ Image *grman_put_cell_image(GraphicsManager *self, uint32_t screen_row, } } - if (!virt_img_ref) return NULL; + if (!virt_img_ref) return; // Create the ref structure on stack first. We will not create a real // reference if the image is completely out of bounds. @@ -958,8 +960,7 @@ Image *grman_put_cell_image(GraphicsManager *self, uint32_t screen_row, uint32_t col_offset = ref.cell_x_offset / cell.width; ref.cell_x_offset %= cell.width; ref.start_column += col_offset; - if (ref.num_cols <= col_offset) - return img; + if (ref.num_cols <= col_offset) return; ref.num_cols -= col_offset; } if (ref.src_y < 0) { @@ -969,8 +970,7 @@ Image *grman_put_cell_image(GraphicsManager *self, uint32_t screen_row, uint32_t row_offset = ref.cell_y_offset / cell.height; ref.cell_y_offset %= cell.height; ref.start_row += row_offset; - if (ref.num_rows <= row_offset) - return img; + if (ref.num_rows <= row_offset) return; ref.num_rows -= row_offset; } @@ -979,16 +979,14 @@ Image *grman_put_cell_image(GraphicsManager *self, uint32_t screen_row, if (ref.src_x + ref.src_width > img->width) { float redundant_w = ref.src_x + ref.src_width - img->width; uint32_t redundant_cols = (uint32_t)(redundant_w * x_scale) / cell.width; - if (ref.num_cols <= redundant_cols) - return img; + if (ref.num_cols <= redundant_cols) return; ref.src_width -= redundant_cols * cell.width / x_scale; ref.num_cols -= redundant_cols; } if (ref.src_y + ref.src_height > img->height) { float redundant_h = ref.src_y + ref.src_height - img->height; uint32_t redundant_rows = (uint32_t)(redundant_h * y_scale) / cell.height; - if (ref.num_rows <= redundant_rows) - return img; + if (ref.num_rows <= redundant_rows) return; ref.src_height -= redundant_rows * cell.height / y_scale; ref.num_rows -= redundant_rows; } @@ -1004,7 +1002,6 @@ Image *grman_put_cell_image(GraphicsManager *self, uint32_t screen_row, update_src_rect(real_ref, img); update_dest_rect(real_ref, ref.num_cols, ref.num_rows, cell); - return img; } static void remove_ref(Image *img, ImageRef *ref); @@ -2428,4 +2425,15 @@ init_graphics(PyObject *module) { Py_INCREF(&GraphicsManager_Type); return true; } + +void grman_mark_layers_dirty(GraphicsManager *self) { self->layers_dirty = true; } +void grman_set_window_id(GraphicsManager *self, id_type id) { self->window_id = id; } +GraphicsRenderData grman_render_data(GraphicsManager *self) { + GraphicsRenderData ans = { + .count=self->render_data.count, .capacity=self->render_data.capacity, .images=self->render_data.item, + .num_of_below_refs=self->num_of_below_refs, .num_of_negative_refs=self->num_of_negative_refs, + .num_of_positive_refs=self->num_of_positive_refs + }; + return ans; +} // }}} diff --git a/kitty/graphics.h b/kitty/graphics.h index 43065c4dd..aa44fd542 100644 --- a/kitty/graphics.h +++ b/kitty/graphics.h @@ -7,7 +7,6 @@ #pragma once #include "data-types.h" #include "monotonic.h" -#include "kitty-uthash.h" typedef struct { unsigned char action, transmission_type, compressed, delete_action; @@ -30,6 +29,22 @@ typedef struct { float left, top, right, bottom; } ImageRect; +typedef struct { + ImageRect src_rect, dest_rect; + uint32_t texture_id, group_count; + int z_index; + id_type image_id, ref_id; +} ImageRenderData; + +typedef struct { + uint32_t texture_id; + unsigned int height, width; + uint8_t* bitmap; + uint32_t refcnt; +} BackgroundImage; + + +#ifdef GRAPHICS_INTERNAL_APIS typedef struct { float src_width, src_height, src_x, src_y; uint32_t cell_x_offset, cell_y_offset, num_cols, num_rows, effective_num_rows, effective_num_cols; @@ -87,20 +102,6 @@ typedef struct { hash_handle_type hh; } Image; -typedef struct { - uint32_t texture_id; - unsigned int height, width; - uint8_t* bitmap; - uint32_t refcnt; -} BackgroundImage; - -typedef struct { - ImageRect src_rect, dest_rect; - uint32_t texture_id, group_count; - int z_index; - id_type image_id, ref_id; -} ImageRenderData; - typedef struct { id_type image_id; uint32_t frame_id; @@ -142,7 +143,9 @@ typedef struct { bool has_images_needing_animation, context_made_current_for_this_command; id_type window_id; } GraphicsManager; - +#else +typedef struct {int x;} *GraphicsManager; +#endif typedef struct { int32_t amt, limit; @@ -179,11 +182,15 @@ gl_pos_y(const unsigned int px_from_top_margin, const unsigned int viewport_size return 1.f - px_from_top_margin * px; } +typedef struct GraphicsRenderData { + size_t count, capacity, num_of_below_refs, num_of_negative_refs, num_of_positive_refs; + ImageRenderData *images; +} GraphicsRenderData; GraphicsManager* grman_alloc(bool for_paused_rendering); void grman_clear(GraphicsManager*, bool, CellPixelSize fg); const char* grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload, Cursor *c, bool *is_dirty, CellPixelSize fg); -Image* grman_put_cell_image(GraphicsManager *self, uint32_t row, uint32_t col, uint32_t image_id, uint32_t placement_id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, CellPixelSize cell); +void grman_put_cell_image(GraphicsManager *self, uint32_t row, uint32_t col, uint32_t image_id, uint32_t placement_id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, CellPixelSize cell); bool grman_update_layers(GraphicsManager *self, unsigned int scrolled_by, float screen_left, float screen_top, float dx, float dy, unsigned int num_cols, unsigned int num_rows, CellPixelSize); void grman_scroll_images(GraphicsManager *self, const ScrollData*, CellPixelSize fg); void grman_resize(GraphicsManager*, index_type, index_type, index_type, index_type, index_type, index_type); @@ -197,3 +204,6 @@ bool png_from_data(void *png_data, size_t png_data_sz, const char *path_for_erro bool scan_active_animations(GraphicsManager *self, const monotonic_t now, monotonic_t *minimum_gap, bool os_window_context_set); void scale_rendered_graphic(ImageRenderData*, float xstart, float ystart, float x_scale, float y_scale); void grman_pause_rendering(GraphicsManager *self, GraphicsManager *dest); +void grman_mark_layers_dirty(GraphicsManager *self); +void grman_set_window_id(GraphicsManager *self, id_type id); +GraphicsRenderData grman_render_data(GraphicsManager *self); diff --git a/kitty/screen.c b/kitty/screen.c index ff9054bf8..c59569c19 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -142,7 +142,8 @@ new_screen_object(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { ) { Py_CLEAR(self); return NULL; } - self->main_grman->window_id = self->window_id; self->alt_grman->window_id = self->window_id; + grman_set_window_id(self->main_grman, self->window_id); + grman_set_window_id(self->alt_grman, self->window_id); self->alt_tabstops = self->main_tabstops + self->columns; self->tabstops = self->main_tabstops; init_tabstops(self->main_tabstops, self->columns); @@ -1065,7 +1066,7 @@ screen_toggle_screen_buffer(Screen *self, bool save_cursor, bool clear_alt_scree } screen_history_scroll(self, SCROLL_FULL, false); self->is_dirty = true; - self->grman->layers_dirty = true; + grman_mark_layers_dirty(self->grman); clear_selection(&self->selections); global_state.check_for_active_animated_images = true; } diff --git a/kitty/shaders.c b/kitty/shaders.c index 992d173d4..1288bc8ab 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -574,15 +574,14 @@ viewport_for_cells(const CellRenderData *crd) { } static void -draw_cells_simple(ssize_t vao_idx, Screen *screen, const CellRenderData *crd, bool is_semi_transparent) { +draw_cells_simple(ssize_t vao_idx, Screen *screen, const CellRenderData *crd, GraphicsRenderData grd, bool is_semi_transparent) { bind_program(CELL_PROGRAM); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); - GraphicsManager *grman = screen->paused_rendering.expires_at && screen->paused_rendering.grman ? screen->paused_rendering.grman : screen->grman; - if (grman->render_data.count) { + if (grd.count) { glEnable(GL_BLEND); int program = GRAPHICS_PROGRAM; if (is_semi_transparent) { BLEND_PREMULT; program = GRAPHICS_PREMULT_PROGRAM; } else { BLEND_ONTO_OPAQUE; } - draw_graphics(program, vao_idx, grman->render_data.item, 0, grman->render_data.count, viewport_for_cells(crd)); + draw_graphics(program, vao_idx, grd.images, 0, grd.count, viewport_for_cells(crd)); glDisable(GL_BLEND); } } @@ -865,7 +864,7 @@ draw_visual_bell_flash(GLfloat intensity, const CellRenderData *crd, Screen *scr } static void -draw_cells_interleaved(ssize_t vao_idx, Screen *screen, OSWindow *w, const CellRenderData *crd, const WindowLogoRenderData *wl) { +draw_cells_interleaved(ssize_t vao_idx, Screen *screen, OSWindow *w, const CellRenderData *crd, GraphicsRenderData grd, const WindowLogoRenderData *wl) { glEnable(GL_BLEND); BLEND_ONTO_OPAQUE; @@ -879,21 +878,20 @@ draw_cells_interleaved(ssize_t vao_idx, Screen *screen, OSWindow *w, const CellR BLEND_ONTO_OPAQUE; } - GraphicsManager *grman = screen->paused_rendering.expires_at && screen->paused_rendering.grman ? screen->paused_rendering.grman : screen->grman; - if (grman->num_of_below_refs || has_bgimage(w) || wl) { + if (grd.num_of_below_refs || has_bgimage(w) || wl) { if (wl) { draw_window_logo(vao_idx, w, wl, crd); BLEND_ONTO_OPAQUE; } - if (grman->num_of_below_refs) draw_graphics( - GRAPHICS_PROGRAM, vao_idx, grman->render_data.item, 0, grman->num_of_below_refs, viewport_for_cells(crd)); + if (grd.num_of_below_refs) draw_graphics( + GRAPHICS_PROGRAM, vao_idx, grd.images, 0, grd.num_of_below_refs, viewport_for_cells(crd)); bind_program(CELL_BG_PROGRAM); // draw background for non-default bg cells glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].uniforms.draw_bg_bitfield, 2); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); } - if (grman->num_of_negative_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, grman->render_data.item, grman->num_of_below_refs, grman->num_of_negative_refs, viewport_for_cells(crd)); + if (grd.num_of_negative_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, grd.images, grd.num_of_below_refs, grd.num_of_negative_refs, viewport_for_cells(crd)); bind_program(CELL_SPECIAL_PROGRAM); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); @@ -903,13 +901,13 @@ draw_cells_interleaved(ssize_t vao_idx, Screen *screen, OSWindow *w, const CellR glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); BLEND_ONTO_OPAQUE; - if (grman->num_of_positive_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, grman->render_data.item, grman->num_of_negative_refs + grman->num_of_below_refs, grman->num_of_positive_refs, viewport_for_cells(crd)); + if (grd.num_of_positive_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, grd.images, grd.num_of_negative_refs + grd.num_of_below_refs, grd.num_of_positive_refs, viewport_for_cells(crd)); glDisable(GL_BLEND); } static void -draw_cells_interleaved_premult(ssize_t vao_idx, Screen *screen, OSWindow *os_window, const CellRenderData *crd, const WindowLogoRenderData *wl) { +draw_cells_interleaved_premult(ssize_t vao_idx, Screen *screen, OSWindow *os_window, const CellRenderData *crd, GraphicsRenderData grd, const WindowLogoRenderData *wl) { if (OPT(background_tint) > 0.f) { glEnable(GL_BLEND); draw_tint(true, screen, crd); @@ -924,14 +922,13 @@ draw_cells_interleaved_premult(ssize_t vao_idx, Screen *screen, OSWindow *os_win glEnable(GL_BLEND); BLEND_PREMULT; - GraphicsManager *grman = screen->paused_rendering.expires_at && screen->paused_rendering.grman ? screen->paused_rendering.grman : screen->grman; - if (grman->num_of_below_refs || has_bgimage(os_window) || wl) { + if (grd.num_of_below_refs || has_bgimage(os_window) || wl) { if (wl) { draw_window_logo(vao_idx, os_window, wl, crd); BLEND_PREMULT; } - if (grman->num_of_below_refs) draw_graphics( - GRAPHICS_PREMULT_PROGRAM, vao_idx, grman->render_data.item, 0, grman->num_of_below_refs, viewport_for_cells(crd)); + if (grd.num_of_below_refs) draw_graphics( + GRAPHICS_PREMULT_PROGRAM, vao_idx, grd.images, 0, grd.num_of_below_refs, viewport_for_cells(crd)); bind_program(CELL_BG_PROGRAM); // Draw background for non-default bg cells glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].uniforms.draw_bg_bitfield, 2); @@ -942,8 +939,8 @@ draw_cells_interleaved_premult(ssize_t vao_idx, Screen *screen, OSWindow *os_win glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); } - if (grman->num_of_negative_refs) { - draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, grman->render_data.item, grman->num_of_below_refs, grman->num_of_negative_refs, viewport_for_cells(crd)); + if (grd.num_of_negative_refs) { + draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, grd.images, grd.num_of_below_refs, grd.num_of_negative_refs, viewport_for_cells(crd)); } bind_program(CELL_SPECIAL_PROGRAM); @@ -952,7 +949,7 @@ draw_cells_interleaved_premult(ssize_t vao_idx, Screen *screen, OSWindow *os_win bind_program(CELL_FG_PROGRAM); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); - if (grman->num_of_positive_refs) draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, grman->render_data.item, grman->num_of_negative_refs + grman->num_of_below_refs, grman->num_of_positive_refs, viewport_for_cells(crd)); + if (grd.num_of_positive_refs) draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, grd.images, grd.num_of_negative_refs + grd.num_of_below_refs, grd.num_of_positive_refs, viewport_for_cells(crd)); glDisable(GL_BLEND); } @@ -1037,24 +1034,26 @@ draw_cells(ssize_t vao_idx, const WindowRenderData *srd, OSWindow *os_window, bo has_underlying_image = true; set_on_gpu_state(window->window_logo.instance, true); } else wl = NULL; - ImageRenderData *previous_graphics_render_data = NULL; + ImageRenderData *scaled_render_data = NULL; GraphicsManager *grman = screen->paused_rendering.expires_at && screen->paused_rendering.grman ? screen->paused_rendering.grman : screen->grman; - if (os_window->live_resize.in_progress && grman->render_data.count && (crd.x_ratio != 1 || crd.y_ratio != 1)) { - previous_graphics_render_data = malloc(sizeof(previous_graphics_render_data[0]) * grman->render_data.capacity); - if (previous_graphics_render_data) { - memcpy(previous_graphics_render_data, grman->render_data.item, sizeof(previous_graphics_render_data[0]) * grman->render_data.count); - for (size_t i = 0; i < grman->render_data.count; i++) - scale_rendered_graphic(grman->render_data.item + i, srd->xstart, srd->ystart, crd.x_ratio, crd.y_ratio); + GraphicsRenderData grd = grman_render_data(grman); + if (os_window->live_resize.in_progress && grd.count && (crd.x_ratio != 1 || crd.y_ratio != 1)) { + scaled_render_data = malloc(sizeof(scaled_render_data[0]) * grd.count); + if (scaled_render_data) { + memcpy(scaled_render_data, grd.images, sizeof(scaled_render_data[0]) * grd.count); + grd.images = scaled_render_data; + for (size_t i = 0; i < grd.count; i++) + scale_rendered_graphic(grd.images + i, srd->xstart, srd->ystart, crd.x_ratio, crd.y_ratio); } } bool use_premult = false; - has_underlying_image |= grman->num_of_below_refs > 0 || grman->num_of_negative_refs > 0; + has_underlying_image |= grd.num_of_below_refs > 0 || grd.num_of_negative_refs > 0; if (os_window->is_semi_transparent) { - if (has_underlying_image) { draw_cells_interleaved_premult(vao_idx, screen, os_window, &crd, wl); use_premult = true; } - else draw_cells_simple(vao_idx, screen, &crd, os_window->is_semi_transparent); + if (has_underlying_image) { draw_cells_interleaved_premult(vao_idx, screen, os_window, &crd, grd, wl); use_premult = true; } + else draw_cells_simple(vao_idx, screen, &crd, grd, os_window->is_semi_transparent); } else { - if (has_underlying_image) draw_cells_interleaved(vao_idx, screen, os_window, &crd, wl); - else draw_cells_simple(vao_idx, screen, &crd, os_window->is_semi_transparent); + if (has_underlying_image) draw_cells_interleaved(vao_idx, screen, os_window, &crd, grd, wl); + else draw_cells_simple(vao_idx, screen, &crd, grd, os_window->is_semi_transparent); } draw_scroll_indicator(use_premult, screen, &crd); @@ -1065,10 +1064,7 @@ draw_cells(ssize_t vao_idx, const WindowRenderData *srd, OSWindow *os_window, bo if (window && screen->display_window_char) draw_window_number(os_window, screen, &crd, window); if (OPT(show_hyperlink_targets) && window && screen->current_hyperlink_under_mouse.id && !is_mouse_hidden(os_window)) draw_hyperlink_target(os_window, screen, &crd, window); - if (previous_graphics_render_data) { - free(grman->render_data.item); - grman->render_data.item = previous_graphics_render_data; - } + free(scaled_render_data); } // }}}