mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-09-11 14:45:31 +03:00
Implement paused rendering for graphics
This commit is contained in:
parent
7b963a2372
commit
f45cd87488
@ -68,7 +68,7 @@ next_id(id_type *counter) {
|
||||
static const unsigned PARENT_DEPTH_LIMIT = 8;
|
||||
|
||||
GraphicsManager*
|
||||
grman_alloc(void) {
|
||||
grman_alloc(bool for_paused_rendering) {
|
||||
GraphicsManager *self = (GraphicsManager *)GraphicsManager_Type.tp_alloc(&GraphicsManager_Type, 0);
|
||||
self->render_data.capacity = 64;
|
||||
self->render_data.item = calloc(self->render_data.capacity, sizeof(self->render_data.item[0]));
|
||||
@ -77,8 +77,10 @@ grman_alloc(void) {
|
||||
PyErr_NoMemory();
|
||||
Py_CLEAR(self); return NULL;
|
||||
}
|
||||
self->disk_cache = create_disk_cache();
|
||||
if (!self->disk_cache) { Py_CLEAR(self); return NULL; }
|
||||
if (!for_paused_rendering) {
|
||||
self->disk_cache = create_disk_cache();
|
||||
if (!self->disk_cache) { Py_CLEAR(self); return NULL; }
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -113,6 +115,12 @@ clear_texture_ref(TextureRef **x) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static TextureRef*
|
||||
incref_texture_ref(TextureRef *ref) {
|
||||
if (ref) ref->refcnt++;
|
||||
return ref;
|
||||
}
|
||||
|
||||
static TextureRef*
|
||||
new_texture_ref(void) {
|
||||
TextureRef *ans = malloc(sizeof(TextureRef));
|
||||
@ -128,18 +136,20 @@ texture_id_for_img(Image *img) {
|
||||
static void
|
||||
free_image_resources(GraphicsManager *self, Image *img) {
|
||||
clear_texture_ref(&img->texture);
|
||||
ImageAndFrame key = { .image_id=img->internal_id, .frame_id = img->root_frame.id };
|
||||
if (!remove_from_cache(self, key) && PyErr_Occurred()) PyErr_Print();
|
||||
for (unsigned i = 0; i < img->extra_framecnt; i++) {
|
||||
key.frame_id = img->extra_frames[i].id;
|
||||
if (self->disk_cache) {
|
||||
ImageAndFrame key = { .image_id=img->internal_id, .frame_id = img->root_frame.id };
|
||||
if (!remove_from_cache(self, key) && PyErr_Occurred()) PyErr_Print();
|
||||
for (unsigned i = 0; i < img->extra_framecnt; i++) {
|
||||
key.frame_id = img->extra_frames[i].id;
|
||||
if (!remove_from_cache(self, key) && PyErr_Occurred()) PyErr_Print();
|
||||
}
|
||||
}
|
||||
if (img->extra_frames) {
|
||||
free(img->extra_frames);
|
||||
img->extra_frames = NULL;
|
||||
}
|
||||
free_refs_data(img);
|
||||
self->used_storage -= img->used_storage;
|
||||
self->used_storage = img->used_storage <= self->used_storage ? self->used_storage - img->used_storage : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -150,7 +160,7 @@ free_image(GraphicsManager *self, Image *img) {
|
||||
}
|
||||
|
||||
static void
|
||||
dealloc(GraphicsManager* self) {
|
||||
free_all_images(GraphicsManager *self) {
|
||||
if (self->images) {
|
||||
Image *img, *tmp;
|
||||
HASH_ITER(hh, self->images, img, tmp) {
|
||||
@ -158,6 +168,11 @@ dealloc(GraphicsManager* self) {
|
||||
}
|
||||
self->images = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dealloc(GraphicsManager* self) {
|
||||
free_all_images(self);
|
||||
free(self->render_data.item);
|
||||
Py_CLEAR(self->disk_cache);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
@ -222,6 +237,38 @@ remove_images(GraphicsManager *self, bool(*predicate)(Image*), id_type skip_imag
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grman_pause_rendering(GraphicsManager *self, GraphicsManager *dest) {
|
||||
make_window_context_current(dest->window_id);
|
||||
free_all_images(dest); dest->images = NULL;
|
||||
dest->render_data.count = 0;
|
||||
if (self == NULL) return;
|
||||
dest->window_id = self->window_id;
|
||||
dest->layers_dirty = true;
|
||||
dest->last_scrolled_by = 0;
|
||||
|
||||
Image *img, *tmpimg;
|
||||
|
||||
HASH_ITER(hh, self->images, img, tmpimg) {
|
||||
Image *clone = calloc(1, sizeof(Image));
|
||||
if (!clone) continue;
|
||||
memcpy(clone, img, sizeof(*clone));
|
||||
clone->extra_frames = NULL;
|
||||
if (img->refs) {
|
||||
clone->refs = NULL;
|
||||
ImageRef *ref, *tmpref;
|
||||
HASH_ITER(hh, img->refs, ref, tmpref) {
|
||||
ImageRef *cr = malloc(sizeof(ImageRef));
|
||||
if (cr) {
|
||||
memcpy(cr, ref, sizeof(*cr));
|
||||
HASH_ADD(hh, clone->refs, internal_id, sizeof(cr->internal_id), cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
HASH_ADD(hh, dest->images, internal_id, sizeof(clone->internal_id), clone);
|
||||
clone->texture = incref_texture_ref(img->texture);
|
||||
}
|
||||
}
|
||||
|
||||
// Loading image data {{{
|
||||
|
||||
@ -2164,7 +2211,7 @@ grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint
|
||||
// Boilerplate {{{
|
||||
static PyObject *
|
||||
new(PyTypeObject UNUSED *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
||||
PyObject *ans = (PyObject*)grman_alloc();
|
||||
PyObject *ans = (PyObject*)grman_alloc(false);
|
||||
if (ans == NULL) PyErr_NoMemory();
|
||||
return ans;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ gl_pos_y(const unsigned int px_from_top_margin, const unsigned int viewport_size
|
||||
}
|
||||
|
||||
|
||||
GraphicsManager* grman_alloc(void);
|
||||
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);
|
||||
@ -196,3 +196,4 @@ bool png_path_to_bitmap(const char *path, uint8_t** data, unsigned int* width, u
|
||||
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 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);
|
||||
|
@ -127,8 +127,8 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
self->main_linebuf = alloc_linebuf(lines, columns); self->alt_linebuf = alloc_linebuf(lines, columns);
|
||||
self->linebuf = self->main_linebuf;
|
||||
self->historybuf = alloc_historybuf(MAX(scrollback, lines), columns, OPT(scrollback_pager_history_size));
|
||||
self->main_grman = grman_alloc();
|
||||
self->alt_grman = grman_alloc();
|
||||
self->main_grman = grman_alloc(false);
|
||||
self->alt_grman = grman_alloc(false);
|
||||
self->active_hyperlink_id = 0;
|
||||
|
||||
self->grman = self->main_grman;
|
||||
@ -474,6 +474,7 @@ dealloc(Screen* self) {
|
||||
Py_CLEAR(self->overlay_line.overlay_text);
|
||||
PyMem_Free(self->main_tabstops);
|
||||
Py_CLEAR(self->paused_rendering.linebuf);
|
||||
Py_CLEAR(self->paused_rendering.grman);
|
||||
free(self->selections.items);
|
||||
free(self->url_ranges.items);
|
||||
free(self->paused_rendering.url_ranges.items);
|
||||
@ -2391,9 +2392,13 @@ screen_pause_rendering(Screen *self, bool pause, int for_in_ms) {
|
||||
self->is_dirty = true;
|
||||
// ensure selection data is updated on GPU
|
||||
self->selections.last_rendered_count = SIZE_MAX; self->url_ranges.last_rendered_count = SIZE_MAX;
|
||||
// free grman data
|
||||
grman_pause_rendering(NULL, self->paused_rendering.grman);
|
||||
return true;
|
||||
}
|
||||
if (self->paused_rendering.expires_at) return false;
|
||||
if (!self->paused_rendering.grman) self->paused_rendering.grman = grman_alloc(true);
|
||||
if (!self->paused_rendering.grman) return false;
|
||||
if (for_in_ms <= 0) for_in_ms = 2000;
|
||||
self->paused_rendering.expires_at = monotonic() + ms_to_monotonic_t(for_in_ms);
|
||||
self->paused_rendering.inverted = self->modes.mDECSCNM;
|
||||
@ -2415,6 +2420,7 @@ screen_pause_rendering(Screen *self, bool pause, int for_in_ms) {
|
||||
}
|
||||
copy_selections(&self->paused_rendering.selections, &self->selections);
|
||||
copy_selections(&self->paused_rendering.url_ranges, &self->url_ranges);
|
||||
grman_pause_rendering(self->grman, self->paused_rendering.grman);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -157,6 +157,7 @@ typedef struct {
|
||||
bool inverted, cell_data_updated, cursor_visible;
|
||||
unsigned int scrolled_by;
|
||||
LineBuf *linebuf;
|
||||
GraphicsManager *grman;
|
||||
Selections selections, url_ranges;
|
||||
} paused_rendering;
|
||||
} Screen;
|
||||
|
@ -419,15 +419,18 @@ cell_prepare_to_render(ssize_t vao_idx, Screen *screen, GLfloat xstart, GLfloat
|
||||
changed = true; \
|
||||
}
|
||||
|
||||
#define update_graphics_data(grman) \
|
||||
grman_update_layers(grman, screen->scrolled_by, xstart, ystart, dx, dy, screen->columns, screen->lines, screen->cell_size)
|
||||
|
||||
if (screen->paused_rendering.expires_at) {
|
||||
if (!screen->paused_rendering.cell_data_updated) update_selection_data;
|
||||
if (!screen->paused_rendering.cell_data_updated) {
|
||||
update_selection_data; update_graphics_data(screen->paused_rendering.grman);
|
||||
}
|
||||
screen->paused_rendering.cell_data_updated = true;
|
||||
screen->last_rendered.scrolled_by = screen->paused_rendering.scrolled_by;
|
||||
} else {
|
||||
if (screen->reload_all_gpu_data || screen_resized || screen_is_selection_dirty(screen)) update_selection_data;
|
||||
if (grman_update_layers(screen->grman, screen->scrolled_by, xstart, ystart, dx, dy, screen->columns, screen->lines, screen->cell_size)) {
|
||||
changed = true;
|
||||
}
|
||||
if (update_graphics_data(screen->grman)) changed = true;
|
||||
screen->last_rendered.scrolled_by = screen->scrolled_by;
|
||||
}
|
||||
#undef update_selection_data
|
||||
@ -563,11 +566,12 @@ static void
|
||||
draw_cells_simple(ssize_t vao_idx, Screen *screen, const CellRenderData *crd, bool is_semi_transparent) {
|
||||
bind_program(CELL_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
if (screen->grman->render_data.count) {
|
||||
GraphicsManager *grman = screen->paused_rendering.expires_at && screen->paused_rendering.grman ? screen->paused_rendering.grman : screen->grman;
|
||||
if (grman->render_data.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, screen->grman->render_data.item, 0, screen->grman->render_data.count, viewport_for_cells(crd));
|
||||
draw_graphics(program, vao_idx, grman->render_data.item, 0, grman->render_data.count, viewport_for_cells(crd));
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
@ -804,20 +808,21 @@ draw_cells_interleaved(ssize_t vao_idx, Screen *screen, OSWindow *w, const CellR
|
||||
BLEND_ONTO_OPAQUE;
|
||||
}
|
||||
|
||||
if (screen->grman->num_of_below_refs || has_bgimage(w) || wl) {
|
||||
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 (wl) {
|
||||
draw_window_logo(vao_idx, w, wl, crd);
|
||||
BLEND_ONTO_OPAQUE;
|
||||
}
|
||||
if (screen->grman->num_of_below_refs) draw_graphics(
|
||||
GRAPHICS_PROGRAM, vao_idx, screen->grman->render_data.item, 0, screen->grman->num_of_below_refs, viewport_for_cells(crd));
|
||||
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));
|
||||
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 (screen->grman->num_of_negative_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, screen->grman->render_data.item, screen->grman->num_of_below_refs, screen->grman->num_of_negative_refs, viewport_for_cells(crd));
|
||||
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));
|
||||
|
||||
bind_program(CELL_SPECIAL_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
@ -827,7 +832,7 @@ 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 (screen->grman->num_of_positive_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, screen->grman->render_data.item, screen->grman->num_of_negative_refs + screen->grman->num_of_below_refs, screen->grman->num_of_positive_refs, viewport_for_cells(crd));
|
||||
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));
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
@ -848,13 +853,14 @@ draw_cells_interleaved_premult(ssize_t vao_idx, Screen *screen, OSWindow *os_win
|
||||
glEnable(GL_BLEND);
|
||||
BLEND_PREMULT;
|
||||
|
||||
if (screen->grman->num_of_below_refs || has_bgimage(os_window) || wl) {
|
||||
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 (wl) {
|
||||
draw_window_logo(vao_idx, os_window, wl, crd);
|
||||
BLEND_PREMULT;
|
||||
}
|
||||
if (screen->grman->num_of_below_refs) draw_graphics(
|
||||
GRAPHICS_PREMULT_PROGRAM, vao_idx, screen->grman->render_data.item, 0, screen->grman->num_of_below_refs, viewport_for_cells(crd));
|
||||
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));
|
||||
bind_program(CELL_BG_PROGRAM);
|
||||
// Draw background for non-default bg cells
|
||||
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].uniforms.draw_bg_bitfield, 2);
|
||||
@ -865,8 +871,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 (screen->grman->num_of_negative_refs) {
|
||||
draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, screen->grman->render_data.item, screen->grman->num_of_below_refs, screen->grman->num_of_negative_refs, viewport_for_cells(crd));
|
||||
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));
|
||||
}
|
||||
|
||||
bind_program(CELL_SPECIAL_PROGRAM);
|
||||
@ -875,7 +881,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 (screen->grman->num_of_positive_refs) draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, screen->grman->render_data.item, screen->grman->num_of_negative_refs + screen->grman->num_of_below_refs, screen->grman->num_of_positive_refs, viewport_for_cells(crd));
|
||||
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 (!has_bgimage(os_window)) glDisable(GL_BLEND);
|
||||
}
|
||||
@ -957,15 +963,16 @@ draw_cells(ssize_t vao_idx, const WindowRenderData *srd, OSWindow *os_window, bo
|
||||
set_on_gpu_state(window->window_logo.instance, true);
|
||||
} else wl = NULL;
|
||||
ImageRenderData *previous_graphics_render_data = NULL;
|
||||
if (os_window->live_resize.in_progress && screen->grman->render_data.count && (crd.x_ratio != 1 || crd.y_ratio != 1)) {
|
||||
previous_graphics_render_data = malloc(sizeof(previous_graphics_render_data[0]) * screen->grman->render_data.capacity);
|
||||
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, screen->grman->render_data.item, sizeof(previous_graphics_render_data[0]) * screen->grman->render_data.count);
|
||||
for (size_t i = 0; i < screen->grman->render_data.count; i++)
|
||||
scale_rendered_graphic(screen->grman->render_data.item + i, srd->xstart, srd->ystart, crd.x_ratio, crd.y_ratio);
|
||||
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);
|
||||
}
|
||||
}
|
||||
has_underlying_image |= screen->grman->num_of_below_refs > 0 || screen->grman->num_of_negative_refs > 0;
|
||||
has_underlying_image |= grman->num_of_below_refs > 0 || grman->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);
|
||||
else draw_cells_simple(vao_idx, screen, &crd, os_window->is_semi_transparent);
|
||||
@ -982,8 +989,8 @@ 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(screen->grman->render_data.item);
|
||||
screen->grman->render_data.item = previous_graphics_render_data;
|
||||
free(grman->render_data.item);
|
||||
grman->render_data.item = previous_graphics_render_data;
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
|
Loading…
Reference in New Issue
Block a user