mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-09 08:21:01 -04:00
shm: split up buffer struct into internal/private and public parts
This commit is contained in:
parent
a18959f2df
commit
75f7f21a48
2 changed files with 127 additions and 99 deletions
205
shm.c
205
shm.c
|
|
@ -55,11 +55,34 @@
|
||||||
*/
|
*/
|
||||||
static off_t max_pool_size = 512 * 1024 * 1024;
|
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 = false;
|
||||||
static bool can_punch_hole_initialized = 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_private {
|
||||||
|
struct buffer public;
|
||||||
|
|
||||||
|
bool busy; /* Owned by compositor */
|
||||||
|
|
||||||
|
unsigned long cookie;
|
||||||
|
struct buffer_pool *pool;
|
||||||
|
off_t offset; /* Offset into memfd where data begins */
|
||||||
|
|
||||||
|
bool scrollable;
|
||||||
|
bool purge; /* True if this buffer should be destroyed */
|
||||||
|
};
|
||||||
|
|
||||||
|
static tll(struct buffer_private) buffers;
|
||||||
|
|
||||||
#undef MEASURE_SHM_ALLOCS
|
#undef MEASURE_SHM_ALLOCS
|
||||||
#if defined(MEASURE_SHM_ALLOCS)
|
#if defined(MEASURE_SHM_ALLOCS)
|
||||||
static size_t max_alloced = 0;
|
static size_t max_alloced = 0;
|
||||||
|
|
@ -114,14 +137,14 @@ pool_unref(struct buffer_pool *pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
pool_unref(buf->pool);
|
||||||
buf->pool = NULL;
|
buf->pool = NULL;
|
||||||
|
|
||||||
free(buf->scroll_damage);
|
free(buf->public.scroll_damage);
|
||||||
pixman_region32_fini(&buf->dirty);
|
pixman_region32_fini(&buf->public.dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -140,12 +163,12 @@ shm_fini(void)
|
||||||
static void
|
static void
|
||||||
buffer_release(void *data, struct wl_buffer *wl_buffer)
|
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)",
|
LOG_DBG("release: cookie=%lx (buf=%p, total buffer count: %zu)",
|
||||||
buffer->cookie, (void *)buffer, tll_length(buffers));
|
buffer->cookie, (void *)buffer, tll_length(buffers));
|
||||||
|
|
||||||
xassert(buffer->wl_buf == wl_buffer);
|
xassert(buffer->public.wl_buf == wl_buffer);
|
||||||
xassert(buffer->busy);
|
xassert(buffer->busy);
|
||||||
buffer->busy = false;
|
buffer->busy = false;
|
||||||
}
|
}
|
||||||
|
|
@ -174,23 +197,24 @@ page_size(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
instantiate_offset(struct wl_shm *shm, struct buffer *buf, off_t new_offset)
|
instantiate_offset(struct wl_shm *shm, struct buffer_private *buf, off_t new_offset)
|
||||||
{
|
{
|
||||||
xassert(buf->mmapped == NULL);
|
xassert(buf->public.mmapped == NULL);
|
||||||
xassert(buf->wl_buf == NULL);
|
xassert(buf->public.pix == NULL);
|
||||||
xassert(buf->pix == NULL);
|
xassert(buf->public.wl_buf == NULL);
|
||||||
xassert(buf->pool != NULL);
|
xassert(buf->pool != NULL);
|
||||||
|
|
||||||
const struct buffer_pool *pool = buf->pool;
|
const struct buffer_pool *pool = buf->pool;
|
||||||
|
|
||||||
void *mmapped = MAP_FAILED;
|
void *mmapped = MAP_FAILED;
|
||||||
struct wl_buffer *wl_buf = NULL;
|
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;
|
mmapped = (uint8_t *)pool->real_mmapped + new_offset;
|
||||||
|
|
||||||
wl_buf = wl_shm_pool_create_buffer(
|
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);
|
WL_SHM_FORMAT_ARGB8888);
|
||||||
|
|
||||||
if (wl_buf == NULL) {
|
if (wl_buf == NULL) {
|
||||||
|
|
@ -199,26 +223,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?) */
|
/* 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(
|
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) {
|
if (pix[i] == NULL) {
|
||||||
LOG_ERR("failed to create pixman image");
|
LOG_ERR("failed to create pixman image");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->mmapped = mmapped;
|
buf->public.mmapped = mmapped;
|
||||||
|
buf->public.wl_buf = wl_buf;
|
||||||
|
buf->public.pix = pix;
|
||||||
buf->offset = new_offset;
|
buf->offset = new_offset;
|
||||||
buf->wl_buf = wl_buf;
|
|
||||||
buf->pix = pix;
|
|
||||||
|
|
||||||
wl_buffer_add_listener(wl_buf, &buffer_listener, buf);
|
wl_buffer_add_listener(wl_buf, &buffer_listener, buf);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (pix != NULL) {
|
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)
|
if (pix[i] != NULL)
|
||||||
pixman_image_unref(pix[i]);
|
pixman_image_unref(pix[i]);
|
||||||
}
|
}
|
||||||
|
|
@ -235,7 +260,7 @@ destroy_all_purgeables(void)
|
||||||
{
|
{
|
||||||
/* Purge buffers marked for purging */
|
/* Purge buffers marked for purging */
|
||||||
tll_foreach(buffers, it) {
|
tll_foreach(buffers, it) {
|
||||||
if (it->item.locked)
|
if (it->item.public.locked)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!it->item.purge)
|
if (!it->item.purge)
|
||||||
|
|
@ -393,29 +418,31 @@ get_new_buffers(struct wl_shm *shm, size_t count,
|
||||||
/* Push to list of available buffers, but marked as 'busy' */
|
/* Push to list of available buffers, but marked as 'busy' */
|
||||||
tll_push_front(
|
tll_push_front(
|
||||||
buffers,
|
buffers,
|
||||||
((struct buffer){
|
((struct buffer_private){
|
||||||
|
.public = {
|
||||||
|
.width = info[i].width,
|
||||||
|
.height = info[i].height,
|
||||||
|
.stride = stride[i],
|
||||||
|
.size = sizes[i],
|
||||||
|
.pix_instances = pix_instances,
|
||||||
|
.age = 1234, /* Force a full repaint */
|
||||||
|
},
|
||||||
.cookie = info[i].cookie,
|
.cookie = info[i].cookie,
|
||||||
.width = info[i].width,
|
|
||||||
.height = info[i].height,
|
|
||||||
.stride = stride[i],
|
|
||||||
.busy = true,
|
.busy = true,
|
||||||
.purge = immediate_purge,
|
.purge = immediate_purge,
|
||||||
.size = sizes[i],
|
|
||||||
.pix_instances = pix_instances,
|
|
||||||
.pool = pool,
|
.pool = pool,
|
||||||
.scrollable = scrollable,
|
.scrollable = scrollable,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.age = 1234, /* Force a full repaint */
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
struct buffer *buf = &tll_front(buffers);
|
struct buffer_private *buf = &tll_front(buffers);
|
||||||
if (!instantiate_offset(shm, buf, offset))
|
if (!instantiate_offset(shm, buf, offset))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
pixman_region32_init(&buf->dirty);
|
pixman_region32_init(&buf->public.dirty);
|
||||||
pool->ref_count++;
|
pool->ref_count++;
|
||||||
offset += buf->size;
|
offset += buf->public.size;
|
||||||
bufs[i] = buf;
|
bufs[i] = &buf->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MEASURE_SHM_ALLOCS) && MEASURE_SHM_ALLOCS
|
#if defined(MEASURE_SHM_ALLOCS) && MEASURE_SHM_ALLOCS
|
||||||
|
|
@ -466,17 +493,17 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, unsigned long cookie,
|
||||||
{
|
{
|
||||||
destroy_all_purgeables();
|
destroy_all_purgeables();
|
||||||
|
|
||||||
struct buffer *cached = NULL;
|
struct buffer_private *cached = NULL;
|
||||||
tll_foreach(buffers, it) {
|
tll_foreach(buffers, it) {
|
||||||
if (it->item.width != width)
|
if (it->item.public.width != width)
|
||||||
continue;
|
continue;
|
||||||
if (it->item.height != height)
|
if (it->item.public.height != height)
|
||||||
continue;
|
continue;
|
||||||
if (it->item.cookie != cookie)
|
if (it->item.cookie != cookie)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (it->item.busy)
|
if (it->item.busy)
|
||||||
it->item.age++;
|
it->item.public.age++;
|
||||||
else
|
else
|
||||||
#if FORCED_DOUBLE_BUFFERING
|
#if FORCED_DOUBLE_BUFFERING
|
||||||
if (it->item.age == 0)
|
if (it->item.age == 0)
|
||||||
|
|
@ -489,16 +516,16 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, unsigned long cookie,
|
||||||
cookie, (void *)&it->item);
|
cookie, (void *)&it->item);
|
||||||
it->item.busy = true;
|
it->item.busy = true;
|
||||||
it->item.purge = false;
|
it->item.purge = false;
|
||||||
pixman_region32_clear(&it->item.dirty);
|
pixman_region32_clear(&it->item.public.dirty);
|
||||||
free(it->item.scroll_damage);
|
free(it->item.public.scroll_damage);
|
||||||
it->item.scroll_damage = NULL;
|
it->item.public.scroll_damage = NULL;
|
||||||
xassert(it->item.pix_instances == pix_instances);
|
xassert(it->item.public.pix_instances == pix_instances);
|
||||||
cached = &it->item;
|
cached = &it->item;
|
||||||
} else {
|
} else {
|
||||||
/* We have multiple buffers eligible for
|
/* We have multiple buffers eligible for
|
||||||
* re-use. Pick the “youngest” one, and mark the
|
* re-use. Pick the “youngest” one, and mark the
|
||||||
* other one for purging */
|
* other one for purging */
|
||||||
if (it->item.age < cached->age) {
|
if (it->item.public.age < cached->public.age) {
|
||||||
cached->purge = true;
|
cached->purge = true;
|
||||||
cached = &it->item;
|
cached = &it->item;
|
||||||
} else
|
} else
|
||||||
|
|
@ -508,7 +535,7 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, unsigned long cookie,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cached != NULL)
|
if (cached != NULL)
|
||||||
return cached;
|
return &cached->public;
|
||||||
|
|
||||||
/* Mark old buffers associated with this cookie for purging */
|
/* Mark old buffers associated with this cookie for purging */
|
||||||
tll_foreach(buffers, it) {
|
tll_foreach(buffers, it) {
|
||||||
|
|
@ -518,7 +545,7 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, unsigned long cookie,
|
||||||
if (it->item.busy)
|
if (it->item.busy)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (it->item.width == width && it->item.height == height)
|
if (it->item.public.width == width && it->item.public.height == height)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LOG_DBG("cookie=%lx: marking buffer %p for purging", cookie, (void *)&it->item);
|
LOG_DBG("cookie=%lx: marking buffer %p for purging", cookie, (void *)&it->item);
|
||||||
|
|
@ -532,9 +559,10 @@ shm_get_buffer(struct wl_shm *shm, int width, int height, unsigned long cookie,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
shm_can_scroll(const struct buffer *buf)
|
shm_can_scroll(const struct buffer *_buf)
|
||||||
{
|
{
|
||||||
#if __SIZEOF_POINTER__ == 8
|
#if __SIZEOF_POINTER__ == 8
|
||||||
|
const struct buffer_private *buf = (const struct buffer_private *)_buf;
|
||||||
return can_punch_hole && max_pool_size > 0 && buf->scrollable;
|
return can_punch_hole && max_pool_size > 0 && buf->scrollable;
|
||||||
#else
|
#else
|
||||||
/* Not enough virtual address space in 32-bit */
|
/* Not enough virtual address space in 32-bit */
|
||||||
|
|
@ -544,17 +572,20 @@ shm_can_scroll(const struct buffer *buf)
|
||||||
|
|
||||||
#if __SIZEOF_POINTER__ == 8 && defined(FALLOC_FL_PUNCH_HOLE)
|
#if __SIZEOF_POINTER__ == 8 && defined(FALLOC_FL_PUNCH_HOLE)
|
||||||
static bool
|
static bool
|
||||||
wrap_buffer(struct wl_shm *shm, struct buffer *buf, off_t new_offset)
|
wrap_buffer(struct wl_shm *shm, struct buffer_private *buf, off_t new_offset)
|
||||||
{
|
{
|
||||||
struct buffer_pool *pool = buf->pool;
|
struct buffer_pool *pool = buf->pool;
|
||||||
xassert(pool->ref_count == 1);
|
xassert(pool->ref_count == 1);
|
||||||
|
|
||||||
/* We don't allow overlapping offsets */
|
/* We don't allow overlapping offsets */
|
||||||
off_t UNUSED diff =
|
off_t UNUSED diff = new_offset < buf->offset
|
||||||
new_offset < buf->offset ? buf->offset - new_offset : new_offset - buf->offset;
|
? buf->offset - new_offset
|
||||||
xassert(diff > buf->size);
|
: new_offset - buf->offset;
|
||||||
|
xassert(diff > buf->public.size);
|
||||||
|
|
||||||
memcpy((uint8_t *)pool->real_mmapped + new_offset, buf->mmapped, buf->size);
|
memcpy((uint8_t *)pool->real_mmapped + new_offset,
|
||||||
|
buf->public.mmapped,
|
||||||
|
buf->public.size);
|
||||||
|
|
||||||
off_t trim_ofs, trim_len;
|
off_t trim_ofs, trim_len;
|
||||||
if (new_offset > buf->offset) {
|
if (new_offset > buf->offset) {
|
||||||
|
|
@ -563,7 +594,7 @@ wrap_buffer(struct wl_shm *shm, struct buffer *buf, off_t new_offset)
|
||||||
trim_len = new_offset;
|
trim_len = new_offset;
|
||||||
} else {
|
} else {
|
||||||
/* Trim everything *after* the new buffer location */
|
/* Trim everything *after* the new buffer location */
|
||||||
trim_ofs = new_offset + buf->size;
|
trim_ofs = new_offset + buf->public.size;
|
||||||
trim_len = pool->mmap_size - trim_ofs;
|
trim_len = pool->mmap_size - trim_ofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -577,12 +608,12 @@ wrap_buffer(struct wl_shm *shm, struct buffer *buf, off_t new_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-instantiate pixman+wl_buffer+raw pointersw */
|
/* Re-instantiate pixman+wl_buffer+raw pointersw */
|
||||||
buffer_destroy_dont_close(buf);
|
buffer_destroy_dont_close(&buf->public);
|
||||||
return instantiate_offset(shm, buf, new_offset);
|
return instantiate_offset(shm, buf, new_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
shm_scroll_forward(struct wl_shm *shm, struct buffer_private *buf, int rows,
|
||||||
int top_margin, int top_keep_rows,
|
int top_margin, int top_keep_rows,
|
||||||
int bottom_margin, int bottom_keep_rows)
|
int bottom_margin, int bottom_keep_rows)
|
||||||
{
|
{
|
||||||
|
|
@ -590,19 +621,19 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||||
|
|
||||||
xassert(can_punch_hole);
|
xassert(can_punch_hole);
|
||||||
xassert(buf->busy);
|
xassert(buf->busy);
|
||||||
xassert(buf->pix);
|
xassert(buf->public.pix != NULL);
|
||||||
xassert(buf->wl_buf);
|
xassert(buf->public.wl_buf != NULL);
|
||||||
xassert(pool != NULL);
|
xassert(pool != NULL);
|
||||||
xassert(pool->ref_count == 1);
|
xassert(pool->ref_count == 1);
|
||||||
xassert(pool->fd >= 0);
|
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->stride);
|
||||||
|
|
||||||
const off_t diff = rows * buf->stride;
|
const off_t diff = rows * buf->public.stride;
|
||||||
xassert(rows > 0);
|
xassert(rows > 0);
|
||||||
xassert(diff < buf->size);
|
xassert(diff < buf->public.size);
|
||||||
|
|
||||||
if (buf->offset + diff + buf->size > max_pool_size) {
|
if (buf->offset + diff + buf->public.size > max_pool_size) {
|
||||||
LOG_DBG("memfd offset wrap around");
|
LOG_DBG("memfd offset wrap around");
|
||||||
if (!wrap_buffer(shm, buf, 0))
|
if (!wrap_buffer(shm, buf, 0))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
@ -610,7 +641,7 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||||
|
|
||||||
off_t new_offset = buf->offset + diff;
|
off_t new_offset = buf->offset + diff;
|
||||||
xassert(new_offset > buf->offset);
|
xassert(new_offset > buf->offset);
|
||||||
xassert(new_offset + buf->size <= max_pool_size);
|
xassert(new_offset + buf->public.size <= max_pool_size);
|
||||||
|
|
||||||
#if TIME_SCROLL
|
#if TIME_SCROLL
|
||||||
struct timeval time1;
|
struct timeval time1;
|
||||||
|
|
@ -621,10 +652,13 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||||
|
|
||||||
if (top_keep_rows > 0) {
|
if (top_keep_rows > 0) {
|
||||||
/* Copy current 'top' region to its new location */
|
/* Copy current 'top' region to its new location */
|
||||||
|
const int stride = buf->public.stride;
|
||||||
|
uint8_t *base = buf->public.mmapped;
|
||||||
|
|
||||||
memmove(
|
memmove(
|
||||||
(uint8_t *)buf->mmapped + (top_margin + rows) * buf->stride,
|
base + (top_margin + rows) * stride,
|
||||||
(uint8_t *)buf->mmapped + (top_margin + 0) * buf->stride,
|
base + (top_margin + 0) * stride,
|
||||||
top_keep_rows * buf->stride);
|
top_keep_rows * stride);
|
||||||
|
|
||||||
#if TIME_SCROLL
|
#if TIME_SCROLL
|
||||||
gettimeofday(&time2, NULL);
|
gettimeofday(&time2, NULL);
|
||||||
|
|
@ -634,7 +668,7 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destroy old objects (they point to the old offset) */
|
/* 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 */
|
/* Free unused memory - everything up until the new offset */
|
||||||
const off_t trim_ofs = 0;
|
const off_t trim_ofs = 0;
|
||||||
|
|
@ -668,10 +702,14 @@ shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||||
|
|
||||||
if (ret && bottom_keep_rows > 0) {
|
if (ret && bottom_keep_rows > 0) {
|
||||||
/* Copy 'bottom' region to its new location */
|
/* Copy 'bottom' region to its new location */
|
||||||
|
const size_t size = buf->public.size;
|
||||||
|
const int stride = buf->public.stride;
|
||||||
|
uint8_t *base = buf->public.mmapped;
|
||||||
|
|
||||||
memmove(
|
memmove(
|
||||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + bottom_keep_rows) * buf->stride,
|
base + size - (bottom_margin + bottom_keep_rows) * stride,
|
||||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + rows + bottom_keep_rows) * buf->stride,
|
base + size - (bottom_margin + rows + bottom_keep_rows) * stride,
|
||||||
bottom_keep_rows * buf->stride);
|
bottom_keep_rows * stride);
|
||||||
|
|
||||||
#if TIME_SCROLL
|
#if TIME_SCROLL
|
||||||
struct timeval time5;
|
struct timeval time5;
|
||||||
|
|
@ -690,7 +728,7 @@ err:
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
shm_scroll_reverse(struct wl_shm *shm, struct buffer_private *buf, int rows,
|
||||||
int top_margin, int top_keep_rows,
|
int top_margin, int top_keep_rows,
|
||||||
int bottom_margin, int bottom_keep_rows)
|
int bottom_margin, int bottom_keep_rows)
|
||||||
{
|
{
|
||||||
|
|
@ -699,10 +737,10 @@ shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||||
struct buffer_pool *pool = buf->pool;
|
struct buffer_pool *pool = buf->pool;
|
||||||
xassert(pool->ref_count == 1);
|
xassert(pool->ref_count == 1);
|
||||||
|
|
||||||
const off_t diff = rows * buf->stride;
|
const off_t diff = rows * buf->public.stride;
|
||||||
if (diff > buf->offset) {
|
if (diff > buf->offset) {
|
||||||
LOG_DBG("memfd offset reverse wrap-around");
|
LOG_DBG("memfd offset reverse wrap-around");
|
||||||
if (!wrap_buffer(shm, buf, (max_pool_size - buf->size) & ~(page_size() - 1)))
|
if (!wrap_buffer(shm, buf, (max_pool_size - buf->public.size) & ~(page_size() - 1)))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -720,10 +758,14 @@ shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||||
|
|
||||||
if (bottom_keep_rows > 0) {
|
if (bottom_keep_rows > 0) {
|
||||||
/* Copy 'bottom' region to its new location */
|
/* Copy 'bottom' region to its new location */
|
||||||
|
const size_t size = buf->public.size;
|
||||||
|
const int stride = buf->public.stride;
|
||||||
|
uint8_t *base = buf->public.mmapped;
|
||||||
|
|
||||||
memmove(
|
memmove(
|
||||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + rows + bottom_keep_rows) * buf->stride,
|
base + size - (bottom_margin + rows + bottom_keep_rows) * stride,
|
||||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + bottom_keep_rows) * buf->stride,
|
base + size - (bottom_margin + bottom_keep_rows) * stride,
|
||||||
bottom_keep_rows * buf->stride);
|
bottom_keep_rows * stride);
|
||||||
|
|
||||||
#if TIME_SCROLL
|
#if TIME_SCROLL
|
||||||
gettimeofday(&time1, NULL);
|
gettimeofday(&time1, NULL);
|
||||||
|
|
@ -733,10 +775,10 @@ shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destroy old objects (they point to the old offset) */
|
/* 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 */
|
/* Free unused memory - everything after the relocated buffer */
|
||||||
const off_t trim_ofs = new_offset + buf->size;
|
const off_t trim_ofs = new_offset + buf->public.size;
|
||||||
const off_t trim_len = pool->mmap_size - trim_ofs;
|
const off_t trim_len = pool->mmap_size - trim_ofs;
|
||||||
|
|
||||||
if (fallocate(
|
if (fallocate(
|
||||||
|
|
@ -766,10 +808,13 @@ shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||||
|
|
||||||
if (ret && top_keep_rows > 0) {
|
if (ret && top_keep_rows > 0) {
|
||||||
/* Copy current 'top' region to its new location */
|
/* Copy current 'top' region to its new location */
|
||||||
|
const int stride = buf->public.stride;
|
||||||
|
uint8_t *base = buf->public.mmapped;
|
||||||
|
|
||||||
memmove(
|
memmove(
|
||||||
(uint8_t *)buf->mmapped + (top_margin + 0) * buf->stride,
|
base + (top_margin + 0) * stride,
|
||||||
(uint8_t *)buf->mmapped + (top_margin + rows) * buf->stride,
|
base + (top_margin + rows) * stride,
|
||||||
top_keep_rows * buf->stride);
|
top_keep_rows * stride);
|
||||||
|
|
||||||
#if TIME_SCROLL
|
#if TIME_SCROLL
|
||||||
struct timeval time4;
|
struct timeval time4;
|
||||||
|
|
@ -788,14 +833,16 @@ err:
|
||||||
#endif /* FALLOC_FL_PUNCH_HOLE */
|
#endif /* FALLOC_FL_PUNCH_HOLE */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows,
|
shm_scroll(struct wl_shm *shm, struct buffer *_buf, int rows,
|
||||||
int top_margin, int top_keep_rows,
|
int top_margin, int top_keep_rows,
|
||||||
int bottom_margin, int bottom_keep_rows)
|
int bottom_margin, int bottom_keep_rows)
|
||||||
{
|
{
|
||||||
#if __SIZEOF_POINTER__ == 8 && defined(FALLOC_FL_PUNCH_HOLE)
|
#if __SIZEOF_POINTER__ == 8 && defined(FALLOC_FL_PUNCH_HOLE)
|
||||||
if (!shm_can_scroll(buf))
|
if (!shm_can_scroll(_buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
struct buffer_private *buf = (struct buffer_private *)_buf;
|
||||||
|
|
||||||
xassert(rows != 0);
|
xassert(rows != 0);
|
||||||
return rows > 0
|
return rows > 0
|
||||||
? shm_scroll_forward(shm, buf, rows, top_margin, top_keep_rows, bottom_margin, bottom_keep_rows)
|
? shm_scroll_forward(shm, buf, rows, top_margin, top_keep_rows, bottom_margin, bottom_keep_rows)
|
||||||
|
|
@ -817,7 +864,7 @@ shm_purge(struct wl_shm *shm, unsigned long cookie)
|
||||||
|
|
||||||
if (it->item.busy) {
|
if (it->item.busy) {
|
||||||
LOG_WARN("deferring purge of 'busy' buffer (width=%d, height=%d)",
|
LOG_WARN("deferring purge of 'busy' buffer (width=%d, height=%d)",
|
||||||
it->item.width, it->item.height);
|
it->item.public.width, it->item.public.height);
|
||||||
it->item.purge = true;
|
it->item.purge = true;
|
||||||
} else {
|
} else {
|
||||||
buffer_destroy(&it->item);
|
buffer_destroy(&it->item);
|
||||||
|
|
|
||||||
21
shm.h
21
shm.h
|
|
@ -9,25 +9,13 @@
|
||||||
|
|
||||||
#include "terminal.h"
|
#include "terminal.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 buffer {
|
struct buffer {
|
||||||
unsigned long cookie;
|
bool locked; /* Caller owned, shm won’t destroy it */
|
||||||
|
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int stride;
|
int stride;
|
||||||
|
|
||||||
bool locked; /* Caller owned, shm won’t destroy it */
|
|
||||||
bool busy; /* Owned by compositor */
|
|
||||||
size_t size; /* Buffer size */
|
size_t size; /* Buffer size */
|
||||||
void *mmapped; /* Raw data (TODO: rename) */
|
void *mmapped; /* Raw data (TODO: rename) */
|
||||||
|
|
||||||
|
|
@ -35,13 +23,6 @@ struct buffer {
|
||||||
pixman_image_t **pix;
|
pixman_image_t **pix;
|
||||||
size_t pix_instances;
|
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;
|
unsigned age;
|
||||||
struct damage *scroll_damage;
|
struct damage *scroll_damage;
|
||||||
size_t scroll_damage_count;
|
size_t scroll_damage_count;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue