1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef LABWC_SCALED_BUFFER_H
#define LABWC_SCALED_BUFFER_H
#include <wayland-server-core.h>
#define LAB_SCALED_BUFFER_MAX_CACHE 2
struct wlr_buffer;
struct wlr_scene_tree;
struct lab_data_buffer;
struct scaled_buffer;
struct scaled_buffer_impl {
/* Return a new buffer optimized for the new scale */
struct lab_data_buffer *(*create_buffer)
(struct scaled_buffer *scaled_buffer, double scale);
/* Might be NULL or used for cleaning up */
void (*destroy)(struct scaled_buffer *scaled_buffer);
/* Returns true if the two buffers are visually the same */
bool (*equal)(struct scaled_buffer *scaled_buffer_a,
struct scaled_buffer *scaled_buffer_b);
};
struct scaled_buffer {
struct wlr_scene_buffer *scene_buffer;
int width; /* unscaled, read only */
int height; /* unscaled, read only */
void *data; /* opaque user data */
/* Private */
bool drop_buffer;
double active_scale;
/* cached wlr_buffers for each scale */
struct wl_list cache; /* struct scaled_buffer_cache_entry.link */
struct wl_listener destroy;
struct wl_listener outputs_update;
const struct scaled_buffer_impl *impl;
struct wl_list link; /* all_scaled_buffers */
};
/*
* | |
* .------------------. .------------.
* scaled_buffer | new_output_scale | | set_buffer |
* architecture ´------------------` ´------------`
* | ^
* .-----------------------------|----------------|-----------.
* | v | |
* | .---------------. .-------------------------. |
* | | scaled_buffer |----| wlr_buffer LRU cache(2) |<---, |
* | ´---------------` ´-------------------------` | |
* | | | | |
* | .------. .--------------------------. | |
* | | impl | | wlr_buffer LRU cache of | | |
* | ´------` | other scaled_buffers | | |
* | | with impl->equal() | | |
* | ´--------------------------` | |
* | / | | |
* | not found found | |
* | .-----------------------. .-----------. | |
* | | impl->create_buffer() |--->| wlr_buffer |------` |
* | ´-----------------------` ´------------` |
* | |
* ´----------------------------------------------------------`
*/
/**
* Create an auto scaling buffer that creates a wlr_scene_buffer
* and subscribes to its output_enter and output_leave signals.
*
* If the maximal scale changes, it either sets an already existing buffer
* that was rendered for the current scale or - if there is none - calls
* implementation->create_buffer(self, scale) to get a new lab_data_buffer
* optimized for the new scale.
*
* Up to LAB_SCALED_BUFFER_MAX_CACHE (2) buffers are cached in an LRU fashion
* to handle the majority of use cases where a view is moved between no more
* than two different scales.
*
* scaled_buffer will clean up automatically once the internal
* wlr_scene_buffer is being destroyed. If implementation->destroy is set
* it will also get called so a consumer of this API may clean up its own
* allocations.
*
* Besides caching buffers for each scale per scaled_buffer, we also
* store all the scaled_buffers from all the implementers in a list
* in order to reuse backing buffers for visually duplicated
* scaled_buffers found via impl->equal().
*
* All requested lab_data_buffers via impl->create_buffer() will be locked
* during the lifetime of the buffer in the internal cache and unlocked
* when being evacuated from the cache (due to LAB_SCALED_BUFFER_MAX_CACHE
* or the internal wlr_scene_buffer being destroyed).
*
* If drop_buffer was set during creation of the scaled_buffer, the
* backing wlr_buffer behind a lab_data_buffer will also get dropped
* (via wlr_buffer_drop). If there are no more locks (consumers) of the
* respective buffer this will then cause the lab_data_buffer to be free'd.
*
* In the case of the buffer provider dropping the buffer itself (due to
* for example a Reconfigure event) the lock prevents the buffer from being
* destroyed until the buffer is evacuated from the internal cache and thus
* unlocked.
*
* This allows using scaled_buffer for an autoscaling font_buffer
* (which gets free'd automatically) and also for theme components like
* rounded corner images or button icons whose buffers only exist once but
* are references by multiple windows with their own scaled_buffers.
*
* The rough idea is: use drop_buffer = true for one-shot buffers and false
* for buffers that should outlive the scaled_buffer instance itself.
*/
struct scaled_buffer *scaled_buffer_create(
struct wlr_scene_tree *parent,
const struct scaled_buffer_impl *implementation,
bool drop_buffer);
/**
* scaled_buffer_request_update - mark the buffer that needs to be
* updated
* @width: the width of the buffer to be rendered, in scene coordinates
* @height: the height of the buffer to be rendered, in scene coordinates
*
* This function should be called when the states bound to the buffer are
* updated and ready for rendering.
*/
void scaled_buffer_request_update(struct scaled_buffer *self,
int width, int height);
/**
* scaled_buffer_invalidate_sharing - clear the list of entire cached
* scaled_buffers used to share visually dupliated buffers. This should
* be called on Reconfigure to force updates of newly created
* scaled_buffers rather than reusing ones created before Reconfigure.
*/
void scaled_buffer_invalidate_sharing(void);
/* Private */
struct scaled_buffer_cache_entry {
struct wl_list link; /* struct scaled_buffer.cache */
struct wlr_buffer *buffer;
double scale;
};
#endif /* LABWC_SCALED_BUFFER_H */
|