2019-06-12 20:08:54 +02:00
|
|
|
#include "shm.h"
|
|
|
|
|
|
|
|
|
|
#include <unistd.h>
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
#include <string.h>
|
2019-06-12 20:08:54 +02:00
|
|
|
#include <assert.h>
|
2020-02-25 19:07:23 +01:00
|
|
|
#include <errno.h>
|
2019-06-12 20:08:54 +02:00
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/mman.h>
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
#include <sys/time.h>
|
2020-03-10 18:01:01 +01:00
|
|
|
#include <linux/mman.h>
|
2019-06-12 20:08:54 +02:00
|
|
|
#include <linux/memfd.h>
|
2020-02-15 19:46:00 +01:00
|
|
|
#include <fcntl.h>
|
2019-06-12 20:08:54 +02:00
|
|
|
|
2019-08-16 20:40:32 +02:00
|
|
|
#include <pixman.h>
|
|
|
|
|
|
2019-12-01 14:03:24 +01:00
|
|
|
#include <fcft/stride.h>
|
2019-11-17 19:19:55 +01:00
|
|
|
#include <tllist.h>
|
|
|
|
|
|
2019-06-12 20:08:54 +02:00
|
|
|
#define LOG_MODULE "shm"
|
2019-11-02 00:33:37 +01:00
|
|
|
#define LOG_ENABLE_DBG 0
|
2019-06-12 20:08:54 +02:00
|
|
|
#include "log.h"
|
|
|
|
|
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
#define TIME_SCROLL 0
|
|
|
|
|
|
2019-06-12 20:08:54 +02:00
|
|
|
static tll(struct buffer) buffers;
|
|
|
|
|
|
2020-03-22 20:36:15 +01:00
|
|
|
static bool can_punch_hole = false;
|
|
|
|
|
static bool can_punch_hole_initialized = false;
|
|
|
|
|
|
2019-11-02 00:35:02 +01:00
|
|
|
static void
|
|
|
|
|
buffer_destroy(struct buffer *buf)
|
|
|
|
|
{
|
|
|
|
|
if (buf->pix != NULL)
|
|
|
|
|
pixman_image_unref(buf->pix);
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
if (buf->wl_buf != NULL)
|
|
|
|
|
wl_buffer_destroy(buf->wl_buf);
|
|
|
|
|
if (buf->real_mmapped != MAP_FAILED)
|
|
|
|
|
munmap(buf->real_mmapped, buf->mmap_size);
|
|
|
|
|
if (buf->fd >= 0)
|
|
|
|
|
close(buf->fd);
|
2019-11-02 00:35:02 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-12 20:08:54 +02:00
|
|
|
static void
|
|
|
|
|
buffer_release(void *data, struct wl_buffer *wl_buffer)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *buffer = data;
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
LOG_DBG("release: cookie=%lx (buf=%p)", buffer->cookie, buffer);
|
2019-06-12 20:08:54 +02:00
|
|
|
assert(buffer->wl_buf == wl_buffer);
|
|
|
|
|
assert(buffer->busy);
|
|
|
|
|
buffer->busy = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_buffer_listener buffer_listener = {
|
|
|
|
|
.release = &buffer_release,
|
|
|
|
|
};
|
|
|
|
|
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
static bool
|
|
|
|
|
instantiate_offset(struct wl_shm *shm, struct buffer *buf, size_t new_offset)
|
|
|
|
|
{
|
|
|
|
|
assert(buf->fd >= 0);
|
|
|
|
|
assert(buf->mmapped == NULL);
|
|
|
|
|
assert(buf->real_mmapped == NULL);
|
|
|
|
|
assert(buf->wl_buf == NULL);
|
|
|
|
|
assert(buf->pix == NULL);
|
|
|
|
|
|
|
|
|
|
static size_t page_size = 0;
|
|
|
|
|
if (page_size == 0) {
|
|
|
|
|
page_size = sysconf(_SC_PAGE_SIZE);
|
|
|
|
|
if (page_size < 0) {
|
|
|
|
|
LOG_ERRNO("failed to get page size");
|
|
|
|
|
page_size = 4096;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(page_size > 0);
|
|
|
|
|
|
|
|
|
|
void *real_mmapped = MAP_FAILED;
|
|
|
|
|
void *mmapped = MAP_FAILED;
|
|
|
|
|
struct wl_shm_pool *pool = NULL;
|
|
|
|
|
struct wl_buffer *wl_buf = NULL;
|
|
|
|
|
pixman_image_t *pix = NULL;
|
|
|
|
|
|
|
|
|
|
/* mmap offset must be page aligned */
|
|
|
|
|
size_t aligned_offset = new_offset & ~(page_size - 1);
|
|
|
|
|
size_t page_offset = new_offset & (page_size - 1);
|
|
|
|
|
size_t mmap_size = buf->size + page_offset;
|
|
|
|
|
|
|
|
|
|
assert(aligned_offset <= new_offset);
|
|
|
|
|
assert(mmap_size >= buf->size);
|
|
|
|
|
|
|
|
|
|
LOG_DBG("size=%zx, offset=%zx, size-aligned=%zx, offset-aligned=%zx",
|
|
|
|
|
buf->size, buf->offset, mmap_size, aligned_offset);
|
|
|
|
|
|
|
|
|
|
real_mmapped = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_UNINITIALIZED, buf->fd, aligned_offset);
|
|
|
|
|
if (real_mmapped == MAP_FAILED) {
|
|
|
|
|
LOG_ERRNO("failed to mmap SHM backing memory file");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
mmapped = real_mmapped + page_offset;
|
|
|
|
|
|
|
|
|
|
pool = wl_shm_create_pool(shm, buf->fd, new_offset + buf->size);
|
|
|
|
|
if (pool == NULL) {
|
|
|
|
|
LOG_ERR("failed to create SHM pool");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_buf = wl_shm_pool_create_buffer(
|
|
|
|
|
pool, new_offset, buf->width, buf->height, buf->stride, WL_SHM_FORMAT_ARGB8888);
|
|
|
|
|
if (wl_buf == NULL) {
|
|
|
|
|
LOG_ERR("failed to create SHM buffer");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We use the entire pool for our single buffer */
|
|
|
|
|
wl_shm_pool_destroy(pool); pool = NULL;
|
|
|
|
|
|
|
|
|
|
/* One pixman image for each worker thread (do we really need multiple?) */
|
|
|
|
|
pix = pixman_image_create_bits_no_clear(
|
|
|
|
|
PIXMAN_a8r8g8b8, buf->width, buf->height, (uint32_t *)mmapped, buf->stride);
|
|
|
|
|
if (pix == NULL) {
|
|
|
|
|
LOG_ERR("failed to create pixman image");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf->offset = new_offset;
|
|
|
|
|
buf->real_mmapped = real_mmapped;
|
|
|
|
|
buf->mmapped = mmapped;
|
|
|
|
|
buf->mmap_size = mmap_size;
|
|
|
|
|
buf->wl_buf = wl_buf;
|
|
|
|
|
buf->pix = pix;
|
|
|
|
|
|
|
|
|
|
wl_buffer_add_listener(wl_buf, &buffer_listener, buf);
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
if (pix != NULL)
|
|
|
|
|
pixman_image_unref(pix);
|
|
|
|
|
if (wl_buf != NULL)
|
|
|
|
|
wl_buffer_destroy(wl_buf);
|
|
|
|
|
if (pool != NULL)
|
|
|
|
|
wl_shm_pool_destroy(pool);
|
|
|
|
|
if (real_mmapped != MAP_FAILED)
|
|
|
|
|
munmap(real_mmapped, mmap_size);
|
|
|
|
|
|
|
|
|
|
abort();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-12 20:08:54 +02:00
|
|
|
struct buffer *
|
2019-11-02 00:33:37 +01:00
|
|
|
shm_get_buffer(struct wl_shm *shm, int width, int height, unsigned long cookie)
|
2019-06-12 20:08:54 +02:00
|
|
|
{
|
2019-11-02 01:27:05 +01:00
|
|
|
/* Purge buffers marked for purging */
|
|
|
|
|
tll_foreach(buffers, it) {
|
|
|
|
|
if (it->item.cookie != cookie)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!it->item.purge)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
assert(!it->item.busy);
|
|
|
|
|
|
2020-03-18 16:41:38 +01:00
|
|
|
LOG_DBG("cookie=%lx: purging buffer %p (width=%d, height=%d): %zu KB",
|
|
|
|
|
cookie, &it->item, it->item.width, it->item.height,
|
|
|
|
|
it->item.size / 1024);
|
2019-11-02 01:27:05 +01:00
|
|
|
|
|
|
|
|
buffer_destroy(&it->item);
|
|
|
|
|
tll_remove(buffers, it);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-02 01:31:48 +01:00
|
|
|
tll_foreach(buffers, it) {
|
|
|
|
|
if (it->item.width != width)
|
|
|
|
|
continue;
|
|
|
|
|
if (it->item.height != height)
|
|
|
|
|
continue;
|
|
|
|
|
if (it->item.cookie != cookie)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!it->item.busy) {
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
LOG_DBG("cookie=%lx: re-using buffer from cache (buf=%p)",
|
|
|
|
|
cookie, &it->item);
|
2019-11-02 01:31:48 +01:00
|
|
|
it->item.busy = true;
|
|
|
|
|
it->item.purge = false;
|
|
|
|
|
return &it->item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-02 00:35:02 +01:00
|
|
|
/* Purge old buffers associated with this cookie */
|
|
|
|
|
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;
|
|
|
|
|
|
2019-11-02 01:27:05 +01:00
|
|
|
LOG_DBG("cookie=%lx: marking buffer %p for purging", cookie, &it->item);
|
|
|
|
|
it->item.purge = true;
|
2019-11-02 00:35:02 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-12 20:08:54 +02:00
|
|
|
/*
|
|
|
|
|
* No existing buffer available. Create a new one by:
|
|
|
|
|
*
|
|
|
|
|
* 1. open a memory backed "file" with memfd_create()
|
2019-08-16 22:11:22 +02:00
|
|
|
* 2. mmap() the memory file, to be used by the pixman image
|
2019-06-12 20:08:54 +02:00
|
|
|
* 3. create a wayland shm buffer for the same memory file
|
|
|
|
|
*
|
2019-08-16 22:11:22 +02:00
|
|
|
* The pixman image and the wayland buffer are now sharing memory.
|
2019-06-12 20:08:54 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int pool_fd = -1;
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
const int stride = stride_for_format_and_width(PIXMAN_a8r8g8b8, width);
|
|
|
|
|
const size_t size = stride * height;
|
2019-06-12 20:08:54 +02:00
|
|
|
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
LOG_DBG("cookie=%lx: allocating new buffer: %zu KB", cookie, size / 1024);
|
2019-06-12 20:08:54 +02:00
|
|
|
|
|
|
|
|
/* Backing memory for SHM */
|
2019-11-02 00:05:07 +01:00
|
|
|
pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC);
|
2019-06-12 20:08:54 +02:00
|
|
|
if (pool_fd == -1) {
|
|
|
|
|
LOG_ERRNO("failed to create SHM backing memory file");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
if (ftruncate(pool_fd, size) == -1) {
|
|
|
|
|
LOG_ERRNO("failed to truncate SHM pool");
|
2019-06-12 20:08:54 +02:00
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-22 20:36:15 +01:00
|
|
|
if (!can_punch_hole_initialized) {
|
|
|
|
|
can_punch_hole_initialized = true;
|
|
|
|
|
can_punch_hole = fallocate(
|
|
|
|
|
pool_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1) == 0;
|
2020-03-22 21:04:00 +01:00
|
|
|
|
|
|
|
|
if (!can_punch_hole) {
|
|
|
|
|
LOG_WARN(
|
|
|
|
|
"fallocate(FALLOC_FL_PUNCH_HOLE) not "
|
|
|
|
|
"supported (%s): expect lower performance", strerror(errno));
|
|
|
|
|
}
|
2020-03-22 20:36:15 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-12 20:08:54 +02:00
|
|
|
/* Push to list of available buffers, but marked as 'busy' */
|
|
|
|
|
tll_push_back(
|
|
|
|
|
buffers,
|
|
|
|
|
((struct buffer){
|
2019-11-02 00:33:37 +01:00
|
|
|
.cookie = cookie,
|
2019-06-12 20:08:54 +02:00
|
|
|
.width = width,
|
|
|
|
|
.height = height,
|
2019-08-16 20:40:32 +02:00
|
|
|
.stride = stride,
|
2019-06-12 20:08:54 +02:00
|
|
|
.busy = true,
|
|
|
|
|
.size = size,
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
.fd = pool_fd,
|
|
|
|
|
.mmap_size = size,
|
|
|
|
|
.offset = 0}
|
2019-06-12 20:08:54 +02:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
struct buffer *ret = &tll_back(buffers);
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
if (!instantiate_offset(shm, ret, 0))
|
|
|
|
|
goto err;
|
2019-06-12 20:08:54 +02:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
if (pool_fd != -1)
|
|
|
|
|
close(pool_fd);
|
|
|
|
|
|
2020-03-10 18:02:10 +01:00
|
|
|
/* We don't handle this */
|
|
|
|
|
abort();
|
2019-06-12 20:08:54 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
shm_fini(void)
|
|
|
|
|
{
|
|
|
|
|
tll_foreach(buffers, it) {
|
2019-11-02 00:35:02 +01:00
|
|
|
buffer_destroy(&it->item);
|
2019-06-12 20:08:54 +02:00
|
|
|
tll_remove(buffers, it);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-02 00:49:00 +01:00
|
|
|
|
2020-03-23 19:31:05 +01:00
|
|
|
bool
|
|
|
|
|
shm_can_scroll(void)
|
|
|
|
|
{
|
|
|
|
|
return can_punch_hole;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-23 21:14:51 +01:00
|
|
|
static bool
|
|
|
|
|
shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
|
|
|
|
int top_margin, int top_keep_rows,
|
|
|
|
|
int bottom_margin, int bottom_keep_rows)
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
{
|
2020-03-23 19:31:05 +01:00
|
|
|
assert(can_punch_hole);
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
assert(buf->busy);
|
|
|
|
|
assert(buf->pix);
|
|
|
|
|
assert(buf->wl_buf);
|
|
|
|
|
assert(buf->real_mmapped);
|
|
|
|
|
assert(buf->fd >= 0);
|
|
|
|
|
|
2020-03-22 20:36:15 +01:00
|
|
|
if (!can_punch_hole)
|
|
|
|
|
return false;
|
|
|
|
|
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
LOG_DBG("scrolling %d rows (%d bytes)", rows, rows * buf->stride);
|
|
|
|
|
|
|
|
|
|
assert(rows > 0);
|
|
|
|
|
assert(rows * buf->stride < buf->size);
|
|
|
|
|
const size_t new_offset = buf->offset + rows * buf->stride;
|
|
|
|
|
|
|
|
|
|
#if TIME_SCROLL
|
|
|
|
|
struct timeval time0;
|
|
|
|
|
gettimeofday(&time0, NULL);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Increase file size */
|
|
|
|
|
if (ftruncate(buf->fd, new_offset + buf->size) < 0) {
|
|
|
|
|
LOG_ERRNO("failed increase memfd size from %zu -> %zu",
|
|
|
|
|
buf->offset + buf->size, new_offset + buf->size);
|
2020-03-22 20:32:11 +01:00
|
|
|
return false;
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if TIME_SCROLL
|
|
|
|
|
struct timeval time1;
|
|
|
|
|
gettimeofday(&time1, NULL);
|
|
|
|
|
|
|
|
|
|
struct timeval tot;
|
|
|
|
|
timersub(&time1, &time0, &tot);
|
2020-03-23 20:45:27 +01:00
|
|
|
LOG_INFO("ftruncate: %lds %ldus", tot.tv_sec, tot.tv_usec);
|
|
|
|
|
|
|
|
|
|
struct timeval time2 = time1;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (top_keep_rows > 0) {
|
|
|
|
|
/* Copy current 'top' region to its new location */
|
|
|
|
|
memmove(
|
|
|
|
|
(uint8_t *)buf->mmapped + (top_margin + rows) * buf->stride,
|
|
|
|
|
(uint8_t *)buf->mmapped + (top_margin + 0) * buf->stride,
|
|
|
|
|
top_keep_rows * buf->stride);
|
|
|
|
|
|
|
|
|
|
#if TIME_SCROLL
|
|
|
|
|
gettimeofday(&time2, NULL);
|
|
|
|
|
timersub(&time2, &time1, &tot);
|
|
|
|
|
LOG_INFO("memmove (top region): %lds %ldus", tot.tv_sec, tot.tv_usec);
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
#endif
|
2020-03-23 20:45:27 +01:00
|
|
|
}
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
|
|
|
|
|
/* Destroy old objects (they point to the old offset) */
|
|
|
|
|
pixman_image_unref(buf->pix);
|
|
|
|
|
wl_buffer_destroy(buf->wl_buf);
|
|
|
|
|
munmap(buf->real_mmapped, buf->mmap_size);
|
|
|
|
|
|
|
|
|
|
buf->pix = NULL;
|
|
|
|
|
buf->wl_buf = NULL;
|
|
|
|
|
buf->real_mmapped = buf->mmapped = NULL;
|
|
|
|
|
|
|
|
|
|
/* Free unused memory */
|
|
|
|
|
if (fallocate(buf->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, new_offset) < 0) {
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if TIME_SCROLL
|
2020-03-23 20:45:27 +01:00
|
|
|
struct timeval time3;
|
|
|
|
|
gettimeofday(&time3, NULL);
|
|
|
|
|
timersub(&time3, &time2, &tot);
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
LOG_INFO("PUNCH HOLE: %lds %ldus", tot.tv_sec, tot.tv_usec);
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-03-23 20:45:27 +01:00
|
|
|
bool ret = instantiate_offset(shm, buf, new_offset);
|
|
|
|
|
|
|
|
|
|
if (ret && bottom_keep_rows > 0) {
|
|
|
|
|
/* Copy 'bottom' region to its new location */
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
#if TIME_SCROLL
|
|
|
|
|
struct timeval time4;
|
|
|
|
|
gettimeofday(&time4, NULL);
|
|
|
|
|
|
|
|
|
|
timersub(&time4, &time3, &tot);
|
|
|
|
|
LOG_INFO("memmove (bottom region): %lds %ldus", tot.tv_sec, tot.tv_usec);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
shm: new function, shm_scroll()
This function "scrolls" the buffer by the specified number of (pixel)
rows.
The idea is move the image offset by re-sizing the underlying memfd
object. I.e. to scroll forward, increase the size of the memfd file,
and move the pixman image offset forward (and the Wayland SHM buffer
as well).
Only increasing the file size would, obviously, cause the memfd file
to grow indefinitely. To deal with this, we "punch" a whole from the
beginning of the file to the new offset. This frees the associated
memory.
Thus, while we have a memfd file whose size is (as seen by
e.g. fstat()) is ever growing, the actual file size is always the
original buffer size.
Some notes:
* FALLOC_FL_PUNCH_HOLE can be quite slow when the number of used pages
to drop is large.
* all normal fallocate() usages have been replaced with ftruncate(),
as this is *much* faster. fallocate() guarantees subsequent writes
wont fail. I.e. it actually reserves (disk) space. While it doesn't
allocate on-disk blocks for on-disk files, it *does* zero-initialize
the in-memory blocks. And this is slow. ftruncate() doesn't do this.
TODO: implement reverse scrolling (i.e. a negative row count).
2020-03-22 20:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-23 21:14:51 +01:00
|
|
|
static bool
|
|
|
|
|
shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
|
|
|
|
int top_margin, int top_keep_rows,
|
|
|
|
|
int bottom_margin, int bottom_keep_rows)
|
|
|
|
|
{
|
|
|
|
|
assert(rows > 0);
|
|
|
|
|
|
|
|
|
|
size_t diff = rows * buf->stride;
|
|
|
|
|
if (diff > buf->offset)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const size_t new_offset = buf->offset - rows * buf->stride;
|
|
|
|
|
assert(new_offset < buf->offset);
|
|
|
|
|
|
|
|
|
|
#if TIME_SCROLL
|
|
|
|
|
struct timeval time0;
|
|
|
|
|
gettimeofday(&time0, NULL);
|
|
|
|
|
|
|
|
|
|
struct timeval tot;
|
|
|
|
|
struct timeval time1 = time0;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (bottom_keep_rows > 0) {
|
|
|
|
|
/* Copy 'bottom' region to its new location */
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
#if TIME_SCROLL
|
|
|
|
|
gettimeofday(&time1, NULL);
|
|
|
|
|
timersub(&time1, &time0, &tot);
|
|
|
|
|
LOG_INFO("memmove (bottom region): %lds %ldus", tot.tv_sec, tot.tv_usec);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Destroy old objects (they point to the old offset) */
|
|
|
|
|
pixman_image_unref(buf->pix);
|
|
|
|
|
wl_buffer_destroy(buf->wl_buf);
|
|
|
|
|
munmap(buf->real_mmapped, buf->mmap_size);
|
|
|
|
|
|
|
|
|
|
buf->pix = NULL;
|
|
|
|
|
buf->wl_buf = NULL;
|
|
|
|
|
buf->real_mmapped = buf->mmapped = NULL;
|
|
|
|
|
|
|
|
|
|
if (ftruncate(buf->fd, new_offset + buf->size) < 0) {
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if TIME_SCROLL
|
|
|
|
|
struct timeval time2;
|
|
|
|
|
gettimeofday(&time2, NULL);
|
|
|
|
|
timersub(&time2, &time1, &tot);
|
|
|
|
|
LOG_INFO("ftruncate: %lds %ldus", tot.tv_sec, tot.tv_usec);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool ret = instantiate_offset(shm, buf, new_offset);
|
|
|
|
|
|
|
|
|
|
if (ret && top_keep_rows > 0) {
|
|
|
|
|
/* Copy current 'top' region to its new location */
|
|
|
|
|
memmove(
|
|
|
|
|
(uint8_t *)buf->mmapped + (top_margin + 0) * buf->stride,
|
|
|
|
|
(uint8_t *)buf->mmapped + (top_margin + rows) * buf->stride,
|
|
|
|
|
top_keep_rows * buf->stride);
|
|
|
|
|
|
|
|
|
|
#if TIME_SCROLL
|
|
|
|
|
struct timeval time3;
|
|
|
|
|
gettimeofday(&time3, NULL);
|
|
|
|
|
timersub(&time3, &time2, &tot);
|
|
|
|
|
LOG_INFO("memmove (top region): %lds %ldus", tot.tv_sec, tot.tv_usec);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows,
|
|
|
|
|
int top_margin, int top_keep_rows,
|
|
|
|
|
int bottom_margin, int bottom_keep_rows)
|
|
|
|
|
{
|
|
|
|
|
assert(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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2019-11-02 00:49:00 +01:00
|
|
|
shm_purge(struct wl_shm *shm, unsigned long cookie)
|
|
|
|
|
{
|
|
|
|
|
LOG_DBG("cookie=%lx: purging all buffers", cookie);
|
|
|
|
|
|
|
|
|
|
/* Purge old buffers associated with this cookie */
|
|
|
|
|
tll_foreach(buffers, it) {
|
|
|
|
|
if (it->item.cookie != cookie)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
assert(!it->item.busy);
|
|
|
|
|
|
|
|
|
|
buffer_destroy(&it->item);
|
|
|
|
|
tll_remove(buffers, it);
|
|
|
|
|
}
|
|
|
|
|
}
|