mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-02 12:44:01 +02:00
This was needed to fix various corner cases when doing blending of colors in linear space. The new architecture has the same performance as the old in the common case of opaque rendering with no UI layers or images. In the case of only positive z-index images there is a performance decrease as the OS Window is now rendered to a offscreen texture and then blitted to screen. However, in the future when we move to Vulkan or I can figure out how to get Wayland to accept buffers with colors in linear space, this performance penalty can be removed. The performance penalty was not significant on my system but this is highly GPU dependent. Modern GPUs are supposedly optimised for rendering to offscreen buffers, so we will see. The awrit project might be a good test case. Now either we have 1-shot rendering for the case of opaque with only ext or all the various pieces are rendered in successive draw calls into an offscreen buffer that is blitted to the output buffer after all drawing is done. Fixes #8869
222 lines
7.6 KiB
C
222 lines
7.6 KiB
C
/*
|
|
* Copyright (C) 2017 Kovid Goyal <kovid at kovidgoyal.net>
|
|
*
|
|
* Distributed under terms of the GPL3 license.
|
|
*/
|
|
|
|
#pragma once
|
|
#include "data-types.h"
|
|
#include "monotonic.h"
|
|
|
|
typedef struct {
|
|
unsigned char action, transmission_type, compressed, delete_action;
|
|
uint32_t format, more, id, image_number, data_sz, data_offset, placement_id, quiet, parent_id, parent_placement_id;
|
|
uint32_t width, height, x_offset, y_offset;
|
|
union { uint32_t cursor_movement, compose_mode; };
|
|
union { uint32_t cell_x_offset, blend_mode; };
|
|
union { uint32_t cell_y_offset, bgcolor; };
|
|
union { uint32_t data_width, animation_state; };
|
|
union { uint32_t data_height, loop_count; };
|
|
union { uint32_t num_lines, frame_number; };
|
|
union { uint32_t num_cells, other_frame_number; };
|
|
union { int32_t z_index, gap; };
|
|
size_t payload_sz;
|
|
bool unicode_placement;
|
|
int32_t offset_from_parent_x, offset_from_parent_y;
|
|
} GraphicsCommand;
|
|
|
|
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, id;
|
|
size_t mmap_size;
|
|
} 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;
|
|
int32_t z_index;
|
|
int32_t start_row, start_column;
|
|
uint32_t client_id;
|
|
ImageRect src_rect;
|
|
// Indicates whether this reference represents a cell ref that should be
|
|
// removed when the corresponding cells are modified.
|
|
// The internal id of the virtual ref this cell image was created from. Is a cell ref if this is non-zero.
|
|
id_type virtual_ref_id;
|
|
// Virtual refs are not displayed but they can be used as prototypes for
|
|
// refs placed using unicode placeholders.
|
|
bool is_virtual_ref;
|
|
|
|
struct {
|
|
id_type img, ref;
|
|
struct { int32_t x, y; } offset;
|
|
} parent;
|
|
|
|
id_type internal_id;
|
|
} ImageRef;
|
|
|
|
typedef struct {
|
|
uint32_t gap, id, width, height, x, y, base_frame_id, bgcolor;
|
|
bool is_opaque, is_4byte_aligned, alpha_blend;
|
|
} Frame;
|
|
|
|
typedef enum { ANIMATION_STOPPED = 0, ANIMATION_LOADING = 1, ANIMATION_RUNNING = 2} AnimationState;
|
|
|
|
typedef struct TextureRef {
|
|
uint32_t id, refcnt;
|
|
} TextureRef;
|
|
|
|
#define NAME ref_map
|
|
#define KEY_TY id_type
|
|
#define VAL_TY ImageRef*
|
|
#include "kitty-verstable.h"
|
|
|
|
typedef struct {
|
|
uint32_t client_id, client_number, width, height;
|
|
TextureRef *texture;
|
|
id_type internal_id;
|
|
|
|
bool root_frame_data_loaded;
|
|
id_type ref_id_counter;
|
|
Frame *extra_frames, root_frame;
|
|
uint32_t current_frame_index, frame_id_counter;
|
|
uint64_t animation_duration;
|
|
size_t extra_framecnt;
|
|
monotonic_t atime;
|
|
size_t used_storage;
|
|
bool is_drawn;
|
|
AnimationState animation_state;
|
|
uint32_t max_loops, current_loop;
|
|
monotonic_t current_frame_shown_at;
|
|
ref_map refs_by_internal_id;
|
|
} Image;
|
|
|
|
typedef struct {
|
|
id_type image_id;
|
|
uint32_t frame_id;
|
|
} ImageAndFrame;
|
|
|
|
typedef struct {
|
|
uint8_t *buf;
|
|
size_t buf_capacity, buf_used;
|
|
|
|
uint8_t *mapped_file;
|
|
size_t mapped_file_sz;
|
|
|
|
size_t data_sz;
|
|
uint8_t *data;
|
|
bool is_4byte_aligned;
|
|
bool is_opaque, loading_completed_successfully;
|
|
uint32_t width, height;
|
|
GraphicsCommand start_command;
|
|
ImageAndFrame loading_for;
|
|
} LoadData;
|
|
|
|
#define NAME image_map
|
|
#define KEY_TY id_type
|
|
#define VAL_TY Image*
|
|
#include "kitty-verstable.h"
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
|
|
size_t storage_limit;
|
|
LoadData currently_loading;
|
|
id_type image_id_counter;
|
|
struct {
|
|
size_t count, capacity;
|
|
ImageRenderData *item;
|
|
} render_data;
|
|
bool layers_dirty;
|
|
// The number of images below MIN_ZINDEX / 2, then the number of refs between MIN_ZINDEX / 2 and -1 inclusive, then the number of refs above 0 inclusive.
|
|
size_t num_of_below_refs, num_of_negative_refs, num_of_positive_refs;
|
|
unsigned int last_scrolled_by;
|
|
size_t used_storage;
|
|
PyObject *disk_cache;
|
|
bool has_images_needing_animation, context_made_current_for_this_command;
|
|
id_type window_id;
|
|
image_map images_by_internal_id;
|
|
} GraphicsManager;
|
|
#else
|
|
typedef struct {int x;} *GraphicsManager;
|
|
#endif
|
|
|
|
typedef struct {
|
|
int32_t amt, limit;
|
|
index_type margin_top, margin_bottom;
|
|
bool has_margins;
|
|
} ScrollData;
|
|
|
|
|
|
static inline float
|
|
gl_size(const unsigned int sz, const unsigned int viewport_size) {
|
|
// convert pixel sz to OpenGL coordinate system.
|
|
const float px = 2.f / viewport_size;
|
|
return px * sz;
|
|
}
|
|
|
|
static inline float
|
|
gl_pos_x(const int px_from_left_margin, const unsigned int viewport_size) {
|
|
const float px = 2.f / viewport_size;
|
|
return -1.f + px_from_left_margin * px;
|
|
}
|
|
|
|
static inline float
|
|
tex_pos_x(const int px_from_left_margin, const unsigned texture_width) {
|
|
return px_from_left_margin / (float)texture_width;
|
|
}
|
|
|
|
static inline float
|
|
gl_pos_y(const int px_from_top_margin, const unsigned int viewport_size) {
|
|
const float px = 2.f / viewport_size;
|
|
return 1.f - px_from_top_margin * px;
|
|
}
|
|
|
|
static inline float
|
|
tex_pos_y(const int px_from_top_margin, const unsigned texture_height) {
|
|
const int px_from_bottom_margin = texture_height - px_from_top_margin;
|
|
return px_from_bottom_margin / (float)texture_height;
|
|
}
|
|
|
|
|
|
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);
|
|
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);
|
|
void grman_rescale(GraphicsManager *self, CellPixelSize fg);
|
|
void grman_remove_cell_images(GraphicsManager *self, int32_t top, int32_t bottom);
|
|
void grman_remove_all_cell_images(GraphicsManager *self);
|
|
void gpu_data_for_image(ImageRenderData *ans, float left, float top, float right, float bottom);
|
|
bool png_from_file_pointer(FILE* fp, const char *path, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz);
|
|
bool png_path_to_bitmap(const char *path, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz);
|
|
bool png_from_data(void *png_data, size_t png_data_sz, const char *path_for_error_messages, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz);
|
|
bool image_path_to_bitmap(const char *path, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz);
|
|
bool scan_active_animations(GraphicsManager *self, const monotonic_t now, monotonic_t *minimum_gap, bool os_window_context_set);
|
|
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);
|
|
bool grman_has_images(GraphicsManager *self);
|
|
GraphicsRenderData grman_render_data(GraphicsManager *self);
|