mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-05-09 05:58:13 +02:00
types/scene: split wlr_scene into modular components
Refactor the scene graph implementation by splitting wlr_scene.c into multiple focused units: buffer, node, rect and tree. Introduce corresponding public headers for each component. This reduces the size and complexity of the core scene file, improves code organization and makes individual parts of the scene graph easier to maintain and extend. As part of this refactor, drop unnecessary pointer indirection when passing scene trees (e.g. &scene->tree → scene->tree) and update all call sites accordingly. No functional changes intended.
This commit is contained in:
parent
b806de1d8c
commit
04501f8d8b
21 changed files with 2970 additions and 1999 deletions
|
|
@ -178,7 +178,7 @@ int main(void) {
|
|||
/* End drawing */
|
||||
|
||||
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create(
|
||||
&server.scene->tree, &buffer->base);
|
||||
server.scene->tree, &buffer->base);
|
||||
if (!scene_buffer) {
|
||||
wl_display_destroy(server.display);
|
||||
return EXIT_FAILURE;
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ static void handle_new_surface(struct wl_listener *listener, void *data) {
|
|||
surface->destroy.notify = surface_handle_destroy;
|
||||
wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);
|
||||
|
||||
wlr_scene_surface_create(&scene->tree, wlr_surface);
|
||||
wlr_scene_surface_create(scene->tree, wlr_surface);
|
||||
}
|
||||
|
||||
static void init_egl(struct wl_display *display) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_scene_rect.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
|
|
@ -131,12 +132,12 @@ static void server_handle_new_surface(struct wl_listener *listener,
|
|||
wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);
|
||||
|
||||
/* Border dimensions will be set in surface.commit handler */
|
||||
surface->border = wlr_scene_rect_create(&server->scene->tree,
|
||||
surface->border = wlr_scene_rect_create(server->scene->tree,
|
||||
0, 0, (float[4]){ 0.5f, 0.5f, 0.5f, 1 });
|
||||
wlr_scene_node_set_position(&surface->border->node, pos, pos);
|
||||
|
||||
surface->scene_surface =
|
||||
wlr_scene_surface_create(&server->scene->tree, wlr_surface);
|
||||
wlr_scene_surface_create(server->scene->tree, wlr_surface);
|
||||
|
||||
wlr_scene_node_set_position(&surface->scene_surface->buffer->node,
|
||||
pos + border_width, pos + border_width);
|
||||
|
|
|
|||
|
|
@ -3,10 +3,6 @@
|
|||
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
|
||||
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
|
||||
|
||||
void scene_node_get_size(struct wlr_scene_node *node, int *width, int *height);
|
||||
|
||||
void scene_surface_set_clip(struct wlr_scene_surface *surface, struct wlr_box *clip);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_damage_ring.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_scene_tree.h>
|
||||
#include <wlr/types/wlr_scene_buffer.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include <wlr/util/box.h>
|
||||
|
||||
|
|
@ -46,57 +48,18 @@ struct wlr_gamma_control_manager_v1;
|
|||
struct wlr_color_manager_v1;
|
||||
struct wlr_output_state;
|
||||
|
||||
typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)(
|
||||
struct wlr_scene_buffer *buffer, double *sx, double *sy);
|
||||
|
||||
typedef void (*wlr_scene_buffer_iterator_func_t)(
|
||||
struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data);
|
||||
|
||||
enum wlr_scene_node_type {
|
||||
WLR_SCENE_NODE_TREE,
|
||||
WLR_SCENE_NODE_RECT,
|
||||
WLR_SCENE_NODE_BUFFER,
|
||||
};
|
||||
|
||||
/** A node is an object in the scene. */
|
||||
struct wlr_scene_node {
|
||||
enum wlr_scene_node_type type;
|
||||
struct wlr_scene_tree *parent;
|
||||
|
||||
struct wl_list link; // wlr_scene_tree.children
|
||||
|
||||
bool enabled;
|
||||
int x, y; // relative to parent
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
void *data;
|
||||
|
||||
struct wlr_addon_set addons;
|
||||
|
||||
struct {
|
||||
pixman_region32_t visible;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
enum wlr_scene_debug_damage_option {
|
||||
WLR_SCENE_DEBUG_DAMAGE_NONE,
|
||||
WLR_SCENE_DEBUG_DAMAGE_RERENDER,
|
||||
WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT
|
||||
};
|
||||
|
||||
/** A sub-tree in the scene-graph. */
|
||||
struct wlr_scene_tree {
|
||||
struct wlr_scene_node node;
|
||||
|
||||
struct wl_list children; // wlr_scene_node.link
|
||||
};
|
||||
|
||||
/** The root scene-graph node. */
|
||||
struct wlr_scene {
|
||||
struct wlr_scene_tree tree;
|
||||
struct wlr_scene_tree *tree;
|
||||
|
||||
struct wl_list outputs; // wlr_scene_output.link
|
||||
|
||||
|
|
@ -138,13 +101,6 @@ struct wlr_scene_surface {
|
|||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/** A scene-graph node displaying a solid-colored rectangle */
|
||||
struct wlr_scene_rect {
|
||||
struct wlr_scene_node node;
|
||||
int width, height;
|
||||
float color[4];
|
||||
};
|
||||
|
||||
struct wlr_scene_outputs_update_event {
|
||||
struct wlr_scene_output **active;
|
||||
size_t size;
|
||||
|
|
@ -157,68 +113,6 @@ struct wlr_scene_output_sample_event {
|
|||
uint64_t release_point;
|
||||
};
|
||||
|
||||
struct wlr_scene_frame_done_event {
|
||||
struct wlr_scene_output *output;
|
||||
struct timespec when;
|
||||
};
|
||||
|
||||
/** A scene-graph node displaying a buffer */
|
||||
struct wlr_scene_buffer {
|
||||
struct wlr_scene_node node;
|
||||
|
||||
// May be NULL
|
||||
struct wlr_buffer *buffer;
|
||||
|
||||
struct {
|
||||
struct wl_signal outputs_update; // struct wlr_scene_outputs_update_event
|
||||
struct wl_signal output_sample; // struct wlr_scene_output_sample_event
|
||||
struct wl_signal frame_done; // struct wlr_scene_frame_done_event
|
||||
} events;
|
||||
|
||||
// May be NULL
|
||||
wlr_scene_buffer_point_accepts_input_func_t point_accepts_input;
|
||||
|
||||
/**
|
||||
* The output that the largest area of this buffer is displayed on.
|
||||
* This may be NULL if the buffer is not currently displayed on any
|
||||
* outputs.
|
||||
*/
|
||||
struct wlr_scene_output *primary_output;
|
||||
|
||||
float opacity;
|
||||
enum wlr_scale_filter_mode filter_mode;
|
||||
struct wlr_fbox src_box;
|
||||
int dst_width, dst_height;
|
||||
enum wl_output_transform transform;
|
||||
pixman_region32_t opaque_region;
|
||||
enum wlr_color_transfer_function transfer_function;
|
||||
enum wlr_color_named_primaries primaries;
|
||||
enum wlr_color_encoding color_encoding;
|
||||
enum wlr_color_range color_range;
|
||||
|
||||
struct {
|
||||
uint64_t active_outputs;
|
||||
struct wlr_texture *texture;
|
||||
struct wlr_linux_dmabuf_feedback_v1_init_options prev_feedback_options;
|
||||
|
||||
bool own_buffer;
|
||||
int buffer_width, buffer_height;
|
||||
bool buffer_is_opaque;
|
||||
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
|
||||
struct wl_listener buffer_release;
|
||||
struct wl_listener renderer_destroy;
|
||||
|
||||
// True if the underlying buffer is a wlr_single_pixel_buffer_v1
|
||||
bool is_single_pixel_buffer;
|
||||
// If is_single_pixel_buffer is set, contains the color of the buffer
|
||||
// as {R, G, B, A} where the max value of each component is UINT32_MAX
|
||||
uint32_t single_pixel_buffer_color[4];
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/** A viewport for an output in the scene-graph */
|
||||
struct wlr_scene_output {
|
||||
struct wlr_output *output;
|
||||
|
|
@ -289,66 +183,6 @@ struct wlr_scene_layer_surface_v1 {
|
|||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
* Immediately destroy the scene-graph node.
|
||||
*/
|
||||
void wlr_scene_node_destroy(struct wlr_scene_node *node);
|
||||
/**
|
||||
* Enable or disable this node. If a node is disabled, all of its children are
|
||||
* implicitly disabled as well.
|
||||
*/
|
||||
void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled);
|
||||
/**
|
||||
* Set the position of the node relative to its parent.
|
||||
*/
|
||||
void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y);
|
||||
/**
|
||||
* Move the node right above the specified sibling.
|
||||
* Asserts that node and sibling are distinct and share the same parent.
|
||||
*/
|
||||
void wlr_scene_node_place_above(struct wlr_scene_node *node,
|
||||
struct wlr_scene_node *sibling);
|
||||
/**
|
||||
* Move the node right below the specified sibling.
|
||||
* Asserts that node and sibling are distinct and share the same parent.
|
||||
*/
|
||||
void wlr_scene_node_place_below(struct wlr_scene_node *node,
|
||||
struct wlr_scene_node *sibling);
|
||||
/**
|
||||
* Move the node above all of its sibling nodes.
|
||||
*/
|
||||
void wlr_scene_node_raise_to_top(struct wlr_scene_node *node);
|
||||
/**
|
||||
* Move the node below all of its sibling nodes.
|
||||
*/
|
||||
void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node);
|
||||
/**
|
||||
* Move the node to another location in the tree.
|
||||
*/
|
||||
void wlr_scene_node_reparent(struct wlr_scene_node *node,
|
||||
struct wlr_scene_tree *new_parent);
|
||||
/**
|
||||
* Get the node's layout-local coordinates.
|
||||
*
|
||||
* True is returned if the node and all of its ancestors are enabled.
|
||||
*/
|
||||
bool wlr_scene_node_coords(struct wlr_scene_node *node, int *lx, int *ly);
|
||||
/**
|
||||
* Call `iterator` on each buffer in the scene-graph, with the buffer's
|
||||
* position in layout coordinates. The function is called from root to leaves
|
||||
* (in rendering order).
|
||||
*/
|
||||
void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node,
|
||||
wlr_scene_buffer_iterator_func_t iterator, void *user_data);
|
||||
/**
|
||||
* Find the topmost node in this scene-graph that contains the point at the
|
||||
* given layout-local coordinates. (For surface nodes, this means accepting
|
||||
* input events at that point.) Returns the node and coordinates relative to the
|
||||
* returned node, or NULL if no node is found at that location.
|
||||
*/
|
||||
struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
|
||||
double lx, double ly, double *nx, double *ny);
|
||||
|
||||
/**
|
||||
* Create a new scene-graph.
|
||||
*
|
||||
|
|
@ -357,6 +191,8 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
|
|||
*/
|
||||
struct wlr_scene *wlr_scene_create(void);
|
||||
|
||||
void wlr_scene_destroy(struct wlr_scene *scene);
|
||||
|
||||
/**
|
||||
* Handles linux_dmabuf_v1 feedback for all surfaces in the scene.
|
||||
*
|
||||
|
|
@ -381,11 +217,6 @@ void wlr_scene_set_gamma_control_manager_v1(struct wlr_scene *scene,
|
|||
*/
|
||||
void wlr_scene_set_color_manager_v1(struct wlr_scene *scene, struct wlr_color_manager_v1 *manager);
|
||||
|
||||
/**
|
||||
* Add a node displaying nothing but its children.
|
||||
*/
|
||||
struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent);
|
||||
|
||||
/**
|
||||
* Add a node displaying a single surface to the scene-graph.
|
||||
*
|
||||
|
|
@ -416,24 +247,6 @@ struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent);
|
|||
struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent,
|
||||
struct wlr_surface *surface);
|
||||
|
||||
/**
|
||||
* If this node represents a wlr_scene_buffer, that buffer will be returned. It
|
||||
* is not legal to feed a node that does not represent a wlr_scene_buffer.
|
||||
*/
|
||||
struct wlr_scene_buffer *wlr_scene_buffer_from_node(struct wlr_scene_node *node);
|
||||
|
||||
/**
|
||||
* If this node represents a wlr_scene_tree, that tree will be returned. It
|
||||
* is not legal to feed a node that does not represent a wlr_scene_tree.
|
||||
*/
|
||||
struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node);
|
||||
|
||||
/**
|
||||
* If this node represents a wlr_scene_rect, that rect will be returned. It
|
||||
* is not legal to feed a node that does not represent a wlr_scene_rect.
|
||||
*/
|
||||
struct wlr_scene_rect *wlr_scene_rect_from_node(struct wlr_scene_node *node);
|
||||
|
||||
/**
|
||||
* If this buffer is backed by a surface, then the struct wlr_scene_surface is
|
||||
* returned. If not, NULL will be returned.
|
||||
|
|
@ -447,135 +260,6 @@ struct wlr_scene_surface *wlr_scene_surface_try_from_buffer(
|
|||
void wlr_scene_surface_send_frame_done(struct wlr_scene_surface *scene_surface,
|
||||
const struct timespec *when);
|
||||
|
||||
/**
|
||||
* Add a node displaying a solid-colored rectangle to the scene-graph.
|
||||
*
|
||||
* The color argument must be a premultiplied color value.
|
||||
*/
|
||||
struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent,
|
||||
int width, int height, const float color[static 4]);
|
||||
|
||||
/**
|
||||
* Change the width and height of an existing rectangle node.
|
||||
*/
|
||||
void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height);
|
||||
|
||||
/**
|
||||
* Change the color of an existing rectangle node.
|
||||
*
|
||||
* The color argument must be a premultiplied color value.
|
||||
*/
|
||||
void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]);
|
||||
|
||||
/**
|
||||
* Add a node displaying a buffer to the scene-graph.
|
||||
*
|
||||
* If the buffer is NULL, this node will not be displayed.
|
||||
*/
|
||||
struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
|
||||
struct wlr_buffer *buffer);
|
||||
|
||||
/**
|
||||
* Sets the buffer's backing buffer.
|
||||
*
|
||||
* If the buffer is NULL, the buffer node will not be displayed.
|
||||
*/
|
||||
void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_buffer *buffer);
|
||||
|
||||
/**
|
||||
* Sets the buffer's backing buffer with a custom damage region.
|
||||
*
|
||||
* The damage region is in buffer-local coordinates. If the region is NULL,
|
||||
* the whole buffer node will be damaged.
|
||||
*/
|
||||
void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_buffer *buffer, const pixman_region32_t *region);
|
||||
|
||||
/**
|
||||
* Options for wlr_scene_buffer_set_buffer_with_options().
|
||||
*/
|
||||
struct wlr_scene_buffer_set_buffer_options {
|
||||
// The damage region is in buffer-local coordinates. If the region is NULL,
|
||||
// the whole buffer node will be damaged.
|
||||
const pixman_region32_t *damage;
|
||||
|
||||
// Wait for a timeline synchronization point before reading from the buffer.
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the buffer's backing buffer.
|
||||
*
|
||||
* If the buffer is NULL, the buffer node will not be displayed. If options is
|
||||
* NULL, empty options are used.
|
||||
*/
|
||||
void wlr_scene_buffer_set_buffer_with_options(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_buffer *buffer, const struct wlr_scene_buffer_set_buffer_options *options);
|
||||
|
||||
/**
|
||||
* Sets the buffer's opaque region. This is an optimization hint used to
|
||||
* determine if buffers which reside under this one need to be rendered or not.
|
||||
*/
|
||||
void wlr_scene_buffer_set_opaque_region(struct wlr_scene_buffer *scene_buffer,
|
||||
const pixman_region32_t *region);
|
||||
|
||||
/**
|
||||
* Set the source rectangle describing the region of the buffer which will be
|
||||
* sampled to render this node. This allows cropping the buffer.
|
||||
*
|
||||
* If NULL, the whole buffer is sampled. By default, the source box is NULL.
|
||||
*/
|
||||
void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer,
|
||||
const struct wlr_fbox *box);
|
||||
|
||||
/**
|
||||
* Set the destination size describing the region of the scene-graph the buffer
|
||||
* will be painted onto. This allows scaling the buffer.
|
||||
*
|
||||
* If zero, the destination size will be the buffer size. By default, the
|
||||
* destination size is zero.
|
||||
*/
|
||||
void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer,
|
||||
int width, int height);
|
||||
|
||||
/**
|
||||
* Set a transform which will be applied to the buffer.
|
||||
*/
|
||||
void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wl_output_transform transform);
|
||||
|
||||
/**
|
||||
* Sets the opacity of this buffer
|
||||
*/
|
||||
void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
|
||||
float opacity);
|
||||
|
||||
/**
|
||||
* Sets the filter mode to use when scaling the buffer
|
||||
*/
|
||||
void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_scale_filter_mode filter_mode);
|
||||
|
||||
void wlr_scene_buffer_set_transfer_function(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_transfer_function transfer_function);
|
||||
|
||||
void wlr_scene_buffer_set_primaries(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_named_primaries primaries);
|
||||
|
||||
void wlr_scene_buffer_set_color_encoding(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_encoding encoding);
|
||||
|
||||
void wlr_scene_buffer_set_color_range(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_range range);
|
||||
|
||||
/**
|
||||
* Calls the buffer's frame_done signal.
|
||||
*/
|
||||
void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_scene_frame_done_event *event);
|
||||
|
||||
/**
|
||||
* Add a viewport for the specified output to the scene-graph.
|
||||
*
|
||||
|
|
|
|||
209
include/wlr/types/wlr_scene_buffer.h
Normal file
209
include/wlr/types/wlr_scene_buffer.h
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
#ifndef WLR_TYPES_WLR_SCENE_BUFFER_H
|
||||
#define WLR_TYPES_WLR_SCENE_BUFFER_H
|
||||
|
||||
#include <wlr/types/wlr_scene_node.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_damage_ring.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include <wlr/util/box.h>
|
||||
|
||||
struct wlr_scene_buffer;
|
||||
|
||||
typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)(
|
||||
struct wlr_scene_buffer *buffer, double *sx, double *sy);
|
||||
typedef void (*wlr_scene_buffer_iterator_func_t)(
|
||||
struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data);
|
||||
|
||||
/** A scene-graph node displaying a buffer */
|
||||
struct wlr_scene_buffer {
|
||||
struct wlr_scene_node node;
|
||||
|
||||
// May be NULL
|
||||
struct wlr_buffer *buffer;
|
||||
|
||||
struct {
|
||||
struct wl_signal outputs_update; // struct wlr_scene_outputs_update_event
|
||||
struct wl_signal output_enter; // struct wlr_scene_output
|
||||
struct wl_signal output_leave; // struct wlr_scene_output
|
||||
struct wl_signal output_sample; // struct wlr_scene_output_sample_event
|
||||
struct wl_signal frame_done; // struct timespec
|
||||
} events;
|
||||
|
||||
// May be NULL
|
||||
wlr_scene_buffer_point_accepts_input_func_t point_accepts_input;
|
||||
|
||||
/**
|
||||
* The output that the largest area of this buffer is displayed on.
|
||||
* This may be NULL if the buffer is not currently displayed on any
|
||||
* outputs. This is the output that should be used for frame callbacks,
|
||||
* presentation feedback, etc.
|
||||
*/
|
||||
struct wlr_scene_output *primary_output;
|
||||
|
||||
float opacity;
|
||||
enum wlr_scale_filter_mode filter_mode;
|
||||
struct wlr_fbox src_box;
|
||||
int dst_width, dst_height;
|
||||
enum wl_output_transform transform;
|
||||
pixman_region32_t opaque_region;
|
||||
enum wlr_color_transfer_function transfer_function;
|
||||
enum wlr_color_named_primaries primaries;
|
||||
enum wlr_color_encoding color_encoding;
|
||||
enum wlr_color_range color_range;
|
||||
|
||||
|
||||
struct {
|
||||
uint64_t active_outputs;
|
||||
struct wlr_texture *texture;
|
||||
struct wlr_linux_dmabuf_feedback_v1_init_options prev_feedback_options;
|
||||
|
||||
bool own_buffer;
|
||||
int buffer_width, buffer_height;
|
||||
bool buffer_is_opaque;
|
||||
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
|
||||
struct wl_listener buffer_release;
|
||||
struct wl_listener renderer_destroy;
|
||||
|
||||
// True if the underlying buffer is a wlr_single_pixel_buffer_v1
|
||||
bool is_single_pixel_buffer;
|
||||
// If is_single_pixel_buffer is set, contains the color of the buffer
|
||||
// as {R, G, B, A} where the max value of each component is UINT32_MAX
|
||||
uint32_t single_pixel_buffer_color[4];
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a node displaying a buffer to the scene-graph.
|
||||
*
|
||||
* If the buffer is NULL, this node will not be displayed.
|
||||
*/
|
||||
struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
|
||||
struct wlr_buffer *buffer);
|
||||
|
||||
/**
|
||||
* Sets the buffer's backing buffer.
|
||||
*
|
||||
* If the buffer is NULL, the buffer node will not be displayed.
|
||||
*/
|
||||
void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_buffer *buffer);
|
||||
|
||||
/**
|
||||
* Sets the buffer's backing buffer with a custom damage region.
|
||||
*
|
||||
* The damage region is in buffer-local coordinates. If the region is NULL,
|
||||
* the whole buffer node will be damaged.
|
||||
*/
|
||||
void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_buffer *buffer, const pixman_region32_t *region);
|
||||
|
||||
/**
|
||||
* Options for wlr_scene_buffer_set_buffer_with_options().
|
||||
*/
|
||||
struct wlr_scene_buffer_set_buffer_options {
|
||||
// The damage region is in buffer-local coordinates. If the region is NULL,
|
||||
// the whole buffer node will be damaged.
|
||||
const pixman_region32_t *damage;
|
||||
|
||||
// Wait for a timeline synchronization point before reading from the buffer.
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the buffer's backing buffer.
|
||||
*
|
||||
* If the buffer is NULL, the buffer node will not be displayed. If options is
|
||||
* NULL, empty options are used.
|
||||
*/
|
||||
void wlr_scene_buffer_set_buffer_with_options(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_buffer *buffer, const struct wlr_scene_buffer_set_buffer_options *options);
|
||||
|
||||
/**
|
||||
* Sets the buffer's opaque region. This is an optimization hint used to
|
||||
* determine if buffers which reside under this one need to be rendered or not.
|
||||
*/
|
||||
void wlr_scene_buffer_set_opaque_region(struct wlr_scene_buffer *scene_buffer,
|
||||
const pixman_region32_t *region);
|
||||
|
||||
/**
|
||||
* Set the source rectangle describing the region of the buffer which will be
|
||||
* sampled to render this node. This allows cropping the buffer.
|
||||
*
|
||||
* If NULL, the whole buffer is sampled. By default, the source box is NULL.
|
||||
*/
|
||||
void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer,
|
||||
const struct wlr_fbox *box);
|
||||
|
||||
/**
|
||||
* Set the destination size describing the region of the scene-graph the buffer
|
||||
* will be painted onto. This allows scaling the buffer.
|
||||
*
|
||||
* If zero, the destination size will be the buffer size. By default, the
|
||||
* destination size is zero.
|
||||
*/
|
||||
void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer,
|
||||
int width, int height);
|
||||
|
||||
/**
|
||||
* Set a transform which will be applied to the buffer.
|
||||
*/
|
||||
void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wl_output_transform transform);
|
||||
|
||||
/**
|
||||
* Sets the opacity of this buffer
|
||||
*/
|
||||
void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
|
||||
float opacity);
|
||||
|
||||
/**
|
||||
* Sets the filter mode to use when scaling the buffer
|
||||
*/
|
||||
void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_scale_filter_mode filter_mode);
|
||||
|
||||
struct wlr_scene_frame_done_event {
|
||||
struct wlr_scene_output *output;
|
||||
struct timespec when;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls the buffer's frame_done signal.
|
||||
*/
|
||||
void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_scene_frame_done_event *event);
|
||||
|
||||
bool wlr_scene_node_is_buffer(const struct wlr_scene_node *node);
|
||||
|
||||
/**
|
||||
* If this node represents a wlr_scene_buffer, that buffer will be returned. It
|
||||
* is not legal to feed a node that does not represent a wlr_scene_buffer.
|
||||
*/
|
||||
struct wlr_scene_buffer *wlr_scene_buffer_from_node(struct wlr_scene_node *node);
|
||||
|
||||
void wlr_scene_buffer_set_transfer_function(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_transfer_function transfer_function);
|
||||
|
||||
void wlr_scene_buffer_set_primaries(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_named_primaries primaries);
|
||||
|
||||
void wlr_scene_buffer_set_color_encoding(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_encoding encoding);
|
||||
|
||||
void wlr_scene_buffer_set_color_range(struct wlr_scene_buffer *scene_buffer,
|
||||
enum wlr_color_range range);
|
||||
|
||||
/**
|
||||
* Call `iterator` on each buffer in the scene-graph, with the buffer's
|
||||
* position in layout coordinates. The function is called from root to leaves
|
||||
* (in rendering order).
|
||||
*/
|
||||
void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node,
|
||||
wlr_scene_buffer_iterator_func_t iterator, void *user_data);
|
||||
#endif // WLR_TYPES_WLR_SCENE_BUFFER_H
|
||||
184
include/wlr/types/wlr_scene_node.h
Normal file
184
include/wlr/types/wlr_scene_node.h
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_SCENE_NODE_H
|
||||
#define WLR_TYPES_WLR_SCENE_NODE_H
|
||||
|
||||
#include <pixman.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/config.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#if WLR_HAS_XWAYLAND
|
||||
#include <wlr/xwayland/xwayland.h>
|
||||
#endif
|
||||
|
||||
struct wlr_scene_node;
|
||||
struct wlr_scene_output;
|
||||
struct wlr_render_list_entry;
|
||||
struct wlr_render_data;
|
||||
struct wlr_scene;
|
||||
struct wlr_scene_buffer;
|
||||
struct wlr_linux_dmabuf_feedback_v1_init_options;
|
||||
|
||||
typedef bool (*scene_node_box_iterator_func_t)(struct wlr_scene_node *node,
|
||||
int sx, int sy, void *data);
|
||||
|
||||
struct wlr_scene_update_data {
|
||||
pixman_region32_t *visible;
|
||||
const pixman_region32_t *update_region;
|
||||
struct wlr_box update_box;
|
||||
struct wl_list *outputs;
|
||||
bool calculate_visibility;
|
||||
bool restack_xwayland_surfaces;
|
||||
|
||||
#if WLR_HAS_XWAYLAND
|
||||
struct wlr_xwayland_surface *restack_above;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct wlr_render_data {
|
||||
enum wl_output_transform transform;
|
||||
float scale;
|
||||
struct wlr_box logical;
|
||||
int trans_width, trans_height;
|
||||
|
||||
struct wlr_scene_output *output;
|
||||
|
||||
struct wlr_render_pass *render_pass;
|
||||
pixman_region32_t damage;
|
||||
};
|
||||
|
||||
struct wlr_render_list_constructor_data {
|
||||
struct wlr_box box;
|
||||
struct wl_array *render_list;
|
||||
bool calculate_visibility;
|
||||
bool highlight_transparent_region;
|
||||
bool fractional_scale;
|
||||
};
|
||||
|
||||
struct wlr_render_list_entry {
|
||||
struct wlr_scene_node *node;
|
||||
bool highlight_transparent_region;
|
||||
int x, y;
|
||||
};
|
||||
|
||||
struct wlr_scene_node_impl {
|
||||
void (*destroy)(struct wlr_scene_node *node);
|
||||
void (*set_enabled)(struct wlr_scene_node *node, bool enabled);
|
||||
void (*set_position)(struct wlr_scene_node *node, int x, int y);
|
||||
void (*bounds)(struct wlr_scene_node *node,
|
||||
int x, int y, pixman_region32_t *visible);
|
||||
void (*get_size)(struct wlr_scene_node *node,
|
||||
int *width, int *height);
|
||||
bool (*coords)(struct wlr_scene_node *node, int *lx_ptr, int *ly_ptr);
|
||||
struct wlr_scene_node *(*at)(struct wlr_scene_node *node,
|
||||
double lx, double ly, double *nx, double *ny);
|
||||
bool (*in_box)(struct wlr_scene_node *node, struct wlr_box *box,
|
||||
scene_node_box_iterator_func_t iterator, void *user_data);
|
||||
void (*opaque_region)(struct wlr_scene_node *node, int x, int y,
|
||||
pixman_region32_t *opaque);
|
||||
void (*update_outputs)(struct wlr_scene_node *node,
|
||||
struct wl_list *outputs, struct wlr_scene_output *ignore,
|
||||
struct wlr_scene_output *force);
|
||||
void (*update)(struct wlr_scene_node *node,
|
||||
pixman_region32_t *damage);
|
||||
void (*visibility)(struct wlr_scene_node *node,
|
||||
pixman_region32_t *visible);
|
||||
void (*frame_done)(struct wlr_scene_node *node,
|
||||
struct wlr_scene_output *scene_output, struct timespec *now);
|
||||
bool (*invisible)(struct wlr_scene_node *node);
|
||||
bool (*construct_render_list_iterator)(struct wlr_scene_node *node,
|
||||
int lx, int ly, void *_data);
|
||||
void (*render)(struct wlr_render_list_entry *entry, const struct wlr_render_data *data);
|
||||
void (*dmabuf_feedback)(struct wlr_render_list_entry *entry,
|
||||
struct wlr_scene_output *scene_output);
|
||||
void (*get_extents)(struct wlr_scene_node *node, int lx, int ly,
|
||||
int *x_min, int *y_min, int *x_max, int *y_max);
|
||||
struct wl_list *(*get_children)(struct wlr_scene_node *node);
|
||||
void (*restack_xwayland_surface)(struct wlr_scene_node *node,
|
||||
struct wlr_box *box, struct wlr_scene_update_data *data);
|
||||
void (*cleanup_when_disabled)(struct wlr_scene_node *node,
|
||||
bool xwayland_restack, struct wl_list *outputs);
|
||||
};
|
||||
|
||||
struct wlr_scene_node {
|
||||
const struct wlr_scene_node_impl *impl;
|
||||
|
||||
struct wlr_scene_tree *parent;
|
||||
struct wlr_scene *scene;
|
||||
|
||||
struct wl_list link; // wlr_scene_tree.children
|
||||
|
||||
bool enabled;
|
||||
int x, y; // relative to parent
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
void *data;
|
||||
|
||||
struct wlr_addon_set addons;
|
||||
|
||||
struct {
|
||||
pixman_region32_t visible;
|
||||
} WLR_PRIVATE;
|
||||
|
||||
struct wl_list children; // wlr_scene_node.link
|
||||
};
|
||||
|
||||
void wlr_scene_node_init(struct wlr_scene_node *node,
|
||||
const struct wlr_scene_node_impl *impl, struct wlr_scene_tree *parent);
|
||||
void wlr_scene_node_destroy(struct wlr_scene_node *node);
|
||||
|
||||
void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled);
|
||||
void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y);
|
||||
void wlr_scene_node_place_above(struct wlr_scene_node *node,
|
||||
struct wlr_scene_node *sibling);
|
||||
void wlr_scene_node_place_below(struct wlr_scene_node *node,
|
||||
struct wlr_scene_node *sibling);
|
||||
void wlr_scene_node_raise_to_top(struct wlr_scene_node *node);
|
||||
void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node);
|
||||
void wlr_scene_node_reparent(struct wlr_scene_node *node,
|
||||
struct wlr_scene_tree *new_parent);
|
||||
void wlr_scene_node_bounds(struct wlr_scene_node *node,
|
||||
int x, int y, pixman_region32_t *visible);
|
||||
void wlr_scene_node_get_size(struct wlr_scene_node *node,
|
||||
int *width, int *height);
|
||||
bool wlr_scene_node_coords(struct wlr_scene_node *node, int *lx_ptr, int *ly_ptr);
|
||||
struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
|
||||
double lx, double ly, double *nx, double *ny);
|
||||
bool wlr_scene_node_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
|
||||
scene_node_box_iterator_func_t iterator, void *user_data);
|
||||
void wlr_scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
|
||||
pixman_region32_t *opaque);
|
||||
void wlr_scene_node_update_outputs(struct wlr_scene_node *node,
|
||||
struct wl_list *outputs, struct wlr_scene_output *ignore,
|
||||
struct wlr_scene_output *force);
|
||||
void wlr_scene_node_update(struct wlr_scene_node *node,
|
||||
pixman_region32_t *damage);
|
||||
void wlr_scene_node_visibility(struct wlr_scene_node *node,
|
||||
pixman_region32_t *visible);
|
||||
void wlr_scene_node_send_frame_done(struct wlr_scene_node *node,
|
||||
struct wlr_scene_output *scene_output, struct timespec *now);
|
||||
bool wlr_scene_node_invisible(struct wlr_scene_node *node);
|
||||
bool wlr_scene_node_construct_render_list_iterator(struct wlr_scene_node *node,
|
||||
int lx, int ly, void *_data);
|
||||
void wlr_scene_node_render(struct wlr_render_list_entry *entry, const struct wlr_render_data *data);
|
||||
void wlr_scene_node_dmabuf_feedback(struct wlr_render_list_entry *entry,
|
||||
struct wlr_scene_output *scene_output);
|
||||
void wlr_scene_node_restack_xwayland_surface_below(struct wlr_scene_node *node);
|
||||
void wlr_scene_node_get_extents(struct wlr_scene_node *node, int lx, int ly,
|
||||
int *x_min, int *y_min, int *x_max, int *y_max);
|
||||
struct wl_list *wlr_scene_node_get_children(struct wlr_scene_node *node);
|
||||
void wlr_scene_node_restack_xwayland_surface(struct wlr_scene_node *node,
|
||||
struct wlr_box *box, struct wlr_scene_update_data *data);
|
||||
void wlr_scene_node_cleanup_when_disabled(struct wlr_scene_node *node,
|
||||
bool xwayland_restack, struct wl_list *outputs);
|
||||
|
||||
#endif
|
||||
40
include/wlr/types/wlr_scene_rect.h
Normal file
40
include/wlr/types/wlr_scene_rect.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef WLR_TYPES_WLR_SCENE_RECT_H
|
||||
#define WLR_TYPES_WLR_SCENE_RECT_H
|
||||
|
||||
#include <wlr/types/wlr_scene_node.h>
|
||||
|
||||
struct wlr_scene_rect {
|
||||
struct wlr_scene_node node;
|
||||
int width, height;
|
||||
float color[4];
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a node displaying a solid-colored rectangle to the scene-graph.
|
||||
*
|
||||
* The color argument must be a premultiplied color value.
|
||||
*/
|
||||
struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent,
|
||||
int width, int height, const float color[static 4]);
|
||||
|
||||
/**
|
||||
* Change the width and height of an existing rectangle node.
|
||||
*/
|
||||
void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height);
|
||||
|
||||
/**
|
||||
* Change the color of an existing rectangle node.
|
||||
*
|
||||
* The color argument must be a premultiplied color value.
|
||||
*/
|
||||
void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]);
|
||||
|
||||
bool wlr_scene_node_is_rect(const struct wlr_scene_node *node);
|
||||
|
||||
/**
|
||||
* If this node represents a wlr_scene_rect, that rect will be returned. It
|
||||
* is not legal to feed a node that does not represent a wlr_scene_rect.
|
||||
*/
|
||||
struct wlr_scene_rect *wlr_scene_rect_from_node(struct wlr_scene_node *node);
|
||||
|
||||
#endif
|
||||
32
include/wlr/types/wlr_scene_tree.h
Normal file
32
include/wlr/types/wlr_scene_tree.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef WLR_TYPES_WLR_SCENE_TREE_H
|
||||
#define WLR_TYPES_WLR_SCENE_TREE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <wlr/types/wlr_scene_node.h>
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
struct wlr_scene;
|
||||
|
||||
struct wlr_scene_tree {
|
||||
struct wlr_scene_node node;
|
||||
|
||||
struct wl_list children; // wlr_scene_node.link
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a node displaying nothing but its children.
|
||||
*/
|
||||
struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent);
|
||||
struct wlr_scene_tree *wlr_root_scene_tree_create(struct wlr_scene *scene);
|
||||
|
||||
bool wlr_scene_node_is_tree(const struct wlr_scene_node *node);
|
||||
|
||||
/**
|
||||
* If this node represents a wlr_scene_tree, that tree will be returned. It
|
||||
* is not legal to feed a node that does not represent a wlr_scene_tree.
|
||||
*/
|
||||
struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node);
|
||||
|
||||
#endif // WLR_TYPES_WLR_SCENE_TREE_H
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_scene_rect.h>
|
||||
|
||||
struct tree_spec {
|
||||
// Parameters for the tree we'll construct
|
||||
|
|
@ -62,7 +63,7 @@ static bool build_tree(struct wlr_scene_tree *parent, struct tree_spec *spec,
|
|||
static bool bench_create_tree(struct wlr_scene *scene, struct tree_spec *spec) {
|
||||
struct timespec start, end;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
if (!build_tree(&scene->tree, spec, 0, 0, 0)) {
|
||||
if (!build_tree(scene->tree, spec, 0, 0, 0)) {
|
||||
fprintf(stderr, "build_tree failed\n");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -90,7 +91,7 @@ static void bench_scene_node_at(struct wlr_scene *scene, struct tree_spec *spec)
|
|||
double ly = (double)(i * 53 % spec->max_y);
|
||||
double nx, ny;
|
||||
struct wlr_scene_node *node =
|
||||
wlr_scene_node_at(&scene->tree.node, lx, ly, &nx, &ny);
|
||||
wlr_scene_node_at(&scene->tree->node, lx, ly, &nx, &ny);
|
||||
if (node != NULL) {
|
||||
hits++;
|
||||
}
|
||||
|
|
@ -119,7 +120,7 @@ static void bench_scene_node_for_each_buffer(struct wlr_scene *scene, struct tre
|
|||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
for (int i = 0; i < iters; i++) {
|
||||
wlr_scene_node_for_each_buffer(&scene->tree.node,
|
||||
wlr_scene_node_for_each_buffer(&scene->tree->node,
|
||||
noop_iterator, &hits);
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
|
|
@ -149,6 +150,6 @@ int main(void) {
|
|||
bench_scene_node_at(scene, &spec);
|
||||
bench_scene_node_for_each_buffer(scene, &spec);
|
||||
|
||||
wlr_scene_node_destroy(&scene->tree.node);
|
||||
wlr_scene_destroy(scene);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,8 +364,8 @@ static struct tinywl_toplevel *desktop_toplevel_at(
|
|||
* We only care about surface nodes as we are specifically looking for a
|
||||
* surface in the surface tree of a tinywl_toplevel. */
|
||||
struct wlr_scene_node *node = wlr_scene_node_at(
|
||||
&server->scene->tree.node, lx, ly, sx, sy);
|
||||
if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) {
|
||||
&server->scene->tree->node, lx, ly, sx, sy);
|
||||
if (node == NULL || !wlr_scene_node_is_buffer(node)) {
|
||||
return NULL;
|
||||
}
|
||||
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
|
||||
|
|
@ -810,7 +810,7 @@ static void server_new_xdg_toplevel(struct wl_listener *listener, void *data) {
|
|||
toplevel->server = server;
|
||||
toplevel->xdg_toplevel = xdg_toplevel;
|
||||
toplevel->scene_tree =
|
||||
wlr_scene_xdg_surface_create(&toplevel->server->scene->tree, xdg_toplevel->base);
|
||||
wlr_scene_xdg_surface_create(toplevel->server->scene->tree, xdg_toplevel->base);
|
||||
toplevel->scene_tree->node.data = toplevel;
|
||||
xdg_toplevel->base->data = toplevel->scene_tree;
|
||||
|
||||
|
|
@ -1090,7 +1090,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
wl_list_remove(&server.new_output.link);
|
||||
|
||||
wlr_scene_node_destroy(&server.scene->tree.node);
|
||||
wlr_scene_destroy(server.scene);
|
||||
wlr_xcursor_manager_destroy(server.cursor_mgr);
|
||||
wlr_cursor_destroy(server.cursor);
|
||||
wlr_allocator_destroy(server.allocator);
|
||||
|
|
|
|||
|
|
@ -34,43 +34,43 @@ struct scene_node_source_frame_event {
|
|||
|
||||
static size_t last_output_num = 0;
|
||||
|
||||
static void _get_scene_node_extents(struct wlr_scene_node *node, int lx, int ly,
|
||||
int *x_min, int *y_min, int *x_max, int *y_max) {
|
||||
switch (node->type) {
|
||||
case WLR_SCENE_NODE_TREE:;
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
_get_scene_node_extents(child, lx + child->x, ly + child->y, x_min, y_min, x_max, y_max);
|
||||
}
|
||||
break;
|
||||
case WLR_SCENE_NODE_RECT:
|
||||
case WLR_SCENE_NODE_BUFFER:;
|
||||
struct wlr_box node_box = { .x = lx, .y = ly };
|
||||
scene_node_get_size(node, &node_box.width, &node_box.height);
|
||||
// static void _get_scene_node_extents(struct wlr_scene_node *node, int lx, int ly,
|
||||
// int *x_min, int *y_min, int *x_max, int *y_max) {
|
||||
// switch (node->type) {
|
||||
// case WLR_SCENE_NODE_TREE:;
|
||||
// struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
// struct wlr_scene_node *child;
|
||||
// wl_list_for_each(child, &scene_tree->children, link) {
|
||||
// _get_scene_node_extents(child, lx + child->x, ly + child->y, x_min, y_min, x_max, y_max);
|
||||
// }
|
||||
// break;
|
||||
// case WLR_SCENE_NODE_RECT:
|
||||
// case WLR_SCENE_NODE_BUFFER:;
|
||||
// struct wlr_box node_box = { .x = lx, .y = ly };
|
||||
// scene_node_get_size(node, &node_box.width, &node_box.height);
|
||||
|
||||
if (node_box.x < *x_min) {
|
||||
*x_min = node_box.x;
|
||||
}
|
||||
if (node_box.y < *y_min) {
|
||||
*y_min = node_box.y;
|
||||
}
|
||||
if (node_box.x + node_box.width > *x_max) {
|
||||
*x_max = node_box.x + node_box.width;
|
||||
}
|
||||
if (node_box.y + node_box.height > *y_max) {
|
||||
*y_max = node_box.y + node_box.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if (node_box.x < *x_min) {
|
||||
// *x_min = node_box.x;
|
||||
// }
|
||||
// if (node_box.y < *y_min) {
|
||||
// *y_min = node_box.y;
|
||||
// }
|
||||
// if (node_box.x + node_box.width > *x_max) {
|
||||
// *x_max = node_box.x + node_box.width;
|
||||
// }
|
||||
// if (node_box.y + node_box.height > *y_max) {
|
||||
// *y_max = node_box.y + node_box.height;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
static void get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box *box) {
|
||||
int lx = 0, ly = 0;
|
||||
wlr_scene_node_coords(node, &lx, &ly);
|
||||
*box = (struct wlr_box){ .x = INT_MAX, .y = INT_MAX };
|
||||
int x_max = INT_MIN, y_max = INT_MIN;
|
||||
_get_scene_node_extents(node, lx, ly, &box->x, &box->y, &x_max, &y_max);
|
||||
wlr_scene_node_get_extents(node, lx, ly, &box->x, &box->y, &x_max, &y_max);
|
||||
box->width = x_max - box->x;
|
||||
box->height = y_max - box->y;
|
||||
}
|
||||
|
|
@ -321,7 +321,7 @@ struct wlr_ext_image_capture_source_v1 *wlr_ext_image_capture_source_v1_create_w
|
|||
|
||||
wlr_output_init_render(&source->output, allocator, renderer);
|
||||
|
||||
struct wlr_scene *scene = scene_node_get_root(node);
|
||||
struct wlr_scene *scene = node->scene;
|
||||
source->scene_output = wlr_scene_output_create(scene, &source->output);
|
||||
|
||||
source->node_destroy.notify = source_handle_node_destroy;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ wlr_files += files(
|
|||
'scene/output_layout.c',
|
||||
'scene/xdg_shell.c',
|
||||
'scene/layer_shell_v1.c',
|
||||
'scene/wlr_scene_node.c',
|
||||
'scene/wlr_scene_tree.c',
|
||||
'scene/wlr_scene_buffer.c',
|
||||
'scene/wlr_scene_rect.c',
|
||||
'seat/wlr_seat_keyboard.c',
|
||||
'seat/wlr_seat_pointer.c',
|
||||
'seat/wlr_seat_touch.c',
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ struct wlr_scene_output_layout *wlr_scene_attach_output_layout(struct wlr_scene
|
|||
wl_signal_add(&output_layout->events.change, &sol->layout_change);
|
||||
|
||||
sol->scene_destroy.notify = scene_output_layout_handle_scene_destroy;
|
||||
wl_signal_add(&scene->tree.node.events.destroy, &sol->scene_destroy);
|
||||
wl_signal_add(&scene->tree->node.events.destroy, &sol->scene_destroy);
|
||||
|
||||
return sol;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ static struct wlr_scene_subsurface_tree *get_subsurface_tree_from_node(
|
|||
|
||||
static bool subsurface_tree_set_clip(struct wlr_scene_node *node,
|
||||
const struct wlr_box *clip) {
|
||||
if (node->type != WLR_SCENE_NODE_TREE) {
|
||||
if (wlr_scene_node_get_children(node) == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -350,9 +350,9 @@ static bool subsurface_tree_set_clip(struct wlr_scene_node *node,
|
|||
subsurface_tree_reconfigure_clip(tree);
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wl_list *childrens = wlr_scene_node_get_children(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
wl_list_for_each(child, childrens, link) {
|
||||
discovered_subsurface_tree |= subsurface_tree_set_clip(child, clip);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ static void handle_scene_buffer_outputs_update(
|
|||
struct wlr_scene_surface *surface =
|
||||
wl_container_of(listener, surface, outputs_update);
|
||||
struct wlr_scene_outputs_update_event *event = data;
|
||||
struct wlr_scene *scene = scene_node_get_root(&surface->buffer->node);
|
||||
struct wlr_scene *scene = surface->buffer->node.scene;
|
||||
|
||||
// If the surface is no longer visible on any output, keep the last sent
|
||||
// preferred configuration to avoid unnecessary redraws
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
1190
types/scene/wlr_scene_buffer.c
Normal file
1190
types/scene/wlr_scene_buffer.c
Normal file
File diff suppressed because it is too large
Load diff
505
types/scene/wlr_scene_node.c
Normal file
505
types/scene/wlr_scene_node.c
Normal file
|
|
@ -0,0 +1,505 @@
|
|||
#include <KHR/khrplatform.h>
|
||||
#include <sched.h>
|
||||
#include <wlr/types/wlr_scene_node.h>
|
||||
#include <wlr/types/wlr_scene_tree.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/util/region.h>
|
||||
#include <wlr/util/transform.h>
|
||||
#include "types/wlr_scene.h"
|
||||
#include "types/wlr_output.h"
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-util.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <wlr/config.h>
|
||||
|
||||
void wlr_scene_node_init(struct wlr_scene_node *node,
|
||||
const struct wlr_scene_node_impl *impl,
|
||||
struct wlr_scene_tree *parent) {
|
||||
assert(impl->destroy);
|
||||
*node = (struct wlr_scene_node){
|
||||
.impl = impl,
|
||||
.parent = parent,
|
||||
.enabled = true,
|
||||
};
|
||||
|
||||
wl_list_init(&node->link);
|
||||
|
||||
wl_signal_init(&node->events.destroy);
|
||||
pixman_region32_init(&node->visible);
|
||||
|
||||
if (parent != NULL) {
|
||||
wl_list_insert(parent->children.prev, &node->link);
|
||||
node->scene = parent->node.scene;
|
||||
}
|
||||
|
||||
wlr_addon_set_init(&node->addons);
|
||||
}
|
||||
|
||||
void wlr_scene_node_destroy(struct wlr_scene_node *node) {
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
wl_signal_emit_mutable(&node->events.destroy, NULL);
|
||||
assert(wl_list_empty(&node->events.destroy.listener_list));
|
||||
wlr_addon_set_finish(&node->addons);
|
||||
|
||||
wlr_scene_node_set_enabled(node, false);
|
||||
wl_list_remove(&node->link);
|
||||
pixman_region32_fini(&node->visible);
|
||||
if (node->impl->destroy != NULL) {
|
||||
node->impl->destroy(node);
|
||||
}
|
||||
}
|
||||
|
||||
void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled) {
|
||||
if (node->impl->set_enabled == NULL) {
|
||||
if (node->enabled == enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
pixman_region32_t visible;
|
||||
pixman_region32_init(&visible);
|
||||
if (wlr_scene_node_coords(node, &x, &y)) {
|
||||
wlr_scene_node_visibility(node, &visible);
|
||||
}
|
||||
|
||||
node->enabled = enabled;
|
||||
wlr_scene_node_update(node, &visible);
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->set_enabled(node, enabled);
|
||||
}
|
||||
|
||||
void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) {
|
||||
if (node->impl->set_position == NULL) {
|
||||
if (node->x == x && node->y == y) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->x = x;
|
||||
node->y = y;
|
||||
wlr_scene_node_update(node, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->set_position(node, x, y);
|
||||
}
|
||||
|
||||
void wlr_scene_node_place_above(struct wlr_scene_node *node,
|
||||
struct wlr_scene_node *sibling) {
|
||||
assert(node != sibling);
|
||||
assert(node->parent == sibling->parent);
|
||||
|
||||
if (node->link.prev == &sibling->link) {
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_remove(&node->link);
|
||||
wl_list_insert(&sibling->link, &node->link);
|
||||
wlr_scene_node_update(node, NULL);
|
||||
}
|
||||
|
||||
void wlr_scene_node_place_below(struct wlr_scene_node *node,
|
||||
struct wlr_scene_node *sibling) {
|
||||
assert(node != sibling);
|
||||
assert(node->parent == sibling->parent);
|
||||
|
||||
if (node->link.next == &sibling->link) {
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_remove(&node->link);
|
||||
wl_list_insert(sibling->link.prev, &node->link);
|
||||
wlr_scene_node_update(node, NULL);
|
||||
}
|
||||
|
||||
void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) {
|
||||
struct wlr_scene_node *current_top = wl_container_of(
|
||||
node->parent->children.prev, current_top, link);
|
||||
if (node == current_top) {
|
||||
return;
|
||||
}
|
||||
wlr_scene_node_place_above(node, current_top);
|
||||
}
|
||||
|
||||
void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) {
|
||||
struct wlr_scene_node *current_bottom = wl_container_of(
|
||||
node->parent->children.next, current_bottom, link);
|
||||
if (node == current_bottom) {
|
||||
return;
|
||||
}
|
||||
wlr_scene_node_place_below(node, current_bottom);
|
||||
}
|
||||
|
||||
void wlr_scene_node_reparent(struct wlr_scene_node *node,
|
||||
struct wlr_scene_tree *new_parent) {
|
||||
assert(new_parent != NULL);
|
||||
|
||||
if (node->parent == new_parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure that a node cannot become its own ancestor */
|
||||
for (struct wlr_scene_tree *ancestor = new_parent; ancestor != NULL;
|
||||
ancestor = ancestor->node.parent) {
|
||||
assert(&ancestor->node != node);
|
||||
}
|
||||
|
||||
int x, y;
|
||||
pixman_region32_t visible;
|
||||
pixman_region32_init(&visible);
|
||||
if (wlr_scene_node_coords(node, &x, &y)) {
|
||||
wlr_scene_node_visibility(node, &visible);
|
||||
}
|
||||
|
||||
wl_list_remove(&node->link);
|
||||
node->parent = new_parent;
|
||||
wl_list_insert(new_parent->children.prev, &node->link);
|
||||
wlr_scene_node_update(node, &visible);
|
||||
}
|
||||
|
||||
void wlr_scene_node_get_size(struct wlr_scene_node *node,
|
||||
int *width, int *height) {
|
||||
if (node->impl->get_size == NULL) {
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->get_size(node, width, height);
|
||||
}
|
||||
|
||||
void wlr_scene_node_bounds(struct wlr_scene_node *node,
|
||||
int x, int y, pixman_region32_t *visible) {
|
||||
if (node->impl->bounds == NULL) {
|
||||
if (!node->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
wlr_scene_node_get_size(node, &width, &height);
|
||||
pixman_region32_union_rect(visible, visible, x, y, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->bounds(node, x, y, visible);
|
||||
}
|
||||
|
||||
bool wlr_scene_node_coords(struct wlr_scene_node *node, int *lx_ptr, int *ly_ptr) {
|
||||
if (node->impl->coords == NULL) {
|
||||
int lx = 0, ly = 0;
|
||||
bool enabled = true;
|
||||
while (true) {
|
||||
lx += node->x;
|
||||
ly += node->y;
|
||||
enabled = enabled && node->enabled;
|
||||
if (node->parent == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = &node->parent->node;
|
||||
}
|
||||
|
||||
*lx_ptr = lx;
|
||||
*ly_ptr = ly;
|
||||
return enabled;
|
||||
}
|
||||
|
||||
return node->impl->coords(node, lx_ptr, ly_ptr);
|
||||
}
|
||||
|
||||
struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
|
||||
double lx, double ly, double *nx, double *ny) {
|
||||
|
||||
if (node->impl->at == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return node->impl->at(node, lx, ly, nx, ny);
|
||||
}
|
||||
|
||||
bool wlr_scene_node_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
|
||||
scene_node_box_iterator_func_t iterator, void *user_data) {
|
||||
if (node->impl->in_box == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node->impl->in_box(node, box, iterator, user_data);
|
||||
}
|
||||
|
||||
void wlr_scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
|
||||
pixman_region32_t *opaque) {
|
||||
if (node->impl->opaque_region == NULL) {
|
||||
int width, height;
|
||||
wlr_scene_node_get_size(node, &width, &height);
|
||||
pixman_region32_fini(opaque);
|
||||
pixman_region32_init_rect(opaque, x, y, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
return node->impl->opaque_region(node, x, y, opaque);
|
||||
}
|
||||
|
||||
void wlr_scene_node_update_outputs(struct wlr_scene_node *node,
|
||||
struct wl_list *outputs, struct wlr_scene_output *ignore,
|
||||
struct wlr_scene_output *force) {
|
||||
|
||||
if (node->impl->update_outputs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
return node->impl->update_outputs(node, outputs, ignore, force);
|
||||
}
|
||||
|
||||
static void scale_region(pixman_region32_t *region, float scale, bool round_up) {
|
||||
wlr_region_scale(region, region, scale);
|
||||
|
||||
if (round_up && floor(scale) != scale) {
|
||||
wlr_region_expand(region, region, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static bool scene_node_update_iterator(struct wlr_scene_node *node,
|
||||
int lx, int ly, void *_data) {
|
||||
struct wlr_scene_update_data *data = _data;
|
||||
|
||||
struct wlr_box box = { .x = lx, .y = ly };
|
||||
wlr_scene_node_get_size(node, &box.width, &box.height);
|
||||
|
||||
pixman_region32_subtract(&node->visible, &node->visible, data->update_region);
|
||||
pixman_region32_union(&node->visible, &node->visible, data->visible);
|
||||
pixman_region32_intersect_rect(&node->visible, &node->visible,
|
||||
lx, ly, box.width, box.height);
|
||||
|
||||
if (data->calculate_visibility) {
|
||||
pixman_region32_t opaque;
|
||||
pixman_region32_init(&opaque);
|
||||
wlr_scene_node_opaque_region(node, lx, ly, &opaque);
|
||||
pixman_region32_subtract(data->visible, data->visible, &opaque);
|
||||
pixman_region32_fini(&opaque);
|
||||
}
|
||||
|
||||
wlr_scene_node_update_outputs(node, data->outputs, NULL, NULL);
|
||||
#if WLR_HAS_XWAYLAND
|
||||
if (data->restack_xwayland_surfaces) {
|
||||
wlr_scene_node_restack_xwayland_surface(node, &box, data);
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void scene_update_region(struct wlr_scene *scene,
|
||||
const pixman_region32_t *update_region) {
|
||||
pixman_region32_t visible;
|
||||
pixman_region32_init(&visible);
|
||||
pixman_region32_copy(&visible, update_region);
|
||||
|
||||
struct pixman_box32 *region_box = pixman_region32_extents(update_region);
|
||||
struct wlr_scene_update_data data = {
|
||||
.visible = &visible,
|
||||
.update_region = update_region,
|
||||
.update_box = {
|
||||
.x = region_box->x1,
|
||||
.y = region_box->y1,
|
||||
.width = region_box->x2 - region_box->x1,
|
||||
.height = region_box->y2 - region_box->y1,
|
||||
},
|
||||
.outputs = &scene->outputs,
|
||||
.calculate_visibility = scene->calculate_visibility,
|
||||
.restack_xwayland_surfaces = scene->restack_xwayland_surfaces,
|
||||
};
|
||||
|
||||
// update node visibility and output enter/leave events
|
||||
wlr_scene_node_nodes_in_box(&scene->tree->node, &data.update_box, scene_node_update_iterator, &data);
|
||||
|
||||
pixman_region32_fini(&visible);
|
||||
}
|
||||
|
||||
static void scene_output_damage(struct wlr_scene_output *scene_output,
|
||||
const pixman_region32_t *damage) {
|
||||
struct wlr_output *output = scene_output->output;
|
||||
|
||||
pixman_region32_t clipped;
|
||||
pixman_region32_init(&clipped);
|
||||
pixman_region32_intersect_rect(&clipped, damage, 0, 0, output->width, output->height);
|
||||
|
||||
if (!pixman_region32_empty(&clipped)) {
|
||||
wlr_output_schedule_frame(scene_output->output);
|
||||
wlr_damage_ring_add(&scene_output->damage_ring, &clipped);
|
||||
|
||||
pixman_region32_union(&scene_output->pending_commit_damage,
|
||||
&scene_output->pending_commit_damage, &clipped);
|
||||
}
|
||||
|
||||
pixman_region32_fini(&clipped);
|
||||
}
|
||||
|
||||
static void output_to_buffer_coords(pixman_region32_t *damage, struct wlr_output *output) {
|
||||
int width, height;
|
||||
wlr_output_transformed_resolution(output, &width, &height);
|
||||
|
||||
wlr_region_transform(damage, damage,
|
||||
wlr_output_transform_invert(output->transform), width, height);
|
||||
}
|
||||
|
||||
static void scene_damage_outputs(struct wlr_scene *scene, const pixman_region32_t *damage) {
|
||||
if (pixman_region32_empty(damage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_scene_output *scene_output;
|
||||
wl_list_for_each(scene_output, &scene->outputs, link) {
|
||||
pixman_region32_t output_damage;
|
||||
pixman_region32_init(&output_damage);
|
||||
pixman_region32_copy(&output_damage, damage);
|
||||
pixman_region32_translate(&output_damage,
|
||||
-scene_output->x, -scene_output->y);
|
||||
scale_region(&output_damage, scene_output->output->scale, true);
|
||||
output_to_buffer_coords(&output_damage, scene_output->output);
|
||||
scene_output_damage(scene_output, &output_damage);
|
||||
pixman_region32_fini(&output_damage);
|
||||
}
|
||||
}
|
||||
|
||||
void wlr_scene_node_update(struct wlr_scene_node *node,
|
||||
pixman_region32_t *damage) {
|
||||
if (node->impl->update == NULL) {
|
||||
struct wlr_scene *scene = node->scene;
|
||||
|
||||
int x, y;
|
||||
if (!wlr_scene_node_coords(node, &x, &y)) {
|
||||
// We assume explicit damage on a disabled tree means the node was just
|
||||
// disabled.
|
||||
if (damage) {
|
||||
wlr_scene_node_cleanup_when_disabled(node, scene->restack_xwayland_surfaces, &scene->outputs);
|
||||
|
||||
scene_update_region(scene, damage);
|
||||
scene_damage_outputs(scene, damage);
|
||||
pixman_region32_fini(damage);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pixman_region32_t visible;
|
||||
if (!damage) {
|
||||
pixman_region32_init(&visible);
|
||||
wlr_scene_node_visibility(node, &visible);
|
||||
damage = &visible;
|
||||
}
|
||||
|
||||
pixman_region32_t update_region;
|
||||
pixman_region32_init(&update_region);
|
||||
pixman_region32_copy(&update_region, damage);
|
||||
wlr_scene_node_bounds(node, x, y, &update_region);
|
||||
|
||||
scene_update_region(scene, &update_region);
|
||||
pixman_region32_fini(&update_region);
|
||||
|
||||
wlr_scene_node_visibility(node, damage);
|
||||
scene_damage_outputs(scene, damage);
|
||||
pixman_region32_fini(damage);
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->update(node, damage);
|
||||
}
|
||||
|
||||
void wlr_scene_node_visibility(struct wlr_scene_node *node,
|
||||
pixman_region32_t *visible) {
|
||||
if (node->impl->visibility == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->visibility(node, visible);
|
||||
}
|
||||
|
||||
void wlr_scene_node_send_frame_done(struct wlr_scene_node *node,
|
||||
struct wlr_scene_output *scene_output, struct timespec *now) {
|
||||
if (!node->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->impl->frame_done == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->frame_done(node, scene_output, now);
|
||||
}
|
||||
|
||||
bool wlr_scene_node_invisible(struct wlr_scene_node *node) {
|
||||
if (node->impl->invisible == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node->impl->invisible(node);
|
||||
}
|
||||
|
||||
bool wlr_scene_node_construct_render_list_iterator(struct wlr_scene_node *node,
|
||||
int lx, int ly, void *_data) {
|
||||
if (node->impl->construct_render_list_iterator == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node->impl->construct_render_list_iterator(node, lx, ly, _data);
|
||||
}
|
||||
|
||||
void wlr_scene_node_render(struct wlr_render_list_entry *entry, const struct wlr_render_data *data) {
|
||||
if (entry->node->impl->render == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->node->impl->render(entry, data);
|
||||
}
|
||||
|
||||
void wlr_scene_node_dmabuf_feedback(struct wlr_render_list_entry *entry,
|
||||
struct wlr_scene_output *scene_output) {
|
||||
if (entry->node->impl->dmabuf_feedback == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->node->impl->dmabuf_feedback(entry, scene_output);
|
||||
}
|
||||
|
||||
void wlr_scene_node_get_extents(struct wlr_scene_node *node, int lx, int ly,
|
||||
int *x_min, int *y_min, int *x_max, int *y_max) {
|
||||
if (node->impl->get_extents == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->get_extents(node, lx, ly, x_min, y_min, x_max, y_max);
|
||||
}
|
||||
|
||||
struct wl_list *wlr_scene_node_get_children(struct wlr_scene_node *node) {
|
||||
if (node->impl->get_children == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return node->impl->get_children(node);
|
||||
}
|
||||
|
||||
void wlr_scene_node_restack_xwayland_surface(struct wlr_scene_node *node,
|
||||
struct wlr_box *box, struct wlr_scene_update_data *data) {
|
||||
if (node->impl->restack_xwayland_surface == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->restack_xwayland_surface(node, box, data);
|
||||
}
|
||||
|
||||
void wlr_scene_node_cleanup_when_disabled(struct wlr_scene_node *node,
|
||||
bool xwayland_restack, struct wl_list *outputs) {
|
||||
if (node->impl->cleanup_when_disabled == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->impl->cleanup_when_disabled(node, xwayland_restack, outputs);
|
||||
}
|
||||
364
types/scene/wlr_scene_rect.c
Normal file
364
types/scene/wlr_scene_rect.c
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
#include <sched.h>
|
||||
#include <wlr/types/wlr_scene_rect.h>
|
||||
#include "types/wlr_scene.h"
|
||||
#include <wlr/util/region.h>
|
||||
#include <wlr/util/transform.h>
|
||||
#include "types/wlr_output.h"
|
||||
#include "types/wlr_scene.h"
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-util.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <wlr/config.h>
|
||||
|
||||
static void scene_node_visibility(struct wlr_scene_node *node,
|
||||
pixman_region32_t *visible);
|
||||
static void scene_node_get_size(struct wlr_scene_node *node,
|
||||
int *width, int *height);
|
||||
|
||||
static void scene_node_destroy(struct wlr_scene_node *node) {
|
||||
struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
|
||||
|
||||
free(scene_rect);
|
||||
}
|
||||
|
||||
struct node_at_data {
|
||||
double lx, ly;
|
||||
double rx, ry;
|
||||
struct wlr_scene_node *node;
|
||||
};
|
||||
|
||||
static bool scene_node_at_iterator(struct wlr_scene_node *node,
|
||||
int lx, int ly, void *data) {
|
||||
struct node_at_data *at_data = data;
|
||||
|
||||
double rx = at_data->lx - lx;
|
||||
double ry = at_data->ly - ly;
|
||||
|
||||
at_data->rx = rx;
|
||||
at_data->ry = ry;
|
||||
at_data->node = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct wlr_scene_node *scene_node_at(struct wlr_scene_node *node,
|
||||
double lx, double ly, double *nx, double *ny) {
|
||||
struct wlr_box box = {
|
||||
.x = floor(lx),
|
||||
.y = floor(ly),
|
||||
.width = 1,
|
||||
.height = 1
|
||||
};
|
||||
|
||||
struct node_at_data data = {
|
||||
.lx = lx,
|
||||
.ly = ly
|
||||
};
|
||||
|
||||
if (wlr_scene_node_nodes_in_box(node, &box, scene_node_at_iterator, &data)) {
|
||||
if (nx) {
|
||||
*nx = data.rx;
|
||||
}
|
||||
if (ny) {
|
||||
*ny = data.ry;
|
||||
}
|
||||
return data.node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void scene_node_get_size(struct wlr_scene_node *node,
|
||||
int *width, int *height) {
|
||||
struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
|
||||
*width = scene_rect->width;
|
||||
*height = scene_rect->height;
|
||||
}
|
||||
|
||||
static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
|
||||
scene_node_box_iterator_func_t iterator, void *user_data, int lx, int ly) {
|
||||
if (!node->enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_box node_box = { .x = lx, .y = ly };
|
||||
scene_node_get_size(node, &node_box.width, &node_box.height);
|
||||
|
||||
if (wlr_box_intersection(&node_box, &node_box, box) &&
|
||||
iterator(node, lx, ly, user_data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
|
||||
scene_node_box_iterator_func_t iterator, void *user_data) {
|
||||
int x, y;
|
||||
wlr_scene_node_coords(node, &x, &y);
|
||||
|
||||
return _scene_nodes_in_box(node, box, iterator, user_data, x, y);
|
||||
}
|
||||
|
||||
static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
|
||||
pixman_region32_t *opaque) {
|
||||
int width, height;
|
||||
scene_node_get_size(node, &width, &height);
|
||||
|
||||
struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
|
||||
if (scene_rect->color[3] != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
pixman_region32_fini(opaque);
|
||||
pixman_region32_init_rect(opaque, x, y, width, height);
|
||||
}
|
||||
|
||||
static void scale_region(pixman_region32_t *region, float scale, bool round_up) {
|
||||
wlr_region_scale(region, region, scale);
|
||||
|
||||
if (round_up && floor(scale) != scale) {
|
||||
wlr_region_expand(region, region, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void scene_node_visibility(struct wlr_scene_node *node,
|
||||
pixman_region32_t *visible) {
|
||||
if (!node->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
pixman_region32_union(visible, visible, &node->visible);
|
||||
}
|
||||
|
||||
static bool scene_node_invisible(struct wlr_scene_node *node) {
|
||||
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
|
||||
|
||||
return rect->color[3] == 0.f;
|
||||
}
|
||||
|
||||
static bool construct_render_list_iterator(struct wlr_scene_node *node,
|
||||
int lx, int ly, void *_data) {
|
||||
struct wlr_render_list_constructor_data *data = _data;
|
||||
|
||||
if (wlr_scene_node_invisible(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// While rendering, the background should always be black. If we see a
|
||||
// black rect, we can ignore rendering everything under the rect, and
|
||||
// unless fractional scale is used even the rect itself (to avoid running
|
||||
// into issues regarding damage region expansion).
|
||||
if (data->calculate_visibility &&
|
||||
(!data->fractional_scale || data->render_list->size == 0)) {
|
||||
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
|
||||
float *black = (float[4]){ 0.f, 0.f, 0.f, 1.f };
|
||||
|
||||
if (memcmp(rect->color, black, sizeof(float) * 4) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pixman_region32_t intersection;
|
||||
pixman_region32_init(&intersection);
|
||||
pixman_region32_intersect_rect(&intersection, &node->visible,
|
||||
data->box.x, data->box.y,
|
||||
data->box.width, data->box.height);
|
||||
if (pixman_region32_empty(&intersection)) {
|
||||
pixman_region32_fini(&intersection);
|
||||
return false;
|
||||
}
|
||||
|
||||
pixman_region32_fini(&intersection);
|
||||
|
||||
struct wlr_render_list_entry *entry = wl_array_add(data->render_list, sizeof(*entry));
|
||||
if (entry == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*entry = (struct wlr_render_list_entry){
|
||||
.node = node,
|
||||
.x = lx,
|
||||
.y = ly,
|
||||
.highlight_transparent_region = data->highlight_transparent_region,
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void logical_to_buffer_coords(pixman_region32_t *region, const struct wlr_render_data *data,
|
||||
bool round_up) {
|
||||
enum wl_output_transform transform = wlr_output_transform_invert(data->transform);
|
||||
scale_region(region, data->scale, round_up);
|
||||
wlr_region_transform(region, region, transform, data->trans_width, data->trans_height);
|
||||
}
|
||||
|
||||
static int scale_length(int length, int offset, float scale) {
|
||||
return round((offset + length) * scale) - round(offset * scale);
|
||||
}
|
||||
|
||||
static void scale_box(struct wlr_box *box, float scale) {
|
||||
box->width = scale_length(box->width, box->x, scale);
|
||||
box->height = scale_length(box->height, box->y, scale);
|
||||
box->x = round(box->x * scale);
|
||||
box->y = round(box->y * scale);
|
||||
}
|
||||
|
||||
static void transform_output_box(struct wlr_box *box, const struct wlr_render_data *data) {
|
||||
enum wl_output_transform transform = wlr_output_transform_invert(data->transform);
|
||||
scale_box(box, data->scale);
|
||||
wlr_box_transform(box, box, transform, data->trans_width, data->trans_height);
|
||||
}
|
||||
|
||||
static void scene_node_render(struct wlr_render_list_entry *entry, const struct wlr_render_data *data) {
|
||||
struct wlr_scene_node *node = entry->node;
|
||||
|
||||
pixman_region32_t render_region;
|
||||
pixman_region32_init(&render_region);
|
||||
pixman_region32_copy(&render_region, &node->visible);
|
||||
pixman_region32_translate(&render_region, -data->logical.x, -data->logical.y);
|
||||
logical_to_buffer_coords(&render_region, data, true);
|
||||
pixman_region32_intersect(&render_region, &render_region, &data->damage);
|
||||
if (pixman_region32_empty(&render_region)) {
|
||||
pixman_region32_fini(&render_region);
|
||||
return;
|
||||
}
|
||||
|
||||
int x = entry->x - data->logical.x;
|
||||
int y = entry->y - data->logical.y;
|
||||
|
||||
struct wlr_box dst_box = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
scene_node_get_size(node, &dst_box.width, &dst_box.height);
|
||||
transform_output_box(&dst_box, data);
|
||||
|
||||
pixman_region32_t opaque;
|
||||
pixman_region32_init(&opaque);
|
||||
scene_node_opaque_region(node, x, y, &opaque);
|
||||
logical_to_buffer_coords(&opaque, data, false);
|
||||
pixman_region32_subtract(&opaque, &render_region, &opaque);
|
||||
|
||||
struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
|
||||
|
||||
wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
|
||||
.box = dst_box,
|
||||
.color = {
|
||||
.r = scene_rect->color[0],
|
||||
.g = scene_rect->color[1],
|
||||
.b = scene_rect->color[2],
|
||||
.a = scene_rect->color[3],
|
||||
},
|
||||
.clip = &render_region,
|
||||
});
|
||||
|
||||
pixman_region32_fini(&opaque);
|
||||
pixman_region32_fini(&render_region);
|
||||
}
|
||||
|
||||
static void get_scene_node_extents(struct wlr_scene_node *node, int lx, int ly,
|
||||
int *x_min, int *y_min, int *x_max, int *y_max) {
|
||||
struct wlr_box node_box = { .x = lx, .y = ly };
|
||||
scene_node_get_size(node, &node_box.width, &node_box.height);
|
||||
|
||||
if (node_box.x < *x_min) {
|
||||
*x_min = node_box.x;
|
||||
}
|
||||
if (node_box.y < *y_min) {
|
||||
*y_min = node_box.y;
|
||||
}
|
||||
if (node_box.x + node_box.width > *x_max) {
|
||||
*x_max = node_box.x + node_box.width;
|
||||
}
|
||||
if (node_box.y + node_box.height > *y_max) {
|
||||
*y_max = node_box.y + node_box.height;
|
||||
}
|
||||
}
|
||||
|
||||
static void scene_node_cleanup_when_disabled(struct wlr_scene_node *node,
|
||||
bool xwayland_restack, struct wl_list *outputs) {
|
||||
pixman_region32_clear(&node->visible);
|
||||
wlr_scene_node_update_outputs(node, outputs, NULL, NULL);
|
||||
}
|
||||
|
||||
static const struct wlr_scene_node_impl scene_node_impl = {
|
||||
.destroy = scene_node_destroy,
|
||||
.set_enabled = NULL,
|
||||
.set_position = NULL,
|
||||
.bounds = NULL,
|
||||
.get_size = scene_node_get_size,
|
||||
.coords = NULL,
|
||||
.at = scene_node_at,
|
||||
.in_box = scene_nodes_in_box,
|
||||
.opaque_region = scene_node_opaque_region,
|
||||
.update_outputs = NULL,
|
||||
.update = NULL,
|
||||
.visibility = scene_node_visibility,
|
||||
.frame_done = NULL,
|
||||
.invisible = scene_node_invisible,
|
||||
.construct_render_list_iterator = construct_render_list_iterator,
|
||||
.render = scene_node_render,
|
||||
.get_extents = get_scene_node_extents,
|
||||
.get_children = NULL,
|
||||
.restack_xwayland_surface = NULL,
|
||||
.cleanup_when_disabled = scene_node_cleanup_when_disabled,
|
||||
};
|
||||
|
||||
struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent,
|
||||
int width, int height, const float color[static 4]) {
|
||||
assert(parent);
|
||||
assert(width >= 0 && height >= 0);
|
||||
|
||||
struct wlr_scene_rect *scene_rect = calloc(1, sizeof(*scene_rect));
|
||||
if (scene_rect == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_scene_node_init(&scene_rect->node, &scene_node_impl, parent);
|
||||
|
||||
scene_rect->width = width;
|
||||
scene_rect->height = height;
|
||||
memcpy(scene_rect->color, color, sizeof(scene_rect->color));
|
||||
|
||||
wlr_scene_node_update(&scene_rect->node, NULL);
|
||||
|
||||
return scene_rect;
|
||||
}
|
||||
|
||||
void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height) {
|
||||
if (rect->width == width && rect->height == height) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(width >= 0 && height >= 0);
|
||||
|
||||
rect->width = width;
|
||||
rect->height = height;
|
||||
wlr_scene_node_update(&rect->node, NULL);
|
||||
}
|
||||
|
||||
void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]) {
|
||||
if (memcmp(rect->color, color, sizeof(rect->color)) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(rect->color, color, sizeof(rect->color));
|
||||
wlr_scene_node_update(&rect->node, NULL);
|
||||
}
|
||||
|
||||
bool wlr_scene_node_is_rect(const struct wlr_scene_node *node) {
|
||||
return node->impl == &scene_node_impl;
|
||||
}
|
||||
|
||||
struct wlr_scene_rect *wlr_scene_rect_from_node(struct wlr_scene_node *node) {
|
||||
assert(node->impl == &scene_node_impl);
|
||||
|
||||
struct wlr_scene_rect *scene_rect =
|
||||
wl_container_of(node, scene_rect, node);
|
||||
|
||||
return scene_rect;
|
||||
}
|
||||
352
types/scene/wlr_scene_tree.c
Normal file
352
types/scene/wlr_scene_tree.c
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
#include <wlr/types/wlr_scene_tree.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/util/region.h>
|
||||
#include <wlr/util/transform.h>
|
||||
#include "types/wlr_output.h"
|
||||
#include "types/wlr_scene.h"
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-util.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <wlr/config.h>
|
||||
|
||||
static void scene_node_visibility(struct wlr_scene_node *node,
|
||||
pixman_region32_t *visible);
|
||||
|
||||
static void scene_node_destroy(struct wlr_scene_node *node) {
|
||||
struct wlr_scene *scene = node->scene;
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
|
||||
if (scene_tree == scene->tree) {
|
||||
assert(!node->parent);
|
||||
struct wlr_scene_output *scene_output, *scene_output_tmp;
|
||||
wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) {
|
||||
wlr_scene_output_destroy(scene_output);
|
||||
}
|
||||
|
||||
wl_list_remove(&scene->linux_dmabuf_v1_destroy.link);
|
||||
wl_list_remove(&scene->gamma_control_manager_v1_destroy.link);
|
||||
wl_list_remove(&scene->gamma_control_manager_v1_set_gamma.link);
|
||||
} else {
|
||||
assert(node->parent);
|
||||
}
|
||||
|
||||
struct wlr_scene_node *child, *child_tmp;
|
||||
wl_list_for_each_safe(child, child_tmp,
|
||||
&scene_tree->children, link) {
|
||||
wlr_scene_node_destroy(child);
|
||||
}
|
||||
|
||||
free(scene_tree);
|
||||
}
|
||||
|
||||
struct node_at_data {
|
||||
double lx, ly;
|
||||
double rx, ry;
|
||||
struct wlr_scene_node *node;
|
||||
};
|
||||
|
||||
static bool scene_node_at_iterator(struct wlr_scene_node *node,
|
||||
int lx, int ly, void *data) {
|
||||
struct node_at_data *at_data = data;
|
||||
|
||||
double rx = at_data->lx - lx;
|
||||
double ry = at_data->ly - ly;
|
||||
|
||||
at_data->rx = rx;
|
||||
at_data->ry = ry;
|
||||
at_data->node = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct wlr_scene_node *scene_node_at(struct wlr_scene_node *node,
|
||||
double lx, double ly, double *nx, double *ny) {
|
||||
struct wlr_box box = {
|
||||
.x = floor(lx),
|
||||
.y = floor(ly),
|
||||
.width = 1,
|
||||
.height = 1
|
||||
};
|
||||
|
||||
struct node_at_data data = {
|
||||
.lx = lx,
|
||||
.ly = ly
|
||||
};
|
||||
|
||||
if (wlr_scene_node_nodes_in_box(node, &box, scene_node_at_iterator, &data)) {
|
||||
if (nx) {
|
||||
*nx = data.rx;
|
||||
}
|
||||
if (ny) {
|
||||
*ny = data.ry;
|
||||
}
|
||||
return data.node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void scene_node_bounds(struct wlr_scene_node *node,
|
||||
int x, int y, pixman_region32_t *visible) {
|
||||
if (!node->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
wlr_scene_node_bounds(child, x + child->x, y + child->y, visible);
|
||||
}
|
||||
}
|
||||
|
||||
static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
|
||||
scene_node_box_iterator_func_t iterator, void *user_data, int lx, int ly) {
|
||||
if (!node->enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each_reverse(child, &scene_tree->children, link) {
|
||||
if (wlr_scene_node_nodes_in_box(child, box, iterator, user_data)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
|
||||
scene_node_box_iterator_func_t iterator, void *user_data) {
|
||||
int x, y;
|
||||
wlr_scene_node_coords(node, &x, &y);
|
||||
|
||||
return _scene_nodes_in_box(node, box, iterator, user_data, x, y);
|
||||
}
|
||||
|
||||
static void scale_region(pixman_region32_t *region, float scale, bool round_up) {
|
||||
wlr_region_scale(region, region, scale);
|
||||
|
||||
if (round_up && floor(scale) != scale) {
|
||||
wlr_region_expand(region, region, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void scene_node_visibility(struct wlr_scene_node *node,
|
||||
pixman_region32_t *visible) {
|
||||
if (!node->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
wlr_scene_node_visibility(child, visible);
|
||||
}
|
||||
}
|
||||
|
||||
static void scene_node_send_frame_done(struct wlr_scene_node *node,
|
||||
struct wlr_scene_output *scene_output, struct timespec *now) {
|
||||
if (!node->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
wlr_scene_node_send_frame_done(child, scene_output, now);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool scene_node_invisible(struct wlr_scene_node *node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool construct_render_list_iterator(struct wlr_scene_node *node,
|
||||
int lx, int ly, void *_data) {
|
||||
struct wlr_render_list_constructor_data *data = _data;
|
||||
|
||||
if (wlr_scene_node_invisible(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pixman_region32_t intersection;
|
||||
pixman_region32_init(&intersection);
|
||||
pixman_region32_intersect_rect(&intersection, &node->visible,
|
||||
data->box.x, data->box.y,
|
||||
data->box.width, data->box.height);
|
||||
if (pixman_region32_empty(&intersection)) {
|
||||
pixman_region32_fini(&intersection);
|
||||
return false;
|
||||
}
|
||||
|
||||
pixman_region32_fini(&intersection);
|
||||
|
||||
struct wlr_render_list_entry *entry = wl_array_add(data->render_list, sizeof(*entry));
|
||||
if (entry == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*entry = (struct wlr_render_list_entry){
|
||||
.node = node,
|
||||
.x = lx,
|
||||
.y = ly,
|
||||
.highlight_transparent_region = data->highlight_transparent_region,
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void logical_to_buffer_coords(pixman_region32_t *region, const struct wlr_render_data *data,
|
||||
bool round_up) {
|
||||
enum wl_output_transform transform = wlr_output_transform_invert(data->transform);
|
||||
scale_region(region, data->scale, round_up);
|
||||
wlr_region_transform(region, region, transform, data->trans_width, data->trans_height);
|
||||
}
|
||||
|
||||
static int scale_length(int length, int offset, float scale) {
|
||||
return round((offset + length) * scale) - round(offset * scale);
|
||||
}
|
||||
|
||||
static void scale_box(struct wlr_box *box, float scale) {
|
||||
box->width = scale_length(box->width, box->x, scale);
|
||||
box->height = scale_length(box->height, box->y, scale);
|
||||
box->x = round(box->x * scale);
|
||||
box->y = round(box->y * scale);
|
||||
}
|
||||
|
||||
static void transform_output_box(struct wlr_box *box, const struct wlr_render_data *data) {
|
||||
enum wl_output_transform transform = wlr_output_transform_invert(data->transform);
|
||||
scale_box(box, data->scale);
|
||||
wlr_box_transform(box, box, transform, data->trans_width, data->trans_height);
|
||||
}
|
||||
|
||||
static void scene_node_render(struct wlr_render_list_entry *entry, const struct wlr_render_data *data) {
|
||||
struct wlr_scene_node *node = entry->node;
|
||||
|
||||
pixman_region32_t render_region;
|
||||
pixman_region32_init(&render_region);
|
||||
pixman_region32_copy(&render_region, &node->visible);
|
||||
pixman_region32_translate(&render_region, -data->logical.x, -data->logical.y);
|
||||
logical_to_buffer_coords(&render_region, data, true);
|
||||
pixman_region32_intersect(&render_region, &render_region, &data->damage);
|
||||
if (pixman_region32_empty(&render_region)) {
|
||||
pixman_region32_fini(&render_region);
|
||||
return;
|
||||
}
|
||||
|
||||
int x = entry->x - data->logical.x;
|
||||
int y = entry->y - data->logical.y;
|
||||
|
||||
struct wlr_box dst_box = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
wlr_scene_node_get_size(node, &dst_box.width, &dst_box.height);
|
||||
transform_output_box(&dst_box, data);
|
||||
|
||||
pixman_region32_t opaque;
|
||||
pixman_region32_init(&opaque);
|
||||
wlr_scene_node_opaque_region(node, x, y, &opaque);
|
||||
logical_to_buffer_coords(&opaque, data, false);
|
||||
pixman_region32_subtract(&opaque, &render_region, &opaque);
|
||||
|
||||
assert(false);
|
||||
|
||||
pixman_region32_fini(&opaque);
|
||||
pixman_region32_fini(&render_region);
|
||||
}
|
||||
|
||||
static void get_scene_node_extents(struct wlr_scene_node *node, int lx, int ly,
|
||||
int *x_min, int *y_min, int *x_max, int *y_max) {
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
wlr_scene_node_get_extents(child, lx + child->x, ly + child->y, x_min, y_min, x_max, y_max);
|
||||
}
|
||||
}
|
||||
|
||||
static struct wl_list *scene_node_get_children(struct wlr_scene_node *node) {
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
return &scene_tree->children;
|
||||
}
|
||||
|
||||
static void scene_node_cleanup_when_disabled(struct wlr_scene_node *node,
|
||||
bool xwayland_restack, struct wl_list *outputs) {
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
if (!child->enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wlr_scene_node_cleanup_when_disabled(child, xwayland_restack, outputs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct wlr_scene_node_impl scene_node_impl = {
|
||||
.destroy = scene_node_destroy,
|
||||
.set_enabled = NULL,
|
||||
.set_position = NULL,
|
||||
.bounds = scene_node_bounds,
|
||||
.get_size = NULL,
|
||||
.coords = NULL,
|
||||
.at = scene_node_at,
|
||||
.in_box = scene_nodes_in_box,
|
||||
.opaque_region = NULL,
|
||||
.update_outputs = NULL,
|
||||
.update = NULL,
|
||||
.visibility = scene_node_visibility,
|
||||
.frame_done = scene_node_send_frame_done,
|
||||
.invisible = scene_node_invisible,
|
||||
.construct_render_list_iterator = construct_render_list_iterator,
|
||||
.render = scene_node_render,
|
||||
.get_extents = get_scene_node_extents,
|
||||
.get_children = scene_node_get_children,
|
||||
.restack_xwayland_surface = NULL,
|
||||
.cleanup_when_disabled = scene_node_cleanup_when_disabled,
|
||||
};
|
||||
|
||||
static struct wlr_scene_tree *scene_tree_create(struct wlr_scene_tree *parent) {
|
||||
struct wlr_scene_tree *tree = calloc(1, sizeof(*tree));
|
||||
if (tree == NULL) {
|
||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_scene_node_init(&tree->node, &scene_node_impl, parent);
|
||||
wl_list_init(&tree->children);
|
||||
return tree;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) {
|
||||
assert(parent);
|
||||
|
||||
return scene_tree_create(parent);
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *wlr_root_scene_tree_create(struct wlr_scene *scene) {
|
||||
struct wlr_scene_tree *tree = scene_tree_create(NULL);
|
||||
tree->node.scene = scene;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
bool wlr_scene_node_is_tree(const struct wlr_scene_node *node) {
|
||||
return node->impl == &scene_node_impl;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node) {
|
||||
assert(node->impl == &scene_node_impl);
|
||||
|
||||
struct wlr_scene_tree *scene_tree =
|
||||
wl_container_of(node, scene_tree, node);
|
||||
|
||||
return scene_tree;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue