mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
Merge branch 'refactor-shm-buffer-management'
This commit is contained in:
commit
34de799f90
6 changed files with 385 additions and 280 deletions
69
render.c
69
render.c
|
|
@ -943,7 +943,7 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
|
|||
|
||||
if (try_shm_scroll) {
|
||||
did_shm_scroll = shm_scroll(
|
||||
term->wl->shm, buf, dmg->lines * term->cell_height,
|
||||
buf, dmg->lines * term->cell_height,
|
||||
term->margins.top, dmg->region.start * term->cell_height,
|
||||
term->margins.bottom, (term->rows - dmg->region.end) * term->cell_height);
|
||||
}
|
||||
|
|
@ -954,7 +954,7 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
|
|||
term, buf, dmg->region.end - dmg->lines, term->rows, false);
|
||||
} else {
|
||||
/* Fallback for when we either cannot do SHM scrolling, or it failed */
|
||||
uint8_t *raw = buf->mmapped;
|
||||
uint8_t *raw = buf->data;
|
||||
memmove(raw + dst_y * buf->stride,
|
||||
raw + src_y * buf->stride,
|
||||
height * buf->stride);
|
||||
|
|
@ -1008,7 +1008,7 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf,
|
|||
|
||||
if (try_shm_scroll) {
|
||||
did_shm_scroll = shm_scroll(
|
||||
term->wl->shm, buf, -dmg->lines * term->cell_height,
|
||||
buf, -dmg->lines * term->cell_height,
|
||||
term->margins.top, dmg->region.start * term->cell_height,
|
||||
term->margins.bottom, (term->rows - dmg->region.end) * term->cell_height);
|
||||
}
|
||||
|
|
@ -1019,7 +1019,7 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf,
|
|||
term, buf, dmg->region.start, dmg->region.start + dmg->lines, false);
|
||||
} else {
|
||||
/* Fallback for when we either cannot do SHM scrolling, or it failed */
|
||||
uint8_t *raw = buf->mmapped;
|
||||
uint8_t *raw = buf->data;
|
||||
memmove(raw + dst_y * buf->stride,
|
||||
raw + src_y * buf->stride,
|
||||
height * buf->stride);
|
||||
|
|
@ -1587,9 +1587,8 @@ render_csd_title(struct terminal *term)
|
|||
xassert(info.width % term->scale == 0);
|
||||
xassert(info.height % term->scale == 0);
|
||||
|
||||
unsigned long cookie = shm_cookie_csd(term, CSD_SURF_TITLE);
|
||||
struct buffer *buf = shm_get_buffer(
|
||||
term->wl->shm, info.width, info.height, cookie, false, 1);
|
||||
struct buffer_chain *chain = term->render.chains.csd[CSD_SURF_TITLE];
|
||||
struct buffer *buf = shm_get_buffer(chain, info.width, info.height);
|
||||
|
||||
uint32_t _color = term->conf->colors.fg;
|
||||
uint16_t alpha = 0xffff;
|
||||
|
|
@ -1622,9 +1621,8 @@ render_csd_border(struct terminal *term, enum csd_surface surf_idx)
|
|||
xassert(info.width % term->scale == 0);
|
||||
xassert(info.height % term->scale == 0);
|
||||
|
||||
unsigned long cookie = shm_cookie_csd(term, surf_idx);
|
||||
struct buffer *buf = shm_get_buffer(
|
||||
term->wl->shm, info.width, info.height, cookie, false, 1);
|
||||
struct buffer_chain *chain = term->render.chains.csd[surf_idx];
|
||||
struct buffer *buf = shm_get_buffer(chain, info.width, info.height);
|
||||
|
||||
pixman_color_t color = color_hex_to_pixman_with_alpha(0, 0);
|
||||
render_csd_part(term, surf, buf, info.width, info.height, &color);
|
||||
|
|
@ -1808,9 +1806,8 @@ render_csd_button(struct terminal *term, enum csd_surface surf_idx)
|
|||
xassert(info.width % term->scale == 0);
|
||||
xassert(info.height % term->scale == 0);
|
||||
|
||||
unsigned long cookie = shm_cookie_csd(term, surf_idx);
|
||||
struct buffer *buf = shm_get_buffer(
|
||||
term->wl->shm, info.width, info.height, cookie, false, 1);
|
||||
struct buffer_chain *chain = term->render.chains.csd[surf_idx];
|
||||
struct buffer *buf = shm_get_buffer(chain, info.width, info.height);
|
||||
|
||||
uint32_t _color;
|
||||
uint16_t alpha = 0xffff;
|
||||
|
|
@ -2084,9 +2081,8 @@ render_scrollback_position(struct terminal *term)
|
|||
return;
|
||||
}
|
||||
|
||||
unsigned long cookie = shm_cookie_scrollback_indicator(term);
|
||||
struct buffer *buf = shm_get_buffer(
|
||||
term->wl->shm, width, height, cookie, false, 1);
|
||||
struct buffer_chain *chain = term->render.chains.scrollback_indicator;
|
||||
struct buffer *buf = shm_get_buffer(chain, width, height);
|
||||
|
||||
wl_subsurface_set_position(
|
||||
win->scrollback_indicator.sub, x / scale, y / scale);
|
||||
|
|
@ -2117,9 +2113,8 @@ render_render_timer(struct terminal *term, struct timeval render_time)
|
|||
const int height =
|
||||
(2 * margin + term->cell_height + scale - 1) / scale * scale;
|
||||
|
||||
unsigned long cookie = shm_cookie_render_timer(term);
|
||||
struct buffer *buf = shm_get_buffer(
|
||||
term->wl->shm, width, height, cookie, false, 1);
|
||||
struct buffer_chain *chain = term->render.chains.render_timer;
|
||||
struct buffer *buf = shm_get_buffer(chain, width, height);
|
||||
|
||||
wl_subsurface_set_position(
|
||||
win->render_timer.sub,
|
||||
|
|
@ -2162,7 +2157,7 @@ reapply_old_damage(struct terminal *term, struct buffer *new, struct buffer *old
|
|||
}
|
||||
|
||||
if (new->age > 1) {
|
||||
memcpy(new->mmapped, old->mmapped, new->size);
|
||||
memcpy(new->data, old->data, new->height * new->stride);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2292,9 +2287,8 @@ grid_render(struct terminal *term)
|
|||
xassert(term->width > 0);
|
||||
xassert(term->height > 0);
|
||||
|
||||
unsigned long cookie = shm_cookie_grid(term);
|
||||
struct buffer *buf = shm_get_buffer(
|
||||
term->wl->shm, term->width, term->height, cookie, true, 1 + term->render.workers.count);
|
||||
struct buffer_chain *chain = term->render.chains.grid;
|
||||
struct buffer *buf = shm_get_buffer(chain, term->width, term->height);
|
||||
|
||||
/* Dirty old and current cursor cell, to ensure they’re repainted */
|
||||
dirty_old_cursor(term);
|
||||
|
|
@ -2311,7 +2305,7 @@ grid_render(struct terminal *term)
|
|||
}
|
||||
|
||||
else if (buf->age > 0) {
|
||||
LOG_DBG("buffer age: %u", buf->age);
|
||||
LOG_DBG("buffer age: %u (%p)", buf->age, (void *)buf);
|
||||
|
||||
xassert(term->render.last_buf != NULL);
|
||||
xassert(term->render.last_buf != buf);
|
||||
|
|
@ -2324,19 +2318,18 @@ grid_render(struct terminal *term)
|
|||
}
|
||||
|
||||
if (term->render.last_buf != NULL) {
|
||||
term->render.last_buf->locked = false;
|
||||
free(term->render.last_buf->scroll_damage);
|
||||
term->render.last_buf->scroll_damage = NULL;
|
||||
shm_unref(term->render.last_buf);
|
||||
term->render.last_buf = NULL;
|
||||
}
|
||||
|
||||
term->render.last_buf = buf;
|
||||
term->render.was_flashing = term->flash.active;
|
||||
term->render.was_searching = term->is_searching;
|
||||
|
||||
buf->locked = true;
|
||||
shm_addref(buf);
|
||||
buf->age = 0;
|
||||
|
||||
xassert(buf->scroll_damage == NULL);
|
||||
free(term->render.last_buf->scroll_damage);
|
||||
buf->scroll_damage_count = tll_length(term->grid->scroll_damage);
|
||||
buf->scroll_damage = xmalloc(
|
||||
buf->scroll_damage_count * sizeof(buf->scroll_damage[0]));
|
||||
|
|
@ -2627,8 +2620,8 @@ render_search_box(struct terminal *term)
|
|||
const size_t visible_cells = (visible_width - 2 * margin) / term->cell_width;
|
||||
size_t glyph_offset = term->render.search_glyph_offset;
|
||||
|
||||
unsigned long cookie = shm_cookie_search(term);
|
||||
struct buffer *buf = shm_get_buffer(term->wl->shm, width, height, cookie, false, 1);
|
||||
struct buffer_chain *chain = term->render.chains.search;
|
||||
struct buffer *buf = shm_get_buffer(chain, width, height);
|
||||
|
||||
pixman_region32_t clip;
|
||||
pixman_region32_init_rect(&clip, 0, 0, width, height);
|
||||
|
|
@ -2937,7 +2930,8 @@ render_urls(struct terminal *term)
|
|||
} info[tll_length(win->urls)];
|
||||
|
||||
/* For shm_get_many() */
|
||||
struct buffer_description shm_desc[tll_length(win->urls)];
|
||||
int widths[tll_length(win->urls)];
|
||||
int heights[tll_length(win->urls)];
|
||||
|
||||
size_t render_count = 0;
|
||||
|
||||
|
|
@ -3067,15 +3061,15 @@ render_urls(struct terminal *term)
|
|||
info[render_count].x = x;
|
||||
info[render_count].y = y;
|
||||
|
||||
shm_desc[render_count].width = width;
|
||||
shm_desc[render_count].height = height;
|
||||
shm_desc[render_count].cookie = shm_cookie_url(url);
|
||||
widths[render_count] = width;
|
||||
heights[render_count] = height;
|
||||
|
||||
render_count++;
|
||||
}
|
||||
|
||||
struct buffer_chain *chain = term->render.chains.url;
|
||||
struct buffer *bufs[render_count];
|
||||
shm_get_many(term->wl->shm, render_count, shm_desc, bufs, 1);
|
||||
shm_get_many(chain, render_count, widths, heights, bufs);
|
||||
|
||||
uint32_t fg = term->conf->colors.use_custom.jump_label
|
||||
? term->conf->colors.jump_label.fg
|
||||
|
|
@ -3484,8 +3478,7 @@ damage_view:
|
|||
tll_free(term->normal.scroll_damage);
|
||||
tll_free(term->alt.scroll_damage);
|
||||
|
||||
if (term->render.last_buf != NULL)
|
||||
term->render.last_buf->locked = false;
|
||||
shm_unref(term->render.last_buf);
|
||||
term->render.last_buf = NULL;
|
||||
term_damage_view(term);
|
||||
render_refresh_csd(term);
|
||||
|
|
|
|||
477
shm.c
477
shm.c
|
|
@ -55,11 +55,43 @@
|
|||
*/
|
||||
static off_t max_pool_size = 512 * 1024 * 1024;
|
||||
|
||||
static tll(struct buffer) buffers;
|
||||
|
||||
static bool can_punch_hole = false;
|
||||
static bool can_punch_hole_initialized = false;
|
||||
|
||||
struct buffer_pool {
|
||||
int fd; /* memfd */
|
||||
struct wl_shm_pool *wl_pool;
|
||||
|
||||
void *real_mmapped; /* Address returned from mmap */
|
||||
size_t mmap_size; /* Size of mmap (>= size) */
|
||||
|
||||
size_t ref_count;
|
||||
};
|
||||
|
||||
struct buffer_chain;
|
||||
struct buffer_private {
|
||||
struct buffer public;
|
||||
struct buffer_chain *chain;
|
||||
|
||||
size_t ref_count;
|
||||
bool busy; /* Owned by compositor */
|
||||
|
||||
struct buffer_pool *pool;
|
||||
off_t offset; /* Offset into memfd where data begins */
|
||||
size_t size;
|
||||
|
||||
bool scrollable;
|
||||
};
|
||||
|
||||
struct buffer_chain {
|
||||
tll(struct buffer_private *) bufs;
|
||||
struct wl_shm *shm;
|
||||
size_t pix_instances;
|
||||
bool scrollable;
|
||||
};
|
||||
|
||||
static tll(struct buffer_private *) deferred;
|
||||
|
||||
#undef MEASURE_SHM_ALLOCS
|
||||
#if defined(MEASURE_SHM_ALLOCS)
|
||||
static size_t max_alloced = 0;
|
||||
|
|
@ -85,7 +117,7 @@ buffer_destroy_dont_close(struct buffer *buf)
|
|||
free(buf->pix);
|
||||
buf->pix = NULL;
|
||||
buf->wl_buf = NULL;
|
||||
buf->mmapped = NULL;
|
||||
buf->data = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -114,22 +146,41 @@ pool_unref(struct buffer_pool *pool)
|
|||
}
|
||||
|
||||
static void
|
||||
buffer_destroy(struct buffer *buf)
|
||||
buffer_destroy(struct buffer_private *buf)
|
||||
{
|
||||
buffer_destroy_dont_close(buf);
|
||||
buffer_destroy_dont_close(&buf->public);
|
||||
pool_unref(buf->pool);
|
||||
buf->pool = NULL;
|
||||
|
||||
free(buf->scroll_damage);
|
||||
pixman_region32_fini(&buf->dirty);
|
||||
free(buf->public.scroll_damage);
|
||||
pixman_region32_fini(&buf->public.dirty);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static bool
|
||||
buffer_unref_no_remove_from_chain(struct buffer_private *buf)
|
||||
{
|
||||
xassert(buf->ref_count > 0);
|
||||
buf->ref_count--;
|
||||
|
||||
if (buf->ref_count > 0)
|
||||
return false;
|
||||
|
||||
if (buf->busy)
|
||||
tll_push_back(deferred, buf);
|
||||
else
|
||||
buffer_destroy(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
shm_fini(void)
|
||||
{
|
||||
tll_foreach(buffers, it) {
|
||||
buffer_destroy(&it->item);
|
||||
tll_remove(buffers, it);
|
||||
LOG_DBG("deferred buffers: %zu", tll_length(deferred));
|
||||
|
||||
tll_foreach(deferred, it) {
|
||||
buffer_destroy(it->item);
|
||||
tll_remove(deferred, it);
|
||||
}
|
||||
|
||||
#if defined(MEASURE_SHM_ALLOCS) && MEASURE_SHM_ALLOCS
|
||||
|
|
@ -140,14 +191,28 @@ shm_fini(void)
|
|||
static void
|
||||
buffer_release(void *data, struct wl_buffer *wl_buffer)
|
||||
{
|
||||
struct buffer *buffer = data;
|
||||
struct buffer_private *buffer = data;
|
||||
|
||||
LOG_DBG("release: cookie=%lx (buf=%p, total buffer count: %zu)",
|
||||
buffer->cookie, (void *)buffer, tll_length(buffers));
|
||||
|
||||
xassert(buffer->wl_buf == wl_buffer);
|
||||
xassert(buffer->public.wl_buf == wl_buffer);
|
||||
xassert(buffer->busy);
|
||||
buffer->busy = false;
|
||||
|
||||
if (buffer->ref_count == 0) {
|
||||
bool found = false;
|
||||
tll_foreach(deferred, it) {
|
||||
if (it->item == buffer) {
|
||||
found = true;
|
||||
tll_remove(deferred, it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buffer_destroy(buffer);
|
||||
|
||||
xassert(found);
|
||||
if (!found)
|
||||
LOG_WARN("deferred delete: buffer not on the 'deferred' list");
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
|
|
@ -174,23 +239,24 @@ page_size(void)
|
|||
#endif
|
||||
|
||||
static bool
|
||||
instantiate_offset(struct wl_shm *shm, struct buffer *buf, off_t new_offset)
|
||||
instantiate_offset(struct buffer_private *buf, off_t new_offset)
|
||||
{
|
||||
xassert(buf->mmapped == NULL);
|
||||
xassert(buf->wl_buf == NULL);
|
||||
xassert(buf->pix == NULL);
|
||||
xassert(buf->public.data == NULL);
|
||||
xassert(buf->public.pix == NULL);
|
||||
xassert(buf->public.wl_buf == NULL);
|
||||
xassert(buf->pool != NULL);
|
||||
|
||||
const struct buffer_pool *pool = buf->pool;
|
||||
|
||||
void *mmapped = MAP_FAILED;
|
||||
struct wl_buffer *wl_buf = NULL;
|
||||
pixman_image_t **pix = xcalloc(buf->pix_instances, sizeof(*pix));
|
||||
pixman_image_t **pix = xcalloc(buf->public.pix_instances, sizeof(*pix));
|
||||
|
||||
mmapped = (uint8_t *)pool->real_mmapped + new_offset;
|
||||
|
||||
wl_buf = wl_shm_pool_create_buffer(
|
||||
pool->wl_pool, new_offset, buf->width, buf->height, buf->stride,
|
||||
pool->wl_pool, new_offset,
|
||||
buf->public.width, buf->public.height, buf->public.stride,
|
||||
WL_SHM_FORMAT_ARGB8888);
|
||||
|
||||
if (wl_buf == NULL) {
|
||||
|
|
@ -199,26 +265,27 @@ instantiate_offset(struct wl_shm *shm, struct buffer *buf, off_t new_offset)
|
|||
}
|
||||
|
||||
/* One pixman image for each worker thread (do we really need multiple?) */
|
||||
for (size_t i = 0; i < buf->pix_instances; i++) {
|
||||
for (size_t i = 0; i < buf->public.pix_instances; i++) {
|
||||
pix[i] = pixman_image_create_bits_no_clear(
|
||||
PIXMAN_a8r8g8b8, buf->width, buf->height, (uint32_t *)mmapped, buf->stride);
|
||||
PIXMAN_a8r8g8b8, buf->public.width, buf->public.height,
|
||||
(uint32_t *)mmapped, buf->public.stride);
|
||||
if (pix[i] == NULL) {
|
||||
LOG_ERR("failed to create pixman image");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
buf->mmapped = mmapped;
|
||||
buf->public.data = mmapped;
|
||||
buf->public.wl_buf = wl_buf;
|
||||
buf->public.pix = pix;
|
||||
buf->offset = new_offset;
|
||||
buf->wl_buf = wl_buf;
|
||||
buf->pix = pix;
|
||||
|
||||
wl_buffer_add_listener(wl_buf, &buffer_listener, buf);
|
||||
return true;
|
||||
|
||||
err:
|
||||
if (pix != NULL) {
|
||||
for (size_t i = 0; i < buf->pix_instances; i++)
|
||||
for (size_t i = 0; i < buf->public.pix_instances; i++)
|
||||
if (pix[i] != NULL)
|
||||
pixman_image_unref(pix[i]);
|
||||
}
|
||||
|
|
@ -231,35 +298,11 @@ err:
|
|||
}
|
||||
|
||||
static void NOINLINE
|
||||
destroy_all_purgeables(void)
|
||||
get_new_buffers(struct buffer_chain *chain, size_t count,
|
||||
int widths[static count], int heights[static count],
|
||||
struct buffer *bufs[static count], bool immediate_purge)
|
||||
{
|
||||
/* Purge buffers marked for purging */
|
||||
tll_foreach(buffers, it) {
|
||||
if (it->item.locked)
|
||||
continue;
|
||||
|
||||
if (!it->item.purge)
|
||||
continue;
|
||||
|
||||
if (it->item.busy)
|
||||
continue;
|
||||
|
||||
LOG_DBG("cookie=%lx: purging buffer %p (width=%d, height=%d): %zu KB",
|
||||
cookie, (void *)&it->item, it->item.width, it->item.height,
|
||||
it->item.size / 1024);
|
||||
|
||||
buffer_destroy(&it->item);
|
||||
tll_remove(buffers, it);
|
||||
}
|
||||
}
|
||||
|
||||
static void NOINLINE
|
||||
get_new_buffers(struct wl_shm *shm, size_t count,
|
||||
struct buffer_description info[static count],
|
||||
struct buffer *bufs[static count],
|
||||
size_t pix_instances, bool scrollable, bool immediate_purge)
|
||||
{
|
||||
xassert(count == 1 || !scrollable);
|
||||
xassert(count == 1 || !chain->scrollable);
|
||||
/*
|
||||
* No existing buffer available. Create a new one by:
|
||||
*
|
||||
|
|
@ -275,8 +318,8 @@ get_new_buffers(struct wl_shm *shm, size_t count,
|
|||
|
||||
size_t total_size = 0;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
stride[i] = stride_for_format_and_width(PIXMAN_a8r8g8b8, info[i].width);
|
||||
sizes[i] = stride[i] * info[i].height;
|
||||
stride[i] = stride_for_format_and_width(PIXMAN_a8r8g8b8, widths[i]);
|
||||
sizes[i] = stride[i] * heights[i];
|
||||
total_size += sizes[i];
|
||||
}
|
||||
|
||||
|
|
@ -303,14 +346,18 @@ get_new_buffers(struct wl_shm *shm, size_t count,
|
|||
}
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
off_t offset = scrollable && max_pool_size > 0 ? (max_pool_size / 4) & ~(page_size() - 1) : 0;
|
||||
off_t memfd_size = scrollable && max_pool_size > 0 ? max_pool_size : total_size;
|
||||
off_t offset = chain->scrollable && max_pool_size > 0
|
||||
? (max_pool_size / 4) & ~(page_size() - 1)
|
||||
: 0;
|
||||
off_t memfd_size = chain->scrollable && max_pool_size > 0
|
||||
? max_pool_size
|
||||
: total_size;
|
||||
#else
|
||||
off_t offset = 0;
|
||||
off_t memfd_size = total_size;
|
||||
#endif
|
||||
|
||||
xassert(scrollable || (offset == 0 && memfd_size == total_size));
|
||||
xassert(chain->scrollable || (offset == 0 && memfd_size == total_size));
|
||||
|
||||
LOG_DBG("memfd-size: %lu, initial offset: %lu", memfd_size, offset);
|
||||
|
||||
|
|
@ -337,10 +384,10 @@ get_new_buffers(struct wl_shm *shm, size_t count,
|
|||
#endif
|
||||
}
|
||||
|
||||
if (scrollable && !can_punch_hole) {
|
||||
if (chain->scrollable && !can_punch_hole) {
|
||||
offset = 0;
|
||||
memfd_size = total_size;
|
||||
scrollable = false;
|
||||
chain->scrollable = false;
|
||||
|
||||
if (ftruncate(pool_fd, memfd_size) < 0) {
|
||||
LOG_ERRNO("failed to set size of SHM backing memory file");
|
||||
|
|
@ -368,13 +415,13 @@ get_new_buffers(struct wl_shm *shm, size_t count,
|
|||
}
|
||||
#endif
|
||||
|
||||
wl_pool = wl_shm_create_pool(shm, pool_fd, memfd_size);
|
||||
wl_pool = wl_shm_create_pool(chain->shm, pool_fd, memfd_size);
|
||||
if (wl_pool == NULL) {
|
||||
LOG_ERR("failed to create SHM pool");
|
||||
goto err;
|
||||
}
|
||||
|
||||
pool = malloc(sizeof(*pool));
|
||||
pool = xmalloc(sizeof(*pool));
|
||||
if (pool == NULL) {
|
||||
LOG_ERRNO("failed to allocate buffer pool");
|
||||
goto err;
|
||||
|
|
@ -391,31 +438,38 @@ get_new_buffers(struct wl_shm *shm, size_t count,
|
|||
for (size_t i = 0; i < count; i++) {
|
||||
|
||||
/* Push to list of available buffers, but marked as 'busy' */
|
||||
tll_push_front(
|
||||
buffers,
|
||||
((struct buffer){
|
||||
.cookie = info[i].cookie,
|
||||
.width = info[i].width,
|
||||
.height = info[i].height,
|
||||
struct buffer_private *buf = xmalloc(sizeof(*buf));
|
||||
*buf = (struct buffer_private){
|
||||
.public = {
|
||||
.width = widths[i],
|
||||
.height = heights[i],
|
||||
.stride = stride[i],
|
||||
.busy = true,
|
||||
.purge = immediate_purge,
|
||||
.size = sizes[i],
|
||||
.pix_instances = pix_instances,
|
||||
.pool = pool,
|
||||
.scrollable = scrollable,
|
||||
.offset = 0,
|
||||
.pix_instances = chain->pix_instances,
|
||||
.age = 1234, /* Force a full repaint */
|
||||
}));
|
||||
},
|
||||
.chain = chain,
|
||||
.ref_count = immediate_purge ? 0 : 1,
|
||||
.busy = true,
|
||||
.pool = pool,
|
||||
.offset = 0,
|
||||
.size = sizes[i],
|
||||
.scrollable = chain->scrollable,
|
||||
};
|
||||
|
||||
struct buffer *buf = &tll_front(buffers);
|
||||
if (!instantiate_offset(shm, buf, offset))
|
||||
if (!instantiate_offset(buf, offset)) {
|
||||
free(buf);
|
||||
goto err;
|
||||
}
|
||||
|
||||
pixman_region32_init(&buf->dirty);
|
||||
if (immediate_purge)
|
||||
tll_push_front(deferred, buf);
|
||||
else
|
||||
tll_push_front(chain->bufs, buf);
|
||||
|
||||
pixman_region32_init(&buf->public.dirty);
|
||||
pool->ref_count++;
|
||||
offset += buf->size;
|
||||
bufs[i] = buf;
|
||||
bufs[i] = &buf->public;
|
||||
}
|
||||
|
||||
#if defined(MEASURE_SHM_ALLOCS) && MEASURE_SHM_ALLOCS
|
||||
|
|
@ -451,90 +505,77 @@ err:
|
|||
}
|
||||
|
||||
void
|
||||
shm_get_many(struct wl_shm *shm, size_t count,
|
||||
struct buffer_description info[static count],
|
||||
struct buffer *bufs[static count],
|
||||
size_t pix_instances)
|
||||
shm_get_many(struct buffer_chain *chain, size_t count,
|
||||
int widths[static count], int heights[static count],
|
||||
struct buffer *bufs[static count])
|
||||
{
|
||||
destroy_all_purgeables();
|
||||
get_new_buffers(shm, count, info, bufs, pix_instances, false, true);
|
||||
get_new_buffers(chain, count, widths, heights, bufs, true);
|
||||
}
|
||||
|
||||
struct buffer *
|
||||
shm_get_buffer(struct wl_shm *shm, int width, int height, unsigned long cookie,
|
||||
bool scrollable, size_t pix_instances)
|
||||
shm_get_buffer(struct buffer_chain *chain, int width, int height)
|
||||
{
|
||||
destroy_all_purgeables();
|
||||
LOG_DBG(
|
||||
"chain=%p: looking for a re-usable %dx%d buffer "
|
||||
"among %zu potential buffers",
|
||||
(void *)chain, width, height, tll_length(chain->bufs));
|
||||
|
||||
struct buffer *cached = NULL;
|
||||
tll_foreach(buffers, it) {
|
||||
if (it->item.width != width)
|
||||
continue;
|
||||
if (it->item.height != height)
|
||||
continue;
|
||||
if (it->item.cookie != cookie)
|
||||
continue;
|
||||
struct buffer_private *cached = NULL;
|
||||
tll_foreach(chain->bufs, it) {
|
||||
struct buffer_private *buf = it->item;
|
||||
|
||||
if (it->item.busy)
|
||||
it->item.age++;
|
||||
if (buf->public.width != width || buf->public.height != height) {
|
||||
LOG_DBG("purging mismatching buffer %p", (void *)buf);
|
||||
if (buffer_unref_no_remove_from_chain(buf))
|
||||
tll_remove(chain->bufs, it);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buf->busy)
|
||||
buf->public.age++;
|
||||
else
|
||||
#if FORCED_DOUBLE_BUFFERING
|
||||
if (it->item.age == 0)
|
||||
it->item.age++;
|
||||
if (buf->age == 0)
|
||||
buf->age++;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (cached == NULL) {
|
||||
LOG_DBG("cookie=%lx: re-using buffer from cache (buf=%p)",
|
||||
cookie, (void *)&it->item);
|
||||
it->item.busy = true;
|
||||
it->item.purge = false;
|
||||
pixman_region32_clear(&it->item.dirty);
|
||||
free(it->item.scroll_damage);
|
||||
it->item.scroll_damage = NULL;
|
||||
xassert(it->item.pix_instances == pix_instances);
|
||||
cached = &it->item;
|
||||
LOG_DBG("re-using buffer %p from cache", (void *)buf);
|
||||
buf->busy = true;
|
||||
pixman_region32_clear(&buf->public.dirty);
|
||||
free(buf->public.scroll_damage);
|
||||
buf->public.scroll_damage = NULL;
|
||||
xassert(buf->public.pix_instances == chain->pix_instances);
|
||||
cached = it->item;
|
||||
} else {
|
||||
/* We have multiple buffers eligible for
|
||||
* re-use. Pick the “youngest” one, and mark the
|
||||
* other one for purging */
|
||||
if (it->item.age < cached->age) {
|
||||
cached->purge = true;
|
||||
cached = &it->item;
|
||||
} else
|
||||
it->item.purge = true;
|
||||
if (buf->public.age < cached->public.age) {
|
||||
shm_unref(&cached->public);
|
||||
cached = buf;
|
||||
} else {
|
||||
if (buffer_unref_no_remove_from_chain(buf))
|
||||
tll_remove(chain->bufs, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cached != NULL)
|
||||
return cached;
|
||||
|
||||
/* Mark old buffers associated with this cookie for purging */
|
||||
tll_foreach(buffers, it) {
|
||||
if (it->item.cookie != cookie)
|
||||
continue;
|
||||
|
||||
if (it->item.busy)
|
||||
continue;
|
||||
|
||||
if (it->item.width == width && it->item.height == height)
|
||||
continue;
|
||||
|
||||
LOG_DBG("cookie=%lx: marking buffer %p for purging", cookie, (void *)&it->item);
|
||||
it->item.purge = true;
|
||||
}
|
||||
return &cached->public;
|
||||
|
||||
struct buffer *ret;
|
||||
get_new_buffers(shm, 1, &(struct buffer_description){width, height, cookie},
|
||||
&ret, pix_instances, scrollable, false);
|
||||
get_new_buffers(chain, 1, &width, &height, &ret, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
shm_can_scroll(const struct buffer *buf)
|
||||
shm_can_scroll(const struct buffer *_buf)
|
||||
{
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
const struct buffer_private *buf = (const struct buffer_private *)_buf;
|
||||
return can_punch_hole && max_pool_size > 0 && buf->scrollable;
|
||||
#else
|
||||
/* Not enough virtual address space in 32-bit */
|
||||
|
|
@ -544,17 +585,20 @@ shm_can_scroll(const struct buffer *buf)
|
|||
|
||||
#if __SIZEOF_POINTER__ == 8 && defined(FALLOC_FL_PUNCH_HOLE)
|
||||
static bool
|
||||
wrap_buffer(struct wl_shm *shm, struct buffer *buf, off_t new_offset)
|
||||
wrap_buffer(struct buffer_private *buf, off_t new_offset)
|
||||
{
|
||||
struct buffer_pool *pool = buf->pool;
|
||||
xassert(pool->ref_count == 1);
|
||||
|
||||
/* We don't allow overlapping offsets */
|
||||
off_t UNUSED diff =
|
||||
new_offset < buf->offset ? buf->offset - new_offset : new_offset - buf->offset;
|
||||
off_t UNUSED diff = new_offset < buf->offset
|
||||
? buf->offset - new_offset
|
||||
: new_offset - buf->offset;
|
||||
xassert(diff > buf->size);
|
||||
|
||||
memcpy((uint8_t *)pool->real_mmapped + new_offset, buf->mmapped, buf->size);
|
||||
memcpy((uint8_t *)pool->real_mmapped + new_offset,
|
||||
buf->public.data,
|
||||
buf->size);
|
||||
|
||||
off_t trim_ofs, trim_len;
|
||||
if (new_offset > buf->offset) {
|
||||
|
|
@ -577,12 +621,12 @@ wrap_buffer(struct wl_shm *shm, struct buffer *buf, off_t new_offset)
|
|||
}
|
||||
|
||||
/* Re-instantiate pixman+wl_buffer+raw pointersw */
|
||||
buffer_destroy_dont_close(buf);
|
||||
return instantiate_offset(shm, buf, new_offset);
|
||||
buffer_destroy_dont_close(&buf->public);
|
||||
return instantiate_offset(buf, new_offset);
|
||||
}
|
||||
|
||||
static bool
|
||||
shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||
shm_scroll_forward(struct buffer_private *buf, int rows,
|
||||
int top_margin, int top_keep_rows,
|
||||
int bottom_margin, int bottom_keep_rows)
|
||||
{
|
||||
|
|
@ -590,21 +634,21 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
|
||||
xassert(can_punch_hole);
|
||||
xassert(buf->busy);
|
||||
xassert(buf->pix);
|
||||
xassert(buf->wl_buf);
|
||||
xassert(buf->public.pix != NULL);
|
||||
xassert(buf->public.wl_buf != NULL);
|
||||
xassert(pool != NULL);
|
||||
xassert(pool->ref_count == 1);
|
||||
xassert(pool->fd >= 0);
|
||||
|
||||
LOG_DBG("scrolling %d rows (%d bytes)", rows, rows * buf->stride);
|
||||
LOG_DBG("scrolling %d rows (%d bytes)", rows, rows * buf->public.stride);
|
||||
|
||||
const off_t diff = rows * buf->stride;
|
||||
const off_t diff = rows * buf->public.stride;
|
||||
xassert(rows > 0);
|
||||
xassert(diff < buf->size);
|
||||
|
||||
if (buf->offset + diff + buf->size > max_pool_size) {
|
||||
LOG_DBG("memfd offset wrap around");
|
||||
if (!wrap_buffer(shm, buf, 0))
|
||||
if (!wrap_buffer(buf, 0))
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -613,6 +657,7 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
xassert(new_offset + buf->size <= max_pool_size);
|
||||
|
||||
#if TIME_SCROLL
|
||||
struct timeval tot;
|
||||
struct timeval time1;
|
||||
gettimeofday(&time1, NULL);
|
||||
|
||||
|
|
@ -621,10 +666,13 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
|
||||
if (top_keep_rows > 0) {
|
||||
/* Copy current 'top' region to its new location */
|
||||
const int stride = buf->public.stride;
|
||||
uint8_t *base = buf->public.data;
|
||||
|
||||
memmove(
|
||||
(uint8_t *)buf->mmapped + (top_margin + rows) * buf->stride,
|
||||
(uint8_t *)buf->mmapped + (top_margin + 0) * buf->stride,
|
||||
top_keep_rows * buf->stride);
|
||||
base + (top_margin + rows) * stride,
|
||||
base + (top_margin + 0) * stride,
|
||||
top_keep_rows * stride);
|
||||
|
||||
#if TIME_SCROLL
|
||||
gettimeofday(&time2, NULL);
|
||||
|
|
@ -634,7 +682,7 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
}
|
||||
|
||||
/* Destroy old objects (they point to the old offset) */
|
||||
buffer_destroy_dont_close(buf);
|
||||
buffer_destroy_dont_close(&buf->public);
|
||||
|
||||
/* Free unused memory - everything up until the new offset */
|
||||
const off_t trim_ofs = 0;
|
||||
|
|
@ -657,7 +705,7 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
#endif
|
||||
|
||||
/* Re-instantiate pixman+wl_buffer+raw pointersw */
|
||||
bool ret = instantiate_offset(shm, buf, new_offset);
|
||||
bool ret = instantiate_offset(buf, new_offset);
|
||||
|
||||
#if TIME_SCROLL
|
||||
struct timeval time4;
|
||||
|
|
@ -668,10 +716,14 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
|
||||
if (ret && bottom_keep_rows > 0) {
|
||||
/* Copy 'bottom' region to its new location */
|
||||
const size_t size = buf->size;
|
||||
const int stride = buf->public.stride;
|
||||
uint8_t *base = buf->public.data;
|
||||
|
||||
memmove(
|
||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + bottom_keep_rows) * buf->stride,
|
||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + rows + bottom_keep_rows) * buf->stride,
|
||||
bottom_keep_rows * buf->stride);
|
||||
base + size - (bottom_margin + bottom_keep_rows) * stride,
|
||||
base + size - (bottom_margin + rows + bottom_keep_rows) * stride,
|
||||
bottom_keep_rows * stride);
|
||||
|
||||
#if TIME_SCROLL
|
||||
struct timeval time5;
|
||||
|
|
@ -690,7 +742,7 @@ err:
|
|||
}
|
||||
|
||||
static bool
|
||||
shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||
shm_scroll_reverse(struct buffer_private *buf, int rows,
|
||||
int top_margin, int top_keep_rows,
|
||||
int bottom_margin, int bottom_keep_rows)
|
||||
{
|
||||
|
|
@ -699,10 +751,10 @@ shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
struct buffer_pool *pool = buf->pool;
|
||||
xassert(pool->ref_count == 1);
|
||||
|
||||
const off_t diff = rows * buf->stride;
|
||||
const off_t diff = rows * buf->public.stride;
|
||||
if (diff > buf->offset) {
|
||||
LOG_DBG("memfd offset reverse wrap-around");
|
||||
if (!wrap_buffer(shm, buf, (max_pool_size - buf->size) & ~(page_size() - 1)))
|
||||
if (!wrap_buffer(buf, (max_pool_size - buf->size) & ~(page_size() - 1)))
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -720,10 +772,14 @@ shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
|
||||
if (bottom_keep_rows > 0) {
|
||||
/* Copy 'bottom' region to its new location */
|
||||
const size_t size = buf->size;
|
||||
const int stride = buf->public.stride;
|
||||
uint8_t *base = buf->public.data;
|
||||
|
||||
memmove(
|
||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + rows + bottom_keep_rows) * buf->stride,
|
||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + bottom_keep_rows) * buf->stride,
|
||||
bottom_keep_rows * buf->stride);
|
||||
base + size - (bottom_margin + rows + bottom_keep_rows) * stride,
|
||||
base + size - (bottom_margin + bottom_keep_rows) * stride,
|
||||
bottom_keep_rows * stride);
|
||||
|
||||
#if TIME_SCROLL
|
||||
gettimeofday(&time1, NULL);
|
||||
|
|
@ -733,7 +789,7 @@ shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
}
|
||||
|
||||
/* Destroy old objects (they point to the old offset) */
|
||||
buffer_destroy_dont_close(buf);
|
||||
buffer_destroy_dont_close(&buf->public);
|
||||
|
||||
/* Free unused memory - everything after the relocated buffer */
|
||||
const off_t trim_ofs = new_offset + buf->size;
|
||||
|
|
@ -755,7 +811,7 @@ shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
#endif
|
||||
|
||||
/* Re-instantiate pixman+wl_buffer+raw pointers */
|
||||
bool ret = instantiate_offset(shm, buf, new_offset);
|
||||
bool ret = instantiate_offset(buf, new_offset);
|
||||
|
||||
#if TIME_SCROLL
|
||||
struct timeval time3;
|
||||
|
|
@ -766,10 +822,13 @@ shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
|
||||
if (ret && top_keep_rows > 0) {
|
||||
/* Copy current 'top' region to its new location */
|
||||
const int stride = buf->public.stride;
|
||||
uint8_t *base = buf->public.data;
|
||||
|
||||
memmove(
|
||||
(uint8_t *)buf->mmapped + (top_margin + 0) * buf->stride,
|
||||
(uint8_t *)buf->mmapped + (top_margin + rows) * buf->stride,
|
||||
top_keep_rows * buf->stride);
|
||||
base + (top_margin + 0) * stride,
|
||||
base + (top_margin + rows) * stride,
|
||||
top_keep_rows * stride);
|
||||
|
||||
#if TIME_SCROLL
|
||||
struct timeval time4;
|
||||
|
|
@ -788,40 +847,88 @@ err:
|
|||
#endif /* FALLOC_FL_PUNCH_HOLE */
|
||||
|
||||
bool
|
||||
shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||
shm_scroll(struct buffer *_buf, int rows,
|
||||
int top_margin, int top_keep_rows,
|
||||
int bottom_margin, int bottom_keep_rows)
|
||||
{
|
||||
#if __SIZEOF_POINTER__ == 8 && defined(FALLOC_FL_PUNCH_HOLE)
|
||||
if (!shm_can_scroll(buf))
|
||||
if (!shm_can_scroll(_buf))
|
||||
return false;
|
||||
|
||||
struct buffer_private *buf = (struct buffer_private *)_buf;
|
||||
|
||||
xassert(rows != 0);
|
||||
return rows > 0
|
||||
? shm_scroll_forward(shm, buf, rows, top_margin, top_keep_rows, bottom_margin, bottom_keep_rows)
|
||||
: shm_scroll_reverse(shm, buf, -rows, top_margin, top_keep_rows, bottom_margin, bottom_keep_rows);
|
||||
? shm_scroll_forward(buf, rows, top_margin, top_keep_rows, bottom_margin, bottom_keep_rows)
|
||||
: shm_scroll_reverse(buf, -rows, top_margin, top_keep_rows, bottom_margin, bottom_keep_rows);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
shm_purge(struct wl_shm *shm, unsigned long cookie)
|
||||
shm_purge(struct buffer_chain *chain)
|
||||
{
|
||||
LOG_DBG("cookie=%lx: purging all buffers", cookie);
|
||||
LOG_DBG("chain: %p: purging all buffers", (void *)chain);
|
||||
|
||||
/* Purge old buffers associated with this cookie */
|
||||
tll_foreach(buffers, it) {
|
||||
if (it->item.cookie != cookie)
|
||||
continue;
|
||||
|
||||
if (it->item.busy) {
|
||||
LOG_WARN("deferring purge of 'busy' buffer (width=%d, height=%d)",
|
||||
it->item.width, it->item.height);
|
||||
it->item.purge = true;
|
||||
} else {
|
||||
buffer_destroy(&it->item);
|
||||
tll_remove(buffers, it);
|
||||
}
|
||||
tll_foreach(chain->bufs, it) {
|
||||
if (buffer_unref_no_remove_from_chain(it->item))
|
||||
tll_remove(chain->bufs, it);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
shm_addref(struct buffer *_buf)
|
||||
{
|
||||
struct buffer_private *buf = (struct buffer_private *)_buf;
|
||||
buf->ref_count++;
|
||||
}
|
||||
|
||||
void
|
||||
shm_unref(struct buffer *_buf)
|
||||
{
|
||||
if (_buf == NULL)
|
||||
return;
|
||||
|
||||
struct buffer_private *buf = (struct buffer_private *)_buf;
|
||||
struct buffer_chain *chain = buf->chain;
|
||||
|
||||
tll_foreach(chain->bufs, it) {
|
||||
if (it->item != buf)
|
||||
continue;
|
||||
|
||||
if (buffer_unref_no_remove_from_chain(buf))
|
||||
tll_remove(chain->bufs, it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct buffer_chain *
|
||||
shm_chain_new(struct wl_shm *shm, bool scrollable, size_t pix_instances)
|
||||
{
|
||||
struct buffer_chain *chain = xmalloc(sizeof(*chain));
|
||||
*chain = (struct buffer_chain){
|
||||
.bufs = tll_init(),
|
||||
.shm = shm,
|
||||
.pix_instances = pix_instances,
|
||||
.scrollable = scrollable,
|
||||
};
|
||||
return chain;
|
||||
}
|
||||
|
||||
void
|
||||
shm_chain_free(struct buffer_chain *chain)
|
||||
{
|
||||
if (chain == NULL)
|
||||
return;
|
||||
|
||||
shm_purge(chain);
|
||||
|
||||
if (tll_length(chain->bufs) > 0) {
|
||||
BUG("chain=%p: there are buffers remaining; "
|
||||
"is there a missing call to shm_unref()?", (void *)chain);
|
||||
}
|
||||
|
||||
free(chain);
|
||||
}
|
||||
|
|
|
|||
66
shm.h
66
shm.h
|
|
@ -7,69 +7,46 @@
|
|||
#include <pixman.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "terminal.h"
|
||||
#include <tllist.h>
|
||||
|
||||
struct buffer_pool {
|
||||
int fd; /* memfd */
|
||||
struct wl_shm_pool *wl_pool;
|
||||
|
||||
void *real_mmapped; /* Address returned from mmap */
|
||||
size_t mmap_size; /* Size of mmap (>= size) */
|
||||
|
||||
size_t ref_count;
|
||||
};
|
||||
struct damage;
|
||||
|
||||
struct buffer {
|
||||
unsigned long cookie;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
|
||||
bool locked; /* Caller owned, shm won’t destroy it */
|
||||
bool busy; /* Owned by compositor */
|
||||
size_t size; /* Buffer size */
|
||||
void *mmapped; /* Raw data (TODO: rename) */
|
||||
void *data;
|
||||
|
||||
struct wl_buffer *wl_buf;
|
||||
pixman_image_t **pix;
|
||||
size_t pix_instances;
|
||||
|
||||
/* Internal */
|
||||
struct buffer_pool *pool;
|
||||
off_t offset; /* Offset into memfd where data begins */
|
||||
|
||||
bool scrollable;
|
||||
bool purge; /* True if this buffer should be destroyed */
|
||||
|
||||
unsigned age;
|
||||
|
||||
struct damage *scroll_damage;
|
||||
size_t scroll_damage_count;
|
||||
pixman_region32_t dirty;
|
||||
};
|
||||
|
||||
struct buffer_description {
|
||||
int width;
|
||||
int height;
|
||||
unsigned long cookie;
|
||||
};
|
||||
|
||||
void shm_fini(void);
|
||||
void shm_set_max_pool_size(off_t max_pool_size);
|
||||
|
||||
struct buffer_chain;
|
||||
struct buffer_chain *shm_chain_new(
|
||||
struct wl_shm *shm, bool scrollable, size_t pix_instances);
|
||||
void shm_chain_free(struct buffer_chain *chain);
|
||||
|
||||
/*
|
||||
* Returns a single buffer.
|
||||
*
|
||||
* May returned a cached buffer. If so, the buffer’s age indicates how
|
||||
* many shm_get_buffer() calls have been made for the same
|
||||
* width/height/cookie while the buffer was still busy.
|
||||
* width/height while the buffer was still busy.
|
||||
*
|
||||
* A newly allocated buffer has an age of 1234.
|
||||
*/
|
||||
struct buffer *shm_get_buffer(
|
||||
struct wl_shm *shm, int width, int height, unsigned long cookie,
|
||||
bool scrollable, size_t pix_instances);
|
||||
|
||||
struct buffer *shm_get_buffer(struct buffer_chain *chain, int width, int height);
|
||||
/*
|
||||
* Returns many buffers, described by ‘info’, all sharing the same SHM
|
||||
* buffer pool.
|
||||
|
|
@ -85,23 +62,16 @@ struct buffer *shm_get_buffer(
|
|||
* soon as the compositor releases them.
|
||||
*/
|
||||
void shm_get_many(
|
||||
struct wl_shm *shm, size_t count,
|
||||
struct buffer_description info[static count],
|
||||
struct buffer *bufs[static count], size_t pix_instances);
|
||||
struct buffer_chain *chain, size_t count,
|
||||
int widths[static count], int heights[static count],
|
||||
struct buffer *bufs[static count]);
|
||||
|
||||
bool shm_can_scroll(const struct buffer *buf);
|
||||
bool shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||
bool shm_scroll(struct buffer *buf, int rows,
|
||||
int top_margin, int top_keep_rows,
|
||||
int bottom_margin, int bottom_keep_rows);
|
||||
|
||||
void shm_purge(struct wl_shm *shm, unsigned long cookie);
|
||||
void shm_addref(struct buffer *buf);
|
||||
void shm_unref(struct buffer *buf);
|
||||
|
||||
struct terminal;
|
||||
static inline unsigned long shm_cookie_grid(const struct terminal *term) { return (unsigned long)((uintptr_t)term + 0); }
|
||||
static inline unsigned long shm_cookie_search(const struct terminal *term) { return (unsigned long)((uintptr_t)term + 1); }
|
||||
static inline unsigned long shm_cookie_scrollback_indicator(const struct terminal *term) { return (unsigned long)(uintptr_t)term + 2; }
|
||||
static inline unsigned long shm_cookie_render_timer(const struct terminal *term) { return (unsigned long)(uintptr_t)term + 3; }
|
||||
static inline unsigned long shm_cookie_csd(const struct terminal *term, int n) { return (unsigned long)((uintptr_t)term + 4 + (n)); }
|
||||
|
||||
struct url;
|
||||
static inline unsigned long shm_cookie_url(const struct url *url) { return (unsigned long)(uintptr_t)url; }
|
||||
void shm_purge(struct buffer_chain *chain);
|
||||
|
|
|
|||
27
terminal.c
27
terminal.c
|
|
@ -35,6 +35,7 @@
|
|||
#include "selection.h"
|
||||
#include "sixel.h"
|
||||
#include "slave.h"
|
||||
#include "shm.h"
|
||||
#include "spawn.h"
|
||||
#include "url-mode.h"
|
||||
#include "util.h"
|
||||
|
|
@ -1143,6 +1144,23 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
|||
.tab_stops = tll_init(),
|
||||
.wl = wayl,
|
||||
.render = {
|
||||
.chains = {
|
||||
.grid = shm_chain_new(wayl->shm, true, 1 + conf->render_worker_count),
|
||||
.search = shm_chain_new(wayl->shm, false, 1),
|
||||
.scrollback_indicator = shm_chain_new(wayl->shm, false, 1),
|
||||
.render_timer = shm_chain_new(wayl->shm, false, 1),
|
||||
.url = shm_chain_new(wayl->shm, false, 1),
|
||||
.csd = {
|
||||
[CSD_SURF_TITLE] = shm_chain_new(wayl->shm, false, 1),
|
||||
[CSD_SURF_LEFT] = shm_chain_new(wayl->shm, false, 1),
|
||||
[CSD_SURF_RIGHT] = shm_chain_new(wayl->shm, false, 1),
|
||||
[CSD_SURF_TOP] = shm_chain_new(wayl->shm, false, 1),
|
||||
[CSD_SURF_BOTTOM] = shm_chain_new(wayl->shm, false, 1),
|
||||
[CSD_SURF_MINIMIZE] = shm_chain_new(wayl->shm, false, 1),
|
||||
[CSD_SURF_MAXIMIZE] = shm_chain_new(wayl->shm, false, 1),
|
||||
[CSD_SURF_CLOSE] = shm_chain_new(wayl->shm, false, 1),
|
||||
},
|
||||
},
|
||||
.scrollback_lines = conf->scrollback.lines,
|
||||
.app_sync_updates.timer_fd = app_sync_updates_fd,
|
||||
.title = {
|
||||
|
|
@ -1458,6 +1476,15 @@ term_destroy(struct terminal *term)
|
|||
xassert(tll_length(term->render.workers.queue) == 0);
|
||||
tll_free(term->render.workers.queue);
|
||||
|
||||
shm_unref(term->render.last_buf);
|
||||
shm_chain_free(term->render.chains.grid);
|
||||
shm_chain_free(term->render.chains.search);
|
||||
shm_chain_free(term->render.chains.scrollback_indicator);
|
||||
shm_chain_free(term->render.chains.render_timer);
|
||||
shm_chain_free(term->render.chains.url);
|
||||
for (size_t i = 0; i < CSD_SURF_COUNT; i++)
|
||||
shm_chain_free(term->render.chains.csd[i]);
|
||||
|
||||
tll_free(term->tab_stops);
|
||||
|
||||
tll_foreach(term->ptmx_buffers, it) {
|
||||
|
|
|
|||
10
terminal.h
10
terminal.h
|
|
@ -21,6 +21,7 @@
|
|||
#include "fdm.h"
|
||||
#include "macros.h"
|
||||
#include "reaper.h"
|
||||
#include "shm.h"
|
||||
#include "wayland.h"
|
||||
|
||||
/*
|
||||
|
|
@ -475,6 +476,15 @@ struct terminal {
|
|||
enum term_surface active_surface;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
struct buffer_chain *grid;
|
||||
struct buffer_chain *search;
|
||||
struct buffer_chain *scrollback_indicator;
|
||||
struct buffer_chain *render_timer;
|
||||
struct buffer_chain *url;
|
||||
struct buffer_chain *csd[CSD_SURF_COUNT];
|
||||
} chains;
|
||||
|
||||
/* Scheduled for rendering, as soon-as-possible */
|
||||
struct {
|
||||
bool grid;
|
||||
|
|
|
|||
16
wayland.c
16
wayland.c
|
|
@ -52,11 +52,10 @@ static void
|
|||
csd_destroy(struct wl_window *win)
|
||||
{
|
||||
struct terminal *term = win->term;
|
||||
struct wl_shm *shm = term->wl->shm;
|
||||
|
||||
for (size_t i = 0; i < ALEN(win->csd.surface); i++) {
|
||||
wayl_win_subsurface_destroy(&win->csd.surface[i]);
|
||||
shm_purge(shm, shm_cookie_csd(term, i));
|
||||
shm_purge(term->render.chains.csd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1417,7 +1416,6 @@ wayl_win_destroy(struct wl_window *win)
|
|||
return;
|
||||
|
||||
struct terminal *term = win->term;
|
||||
struct wl_shm *shm = term->wl->shm;
|
||||
|
||||
if (win->csd.move_timeout_fd != -1)
|
||||
close(win->csd.move_timeout_fd);
|
||||
|
|
@ -1472,7 +1470,7 @@ wayl_win_destroy(struct wl_window *win)
|
|||
|
||||
tll_foreach(win->urls, it) {
|
||||
wayl_win_subsurface_destroy(&it->item.surf);
|
||||
shm_purge(shm, shm_cookie_url(it->item.url));
|
||||
shm_purge(term->render.chains.url);
|
||||
tll_remove(win->urls, it);
|
||||
}
|
||||
|
||||
|
|
@ -1481,13 +1479,13 @@ wayl_win_destroy(struct wl_window *win)
|
|||
wayl_win_subsurface_destroy(&win->scrollback_indicator);
|
||||
wayl_win_subsurface_destroy(&win->render_timer);
|
||||
|
||||
shm_purge(shm, shm_cookie_search(term));
|
||||
shm_purge(shm, shm_cookie_scrollback_indicator(term));
|
||||
shm_purge(shm, shm_cookie_render_timer(term));
|
||||
shm_purge(shm, shm_cookie_grid(term));
|
||||
shm_purge(term->render.chains.search);
|
||||
shm_purge(term->render.chains.scrollback_indicator);
|
||||
shm_purge(term->render.chains.render_timer);
|
||||
shm_purge(term->render.chains.grid);
|
||||
|
||||
for (size_t i = 0; i < ALEN(win->csd.surface); i++)
|
||||
shm_purge(shm, shm_cookie_csd(term, i));
|
||||
shm_purge(term->render.chains.csd[i]);
|
||||
|
||||
#if defined(HAVE_XDG_ACTIVATION)
|
||||
if (win->xdg_activation_token != NULL)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue