Commit graph

66 commits

Author SHA1 Message Date
Daniel Eklöf
a486851bdd
shm: auto-purge when we have multiple buffers eligible for re-use
It may happen that we end up with multiple non-busy, same-sized
buffers for the same cookie (context), and thus eligible for re-use.

Before this patch, we would keep all those buffers around. This is
completely unnecessary. Under normal circumstances, we’ll either be
re-using a single buffer, or swap between two. In the second case, the
“other” buffer is always busy, and thus not eligible for re-use.

So, if we _do_ detect multiple, re-usable buffers, pick the one with
the lowest “age” (increasing the chance of applying damage tracking,
instead of re-drawing everything), and mark the other one for purging.
2021-07-15 19:19:31 +02:00
Daniel Eklöf
7533684d8f
shm: add shm_get_many() - allows buffers to share a single pool
shm_get_many() always returns new buffers (i.e. never old, cached
ones). The newly allocated buffers are also marked for immediate
purging, meaning they’ll be destroyed on the next call to either
shm_get_buffer(), or shm_get_many().

Furthermore, we add a new attribute, ‘locked’, to the buffer
struct. When auto purging buffers, look at this instead of comparing
cookies.

Buffer consumers are expected to set ‘locked’ while they hold a
reference to it, and don’t want it destroyed behind their back.
2021-07-15 18:39:23 +02:00
Daniel Eklöf
22651ed221
shm: reset buffer pool FD when we close it
This fixes an issue where we ended up "double closing" buffer FDs.

In many cases (especially on compositors with SSDs) this was pretty
rare. And even when it did happen, the FD was normally unused, and
thus nothing bad happened.

However, by quickly resizing the window while using CSDs, it was
fairly easy to trigger this. We sometimes ended up closing the
TIOCSWINCH timer FD while thinking it was a buffer FD, but most of the
times we just ended up closing _another_ buffer’s pool FD, leading to
an immediate disconnect by the compositor.
2021-07-14 20:51:42 +02:00
Daniel Eklöf
107cbb1015
shm: close pool FD if buffer doesn’t support SHM scrolling
The only reason to keep the pool FD open is if we’re going to SHM
scroll the buffer; we need the FD for fallocate(FALLOC_FL_PUNCH_HOLE).

In all other cases, there’s absolutely no need to keep the FD
open. Thus, close it as soon as we’ve instantiated the buffer. This
frees up FDs, and help keep foot from FD ulimit.
2021-07-11 10:22:47 +02:00
Daniel Eklöf
945a346596
shm: clear buffer’s dirty region before returning a cached buffer
A non-busy buffer should always have an empty dirty region
2021-05-12 20:06:15 +02:00
Daniel Eklöf
37bbf44f6d
shm: set ‘age’ in newly allocated buffers to something large
This ensures we don’t try to do a partial update of fresh buffer.
2021-05-12 20:06:15 +02:00
Daniel Eklöf
0433ba8477
shm: free scroll damage before returning cached buffer 2021-05-12 20:06:15 +02:00
Daniel Eklöf
34becf0df0
render: code cleanup, log double buffering time
* Break out cursor cell dirtying to separate functions
* Break out handling of double buffering
* Handle buffers with age > 1 (we’re swapping between more than 2
  buffers)
* Detect full screen repaints, and skip re-applying old frame’s damage
* Use an allocated array insted of a tll list for old frame’s scroll damage
* When logging frame rendering time, including the amount used for
  double buffering.
2021-05-12 20:06:15 +02:00
Daniel Eklöf
434c9c3a34
shm: add damage tracking to buffer 2021-05-12 20:06:15 +02:00
Daniel Eklöf
c8b342ae51
shm: track busy buffers’ age, and add compile-time option to force double buffering
By default, age all matching buffers that are busy (i.e. in use by the
compositor).

This allows us to detect whether we can apply the current frame’s
damage directly, or if we need to prepare the buffer first (e.g. copy
old buffer, or re-apply last frame’s damage etc).
2021-05-12 20:06:04 +02:00
Daniel Eklöf
0d07ee03f5
shm: don’t check for __i386__ and __x86_64__ - there are other architectures out there
Instead, check for __SIZEOF_POINTER__ == 8, since what we’re really
interested in is whether we have enough virtual address space or not.
2021-01-23 09:52:42 +01:00
Jan Beich
db9dc7e908
shm: unbreak build without memfd_create
New FreeBSD versions have memfd_create but other BSDs don't.

pgo/pgo.c:260:22: error: implicit declaration of function 'memfd_create' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
        int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC);
                     ^
pgo/pgo.c:260:52: error: use of undeclared identifier 'MFD_CLOEXEC'
        int mem_fd = memfd_create("foot-pgo-ptmx", MFD_CLOEXEC);
                                                   ^
shm.c:13:10: fatal error: 'linux/mman.h' file not found
 #include <linux/mman.h>
          ^~~~~~~~~~~~~~
