2019-06-12 20:08:54 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stddef.h>
|
2020-03-24 17:46:48 +01:00
|
|
|
#include <sys/types.h>
|
2019-06-12 20:08:54 +02:00
|
|
|
|
2019-08-16 20:40:32 +02:00
|
|
|
#include <pixman.h>
|
2019-06-12 20:08:54 +02:00
|
|
|
#include <wayland-client.h>
|
|
|
|
|
|
shm: refactor: move away from a single, global, buffer list
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).
This patch refactors this, and completely removes the global
list.
Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.
This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.
However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.
Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
2021-07-16 16:48:49 +02:00
|
|
|
#include <tllist.h>
|
|
|
|
|
|
2025-05-01 08:34:49 +02:00
|
|
|
#include "config.h"
|
render: gamma-correct blending
This implements gamma-correct blending, which mainly affects font
rendering.
The implementation requires compile-time availability of the new
color-management protocol (available in wayland-protocols >= 1.41),
and run-time support for the same in the compositor (specifically, the
EXT_LINEAR TF function and sRGB primaries).
How it works: all colors are decoded from sRGB to linear (using a
lookup table, generated in the exact same way pixman generates it's
internal conversion tables) before being used by pixman. The resulting
image buffer is thus in decoded/linear format. We use the
color-management protocol to inform the compositor of this, by tagging
the wayland surfaces with the 'ext_linear' image attribute.
Sixes: all colors are sRGB internally, and decoded to linear before
being used in any sixels. Thus, the image buffers will contain linear
colors. This is important, since otherwise there would be a
decode/encode penalty every time a sixel is blended to the grid.
Emojis: we require fcft >= 3.2, which adds support for sRGB decoding
color glyphs. Meaning, the emoji pixman surfaces can be blended
directly to the grid, just like sixels.
Gamma-correct blending is enabled by default *when the compositor
supports it*. There's a new option to explicitly enable/disable it:
gamma-correct-blending=no|yes. If set to 'yes', and the compositor
does not implement the required color-management features, warning
logs are emitted.
There's a loss of precision when storing linear pixels in 8-bit
channels. For this reason, this patch also adds supports for 10-bit
surfaces. For now, this is disabled by default since such surfaces
only have 2 bits for alpha. It can be enabled with
tweak.surface-bit-depth=10-bit.
Perhaps, in the future, we can enable it by default if:
* gamma-correct blending is enabled
* the user has not enabled a transparent background
2025-02-21 11:01:29 +01:00
|
|
|
#include "wayland.h"
|
|
|
|
|
|
2021-07-15 22:21:37 +02:00
|
|
|
struct damage;
|
2021-05-07 20:20:47 +02:00
|
|
|
|
2019-06-12 20:08:54 +02:00
|
|
|
struct buffer {
|
|
|
|
|
int width;
|
|
|
|
|
int height;
|
2019-08-16 20:40:32 +02:00
|
|
|
int stride;
|
2019-06-12 20:08:54 +02:00
|
|
|
|
2021-07-15 22:30:08 +02:00
|
|
|
void *data;
|
2019-06-12 20:08:54 +02:00
|
|
|
|
|
|
|
|
struct wl_buffer *wl_buf;
|
2020-06-04 15:39:19 +02:00
|
|
|
pixman_image_t **pix;
|
|
|
|
|
size_t pix_instances;
|
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
|
|
|
|
2021-05-08 10:25:14 +02:00
|
|
|
unsigned age;
|
2021-07-16 16:47:57 +02:00
|
|
|
|
2023-10-07 16:23:09 +02:00
|
|
|
/*
|
|
|
|
|
* First item in the array is used to track frame-to-frame
|
|
|
|
|
* damage. This is used when re-applying damage from the last
|
|
|
|
|
* frame, when the compositor doesn't release buffers immediately
|
|
|
|
|
* (forcing us to double buffer)
|
|
|
|
|
*
|
|
|
|
|
* The remaining items are used to track surface damage. Each
|
|
|
|
|
* worker thread adds its own cell damage to "its" region. When
|
|
|
|
|
* the frame is done, all damage is converted to a single region,
|
|
|
|
|
* which is then used in calls to wl_surface_damage_buffer().
|
|
|
|
|
*/
|
|
|
|
|
pixman_region32_t *dirty;
|
2019-06-12 20:08:54 +02:00
|
|
|
};
|
|
|
|
|
|
2021-07-15 18:32:19 +02:00
|
|
|
void shm_fini(void);
|
2020-03-25 20:48:02 +01:00
|
|
|
void shm_set_max_pool_size(off_t max_pool_size);
|
2021-07-15 18:32:19 +02:00
|
|
|
|
shm: refactor: move away from a single, global, buffer list
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).
This patch refactors this, and completely removes the global
list.
Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.
This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.
However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.
Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
2021-07-16 16:48:49 +02:00
|
|
|
struct buffer_chain;
|
|
|
|
|
struct buffer_chain *shm_chain_new(
|
render: gamma-correct blending
This implements gamma-correct blending, which mainly affects font
rendering.
The implementation requires compile-time availability of the new
color-management protocol (available in wayland-protocols >= 1.41),
and run-time support for the same in the compositor (specifically, the
EXT_LINEAR TF function and sRGB primaries).
How it works: all colors are decoded from sRGB to linear (using a
lookup table, generated in the exact same way pixman generates it's
internal conversion tables) before being used by pixman. The resulting
image buffer is thus in decoded/linear format. We use the
color-management protocol to inform the compositor of this, by tagging
the wayland surfaces with the 'ext_linear' image attribute.
Sixes: all colors are sRGB internally, and decoded to linear before
being used in any sixels. Thus, the image buffers will contain linear
colors. This is important, since otherwise there would be a
decode/encode penalty every time a sixel is blended to the grid.
Emojis: we require fcft >= 3.2, which adds support for sRGB decoding
color glyphs. Meaning, the emoji pixman surfaces can be blended
directly to the grid, just like sixels.
Gamma-correct blending is enabled by default *when the compositor
supports it*. There's a new option to explicitly enable/disable it:
gamma-correct-blending=no|yes. If set to 'yes', and the compositor
does not implement the required color-management features, warning
logs are emitted.
There's a loss of precision when storing linear pixels in 8-bit
channels. For this reason, this patch also adds supports for 10-bit
surfaces. For now, this is disabled by default since such surfaces
only have 2 bits for alpha. It can be enabled with
tweak.surface-bit-depth=10-bit.
Perhaps, in the future, we can enable it by default if:
* gamma-correct blending is enabled
* the user has not enabled a transparent background
2025-02-21 11:01:29 +01:00
|
|
|
struct wayland *wayl, bool scrollable, size_t pix_instances,
|
2025-05-01 08:34:49 +02:00
|
|
|
enum shm_bit_depth desired_bit_depth);
|
shm: refactor: move away from a single, global, buffer list
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).
This patch refactors this, and completely removes the global
list.
Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.
This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.
However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.
Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
2021-07-16 16:48:49 +02:00
|
|
|
void shm_chain_free(struct buffer_chain *chain);
|
|
|
|
|
|
2025-05-01 08:34:49 +02:00
|
|
|
enum shm_bit_depth shm_chain_bit_depth(const struct buffer_chain *chain);
|
|
|
|
|
|
2021-07-15 18:32:19 +02:00
|
|
|
/*
|
|
|
|
|
* Returns a single buffer.
|
|
|
|
|
*
|
2024-02-06 12:36:45 +01:00
|
|
|
* May returned a cached buffer. If so, the buffer's age indicates how
|
2021-07-15 18:32:19 +02:00
|
|
|
* many shm_get_buffer() calls have been made for the same
|
shm: refactor: move away from a single, global, buffer list
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).
This patch refactors this, and completely removes the global
list.
Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.
This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.
However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.
Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
2021-07-16 16:48:49 +02:00
|
|
|
* width/height while the buffer was still busy.
|
2021-07-15 18:32:19 +02:00
|
|
|
*
|
|
|
|
|
* A newly allocated buffer has an age of 1234.
|
|
|
|
|
*/
|
2024-02-21 16:29:10 +01:00
|
|
|
struct buffer *shm_get_buffer(
|
|
|
|
|
struct buffer_chain *chain, int width, int height, bool with_alpha);
|
2021-07-15 18:32:19 +02:00
|
|
|
/*
|
2024-02-06 12:36:45 +01:00
|
|
|
* Returns many buffers, described by 'info', all sharing the same SHM
|
2021-07-15 18:32:19 +02:00
|
|
|
* buffer pool.
|
|
|
|
|
*
|
|
|
|
|
* Never returns cached buffers. However, the newly created buffers
|
|
|
|
|
* are all inserted into the regular buffer cache, and are treated
|
|
|
|
|
* just like buffers created by shm_get_buffer().
|
|
|
|
|
*
|
|
|
|
|
* This function is useful when allocating many small buffers, with
|
|
|
|
|
* (roughly) the same life time.
|
|
|
|
|
*
|
|
|
|
|
* Buffers are tagged for immediate purging, and will be destroyed as
|
|
|
|
|
* soon as the compositor releases them.
|
|
|
|
|
*/
|
|
|
|
|
void shm_get_many(
|
shm: refactor: move away from a single, global, buffer list
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).
This patch refactors this, and completely removes the global
list.
Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.
This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.
However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.
Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
2021-07-16 16:48:49 +02:00
|
|
|
struct buffer_chain *chain, size_t count,
|
|
|
|
|
int widths[static count], int heights[static count],
|
2024-02-21 16:29:10 +01:00
|
|
|
struct buffer *bufs[static count], bool with_alpha);
|
2021-07-15 18:32:19 +02:00
|
|
|
|
2022-04-16 17:47:56 +02:00
|
|
|
void shm_did_not_use_buf(struct buffer *buf);
|
|
|
|
|
|
2020-03-25 18:26:58 +01:00
|
|
|
bool shm_can_scroll(const struct buffer *buf);
|
shm: refactor: move away from a single, global, buffer list
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).
This patch refactors this, and completely removes the global
list.
Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.
This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.
However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.
Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
2021-07-16 16:48:49 +02:00
|
|
|
bool shm_scroll(struct buffer *buf, int rows,
|
2020-03-23 20:45:27 +01:00
|
|
|
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
|
|
|
|
2021-07-16 16:47:57 +02:00
|
|
|
void shm_addref(struct buffer *buf);
|
|
|
|
|
void shm_unref(struct buffer *buf);
|
2021-01-31 11:12:07 +01:00
|
|
|
|
shm: refactor: move away from a single, global, buffer list
Up until now, *all* buffers have been tracked in a single, global
buffer list. We've used 'cookies' to separate buffers from different
contexts (so that shm_get_buffer() doesn't try to re-use e.g. a
search-box buffer for the main grid).
This patch refactors this, and completely removes the global
list.
Instead of cookies, we now use 'chains'. A chain tracks both the
properties to apply to newly created buffers (scrollable, number of
pixman instances to instantiate etc), as well as the instantiated
buffers themselves.
This means there's strictly speaking not much use for shm_fini()
anymore, since its up to the chain owner to call shm_chain_free(),
which will also purge all buffers.
However, since purging a buffer may be deferred, if the buffer is
owned by the compositor at the time of the call to shm_purge() or
shm_chain_free(), we still keep a global 'deferred' list, on to which
deferred buffers are pushed. shm_fini() iterates this list and
destroys the buffers _even_ if they are still owned by the
compositor. This only happens at program termination, and not when
destroying a terminal instance. I.e. closing a window in a “foot
--server” does *not* trigger this.
Each terminal instatiates a number of chains, and these chains are
destroyed when the terminal instance is destroyed. Note that some
buffers may be put on the deferred list, as mentioned above.
2021-07-16 16:48:49 +02:00
|
|
|
void shm_purge(struct buffer_chain *chain);
|