shm.c:277:15: error: implicit declaration of function 'memfd_create' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
              ^
shm.c:277:60: error: use of undeclared identifier 'MFD_CLOEXEC'
    pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
                                                           ^
shm.c:277:74: error: use of undeclared identifier 'MFD_ALLOW_SEALING'
    pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
                                                                         ^
shm.c:339:15: error: use of undeclared identifier 'F_SEAL_GROW'
              F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0)
              ^
shm.c:339:29: error: use of undeclared identifier 'F_SEAL_SHRINK'
              F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0)
                            ^
shm.c:339:71: error: use of undeclared identifier 'F_SEAL_SEAL'
              F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0)
                                                                      ^
shm.c:338:24: error: use of undeclared identifier 'F_ADD_SEALS'
    if (fcntl(pool_fd, F_ADD_SEALS,
                       ^
2021-01-23 09:52:40 +01:00
Jan Beich
013e3c2d80
shm: disable fallocate optimization if not supported
shm.c:301:26: error: implicit declaration of function 'fallocate' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
        can_punch_hole = fallocate(
                         ^
shm.c:302:22: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
            pool_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1) == 0;
                     ^
shm.c:302:45: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
            pool_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1) == 0;
                                            ^
shm.c:432:9: error: implicit declaration of function 'fallocate' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    if (fallocate(
        ^
shm.c:434:13: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
            ^
shm.c:434:36: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                   ^
shm.c:501:9: error: implicit declaration of function 'fallocate' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    if (fallocate(
        ^
shm.c:503:13: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
            ^
shm.c:503:36: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                   ^
shm.c:597:9: error: implicit declaration of function 'fallocate' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    if (fallocate(
        ^
shm.c:599:13: error: use of undeclared identifier 'FALLOC_FL_PUNCH_HOLE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
            ^
shm.c:599:36: error: use of undeclared identifier 'FALLOC_FL_KEEP_SIZE'
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                   ^
2021-01-23 09:52:40 +01:00
Jan Beich
e35e98ea94
shm: silence -Wunused-function on i386
shm.c:134:1: error: unused function 'page_size' [-Werror,-Wunused-function]
page_size(void)
^
2021-01-23 09:52:40 +01:00
Craig Barnes
e56136ce11 debug: rename assert() to xassert(), to avoid clashing with <assert.h> 2021-01-16 20:16:00 +00:00
Craig Barnes
22f25a9e4f Print stack trace on assert() failure or when calling fatal_error()
Note: this uses the __sanitizer_print_stack_trace() function from the
AddressSanitizer runtime, so it only works when AddressSanitizer is
in use.
2021-01-16 19:56:33 +00:00
Daniel Eklöf
85cdc66ff2
shm: fix badly indented function return type 2020-12-07 20:44:11 +01:00
Daniel Eklöf
9e0fcb1c27
shm: MAP_UNINITIALIZED is a linux only mmap flag 2020-10-10 11:29:47 +02:00
Craig Barnes
f3acfea815 fix some buggy comparisons relating to signed/unsigned types 2020-08-25 19:39:17 +01:00
Daniel Eklöf
e32c0d9bf6
Cast printf formatter %p arguments to void* 2020-08-23 10:07:08 +02:00
Daniel Eklöf
732e181b1d
shm: don't even try to punch a memfd hole in 32-bit
This ensures we don't issue a warning if we fail, something that will
just confuse users, as SHM scrolling is disabled in 32-bit anyway.
2020-08-11 17:22:12 +02:00
Craig Barnes
7a77958ba2 Convert most dynamic allocations to use functions from xmalloc.h 2020-08-08 20:37:57 +01:00
Craig Barnes
7eb70a453b Replace GCC "unused" and "format" attributes with portable macros 2020-08-07 20:42:34 +01:00
Daniel Eklöf
8b320ed296
render: re-write cell clipping to use pixman destination clipping
Our home rolled clip-to-cell code was, obviously, not correct.

The original problem was that we couldn't use pixman clipping since we
have multiple threads writing to the same pixman image, and thus there
would be races between the threads setting clipping.

The fix is actually simple - just instantiate one pixman
image (referencing the same backing image data) for each rendering
thread.
2020-06-04 15:39:19 +02:00
Daniel Eklöf
4f145bed33
shm: #ifdef conditional code to measure total size of SHM allocations 2020-04-18 12:24:40 +02:00
Daniel Eklöf
a208104743
shm: memfd seal failures are not fatal errors 2020-04-03 20:14:53 +02:00
Daniel Eklöf
c4aaba6299
conf: max-shm-pool-size-mb=0 now disables SHM scrolling 2020-03-26 18:04:30 +01:00
Daniel Eklöf
0baa249d8b
shm: make max pool size user configurable (via a 'tweak' setting) 2020-03-25 20:48:02 +01:00
Daniel Eklöf
e9f1638750
shm: handle ftruncate failure 2020-03-25 18:32:41 +01:00
Daniel Eklöf
dc42cc1d19
shm: seal the memfd
This both prevents accidental resizing of the memfd, and allows the
Wayland server to optimze reads from the buffer - it no longer has to
setup SIGBUS handlers.
2020-03-25 18:30:21 +01:00
Daniel Eklöf
03319560f5
shm: scroll: keep shm pool around, and fix its size at max allowed
This lessens the burden on (primarily) the compositor, since we no
longer tear down and re-create the SHM pool when scrolling.

The SHM pool is setup once, and its size is fixed at the maximum
allowed (512MB for now, 2GB would be possible).

This also allows us to mmap() the memfd once. The exposed raw pointer
is simply an offset from the memfd mmapping.

Note that this means e.g. rouge rendering code will be able to write
outside the buffer.

Finally, only do this if the caller explicitly wants to enable
scrolling. The memfd of other buffers are sized to the requested size.
2020-03-25 18:26:58 +01:00
Daniel Eklöf
5c5f1d096c
shm: scroll: implement offset wrap-around
* Impose a maximum memfd size limit. In theory, this can be
  2GB (wl_shm_create_pool() is the limiting factor - its size argument
  is an int32_t). For now, use 256MB.

  This is mainly to reduce the amount of virtual address space used by
  the compositor, which keeps at least one mmapping (of the entire
  memfd) around. One mmapping *per terminal window* that is.

  Given that we have 128TB with 48-bit virtual addresses, we could
  probably bump this to 2GB without any issues. However, 256MB should
  be enough.

  TODO: check how much we typically move the offset when scrolling in
  a fullscreen window on a 4K monitor. 256MB may turn out to be too
  small.

  On 32-bit shm_scroll() is completely disabled. There simply isn't
  enough address space.

* Wrapping is done by moving the offset to "the other end" of the
  memfd, and copying the buffer contents to the new, wrapped offset.

  The "normal" scrolling code then does the actual scrolling. This
  means we'll re-instantiate all objects twice when wrapping.
2020-03-24 17:46:48 +01:00
Daniel Eklöf
759fd572e9
shm: shm_scroll(): initial implementation of reverse scrolling
Implemented by truncating the file size and moving the offset
backwards. This means we can only reverse scroll when we've previously
scrolled forward.

TODO: figure out if we can somehow do fast reverse scrolling even
though offset is 0 (or well, less than required for scrolling).
2020-03-23 21:14:51 +01:00
Daniel Eklöf
0de3701984
shm: scroll: move top/bottom region handling from renderer into shm
This allows us to restore the regions without copying the contents to
temporary memory.
2020-03-23 20:45:27 +01:00
Daniel Eklöf
5ffee08748
shm: add shm_can_scroll() 2020-03-23 19:31:05 +01:00
Daniel Eklöf
795b0e7ea1
shm: print performance warning when FALLOC_FL_PUNCH_HOLE isn't supported 2020-03-22 21:05:05 +01:00
Daniel Eklöf
7404ace40c
shm: verify the system supports FALLOC_FL_PUNCH_HOLE 2020-03-22 21:05:00 +01:00
Daniel Eklöf
3b9be09b06
shm: scroll: no need to instantiate a new buffer when ftruncate() fails 2020-03-22 20:34:58 +01:00
Daniel Eklöf
1224807f50
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
Daniel Eklöf
7b610e018b
shm: log size of purged buffer 2020-03-18 16:41:38 +01:00
Daniel Eklöf
8a6cfb738b
shm: we don't really handle SHM failures, so just abort() 2020-03-10 18:06:10 +01:00
Daniel Eklöf
cf5da1039f
shm: mmap returns MAP_FAILED, so use that as guard value 2020-03-10 18:06:10 +01:00
Daniel Eklöf
867dc836ab
shm: set pool_fd=1 after closing it, to avoid double-closing on error 2020-03-10 18:06:10 +01:00
Daniel Eklöf
7efe2c6c97
shm: try to mmap with MAP_UNINITIALIZED
This flag is expected to be ignored on most systems, but can't hurt to
try.
2020-03-10 18:06:10 +01:00
Daniel Eklöf
1581143b0b
shm: log errno error message too 2020-03-10 18:06:09 +01:00
Daniel Eklöf
9d834bb43d
shm: log 'size' when failing to fallocate() 2020-03-01 12:19:28 +01:00
Daniel Eklöf
3f601a31dc
shm: handle EINTR in posix_fallocate() 2020-02-25 19:07:23 +01:00
Daniel Eklöf
db830643d2
shm: prefer posix_fallocate over ftruncate 2020-02-15 19:46:00 +01:00
Daniel Eklöf
30335ef32a
fcft: include <fcft/fcft.h>, and use fcft/stride.h instead of local copy 2019-12-01 14:03:24 +01:00
Daniel Eklöf
29cccadd1d
tllist: is now an external "library", so use <> includes 2019-11-17 19:19:55 +01:00