summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/render/fx_renderer/matrix.h8
-rw-r--r--include/render/pixel_format.h56
-rw-r--r--include/types/wlr_buffer.h69
-rw-r--r--include/types/wlr_output.h10
-rw-r--r--include/types/wlr_scene.h2
-rw-r--r--include/util/env.h14
-rw-r--r--include/util/time.h8
-rw-r--r--include/wlr/types/wlr_scene.h152
-rw-r--r--meson.build2
-rw-r--r--render/pixel_format.c398
-rw-r--r--tinywl/tinywl.c407
-rw-r--r--types/buffer/buffer.c43
-rw-r--r--types/meson.build6
-rw-r--r--types/output/wlr_output.c24
-rw-r--r--types/scene/layer_shell_v1.c186
-rw-r--r--types/scene/output_layout.c157
-rw-r--r--types/scene/subsurface_tree.c259
-rw-r--r--types/scene/surface.c211
-rw-r--r--types/scene/wlr_scene.c1299
-rw-r--r--types/scene/xdg_shell.c124
-rw-r--r--util/env.c2
-rw-r--r--util/time.c6
22 files changed, 1647 insertions, 1796 deletions
diff --git a/include/render/fx_renderer/matrix.h b/include/render/fx_renderer/matrix.h
index 6931e8d..c3bae42 100644
--- a/include/render/fx_renderer/matrix.h
+++ b/include/render/fx_renderer/matrix.h
@@ -3,7 +3,13 @@
#include <wlr/types/wlr_output.h>
+/**
+ * Writes a 2D orthographic projection matrix to mat of (width, height) with a
+ * specified wl_output_transform.
+ *
+ * Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied.
+ */
void matrix_projection(float mat[static 9], int width, int height,
- enum wl_output_transform transform);
+ enum wl_output_transform transform);
#endif
diff --git a/include/render/pixel_format.h b/include/render/pixel_format.h
index d045b6a..a024ff9 100644
--- a/include/render/pixel_format.h
+++ b/include/render/pixel_format.h
@@ -3,24 +3,62 @@
#include <wayland-server-protocol.h>
+/**
+ * Information about a pixel format.
+ *
+ * A pixel format is identified via its DRM four character code (see <drm_fourcc.h>).
+ *
+ * Simple formats have a block size of 1×1 pixels and bytes_per_block contains
+ * the number of bytes per pixel (including padding).
+ *
+ * Tiled formats (e.g. sub-sampled YCbCr) are described with a block size
+ * greater than 1×1 pixels. A block is a rectangle of pixels which are stored
+ * next to each other in a byte-aligned memory region.
+ */
struct wlr_pixel_format_info {
- uint32_t drm_format;
+ uint32_t drm_format;
- /* Equivalent of the format if it has an alpha channel,
- * DRM_FORMAT_INVALID (0) if NA
- */
- uint32_t opaque_substitute;
+ /* Equivalent of the format if it has an alpha channel,
+ * DRM_FORMAT_INVALID (0) if NA
+ */
+ uint32_t opaque_substitute;
- /* Bits per pixels */
- uint32_t bpp;
+ /* Bytes per block (including padding) */
+ uint32_t bytes_per_block;
+ /* Size of a block in pixels (zero for 1×1) */
+ uint32_t block_width, block_height;
- /* True if the format has an alpha channel */
- bool has_alpha;
+ /* True if the format has an alpha channel */
+ bool has_alpha;
};
+/**
+ * Get pixel format information from a DRM FourCC.
+ *
+ * NULL is returned if the pixel format is unknown.
+ */
const struct wlr_pixel_format_info *drm_get_pixel_format_info(uint32_t fmt);
+/**
+ * Get the number of pixels per block for a pixel format.
+ */
+uint32_t pixel_format_info_pixels_per_block(const struct wlr_pixel_format_info *info);
+/**
+ * Get the minimum stride for a given pixel format and width.
+ */
+int32_t pixel_format_info_min_stride(const struct wlr_pixel_format_info *info, int32_t width);
+/**
+ * Check whether a stride is large enough for a given pixel format and width.
+ */
+bool pixel_format_info_check_stride(const struct wlr_pixel_format_info *info,
+ int32_t stride, int32_t width);
+/**
+ * Convert an enum wl_shm_format to a DRM FourCC.
+ */
uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt);
+/**
+ * Convert a DRM FourCC to an enum wl_shm_format.
+ */
enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt);
#endif
diff --git a/include/types/wlr_buffer.h b/include/types/wlr_buffer.h
index 59d78e9..016cae8 100644
--- a/include/types/wlr_buffer.h
+++ b/include/types/wlr_buffer.h
@@ -3,75 +3,6 @@
#include <wlr/types/wlr_buffer.h>
-struct wlr_shm_client_buffer {
- struct wlr_buffer base;
-
- uint32_t format;
- size_t stride;
-
- // The following fields are NULL if the client has destroyed the wl_buffer
- struct wl_resource *resource;
- struct wl_shm_buffer *shm_buffer;
-
- // This is used to keep the backing storage alive after the client has
- // destroyed the wl_buffer
- struct wl_shm_pool *saved_shm_pool;
- void *saved_data;
-
- struct wl_listener resource_destroy;
- struct wl_listener release;
-};
-
-struct wlr_shm_client_buffer *shm_client_buffer_get_or_create(
- struct wl_resource *resource);
-
-/**
- * A read-only buffer that holds a data pointer.
- *
- * This is suitable for passing raw pixel data to a function that accepts a
- * wlr_buffer.
- */
-struct wlr_readonly_data_buffer {
- struct wlr_buffer base;
-
- const void *data;
- uint32_t format;
- size_t stride;
-
- void *saved_data;
-};
-
-/**
- * Wraps a read-only data pointer into a wlr_buffer. The data pointer may be
- * accessed until readonly_data_buffer_drop() is called.
- */
-struct wlr_readonly_data_buffer *readonly_data_buffer_create(uint32_t format,
- size_t stride, uint32_t width, uint32_t height, const void *data);
-/**
- * Drops ownership of the buffer (see wlr_buffer_drop() for more details) and
- * perform a copy of the data pointer if a consumer still has the buffer locked.
- */
-bool readonly_data_buffer_drop(struct wlr_readonly_data_buffer *buffer);
-
-struct wlr_dmabuf_buffer {
- struct wlr_buffer base;
- struct wlr_dmabuf_attributes dmabuf;
- bool saved;
-};
-
-/**
- * Wraps a DMA-BUF into a wlr_buffer. The DMA-BUF may be accessed until
- * dmabuf_buffer_drop() is called.
- */
-struct wlr_dmabuf_buffer *dmabuf_buffer_create(
- struct wlr_dmabuf_attributes *dmabuf);
-/**
- * Drops ownership of the buffer (see wlr_buffer_drop() for more details) and
- * takes a reference to the DMA-BUF (by dup'ing its file descriptors) if a
- * consumer still has the buffer locked.
- */
-bool dmabuf_buffer_drop(struct wlr_dmabuf_buffer *buffer);
-
/**
* Check whether a buffer is fully opaque.
*
diff --git a/include/types/wlr_output.h b/include/types/wlr_output.h
new file mode 100644
index 0000000..b239b6a
--- /dev/null
+++ b/include/types/wlr_output.h
@@ -0,0 +1,10 @@
+#ifndef TYPES_WLR_OUTPUT_H
+#define TYPES_WLR_OUTPUT_H
+
+#include <wlr/render/drm_format_set.h>
+#include <wlr/types/wlr_output.h>
+
+void output_pending_resolution(struct wlr_output *output,
+ const struct wlr_output_state *state, int *width, int *height);
+
+#endif
diff --git a/include/types/wlr_scene.h b/include/types/wlr_scene.h
index 64c11bc..80dcfd1 100644
--- a/include/types/wlr_scene.h
+++ b/include/types/wlr_scene.h
@@ -5,4 +5,6 @@
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
+void scene_surface_set_clip(struct wlr_scene_surface *surface, struct wlr_box *clip);
+
#endif
diff --git a/include/util/env.h b/include/util/env.h
index 6720fa8..e271f4b 100644
--- a/include/util/env.h
+++ b/include/util/env.h
@@ -4,8 +4,20 @@
#include <stdbool.h>
#include <unistd.h>
+/**
+ * Parse a bool from an environment variable.
+ *
+ * On success, the parsed value is returned. On error, false is returned.
+ */
bool env_parse_bool(const char *option);
-ssize_t env_parse_switch(const char *option, const char **switches);
+/**
+ * Pick a choice from an environment variable.
+ *
+ * On success, the choice index is returned. On error, zero is returned.
+ *
+ * switches is a NULL-terminated array.
+ */
+size_t env_parse_switch(const char *option, const char **switches);
#endif
diff --git a/include/util/time.h b/include/util/time.h
index 287698d..3f76aa4 100644
--- a/include/util/time.h
+++ b/include/util/time.h
@@ -1,12 +1,13 @@
#ifndef UTIL_TIME_H
#define UTIL_TIME_H
+#include <stdint.h>
#include <time.h>
/**
* Get the current time, in milliseconds.
*/
-uint32_t get_current_time_msec(void);
+int64_t get_current_time_msec(void);
/**
* Convert a timespec to milliseconds.
@@ -14,6 +15,11 @@ uint32_t get_current_time_msec(void);
int64_t timespec_to_msec(const struct timespec *a);
/**
+ * Convert a timespec to nanoseconds.
+ */
+int64_t timespec_to_nsec(const struct timespec *a);
+
+/**
* Convert nanoseconds to a timespec.
*/
void timespec_from_nsec(struct timespec *r, int64_t nsec);
diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
index 7b4c002..f52e167 100644
--- a/include/wlr/types/wlr_scene.h
+++ b/include/wlr/types/wlr_scene.h
@@ -20,21 +20,33 @@
*/
#include <pixman.h>
+#include <time.h>
#include <wayland-server-core.h>
-#include <wlr/types/wlr_compositor.h>
+#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_damage_ring.h>
#include "types/fx/shadow_data.h"
+#include <wlr/types/wlr_linux_dmabuf_v1.h>
+#include <wlr/util/addon.h>
+#include <wlr/util/box.h>
struct wlr_output;
struct wlr_output_layout;
+struct wlr_output_layout_output;
struct wlr_xdg_surface;
struct wlr_layer_surface_v1;
+struct wlr_drag_icon;
+struct wlr_surface;
struct wlr_scene_node;
struct wlr_scene_buffer;
+struct wlr_scene_output_layout;
+
+struct wlr_presentation;
+struct wlr_linux_dmabuf_v1;
+struct wlr_output_state;
typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)(
- struct wlr_scene_buffer *buffer, int sx, int sy);
+ 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);
@@ -89,10 +101,12 @@ struct wlr_scene {
// May be NULL
struct wlr_presentation *presentation;
+ struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
// private state
struct wl_listener presentation_destroy;
+ struct wl_listener linux_dmabuf_v1_destroy;
enum wlr_scene_debug_damage_option debug_damage_option;
bool direct_scanout;
@@ -106,11 +120,14 @@ struct wlr_scene_surface {
// private state
+ struct wlr_box clip;
+
struct wlr_addon addon;
+ struct wl_listener outputs_update;
struct wl_listener output_enter;
struct wl_listener output_leave;
- struct wl_listener output_present;
+ struct wl_listener output_sample;
struct wl_listener frame_done;
struct wl_listener surface_destroy;
struct wl_listener surface_commit;
@@ -123,6 +140,16 @@ struct wlr_scene_rect {
float color[4];
};
+struct wlr_scene_outputs_update_event {
+ struct wlr_scene_output **active;
+ size_t size;
+};
+
+struct wlr_scene_output_sample_event {
+ struct wlr_scene_output *output;
+ bool direct_scanout;
+};
+
/** A scene-graph node displaying a buffer */
struct wlr_scene_buffer {
struct wlr_scene_node node;
@@ -131,9 +158,10 @@ struct wlr_scene_buffer {
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_present; // struct wlr_scene_output
+ struct wl_signal output_sample; // struct wlr_scene_output_sample_event
struct wl_signal frame_done; // struct timespec
} events;
@@ -148,18 +176,20 @@ struct wlr_scene_buffer {
*/
struct wlr_scene_output *primary_output;
- // private state
-
float opacity;
int corner_radius;
struct shadow_data shadow_data;
-
- uint64_t active_outputs;
- struct wlr_texture *texture;
+ 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;
+
+ // private state
+
+ uint64_t active_outputs;
+ struct wlr_texture *texture;
+ struct wlr_linux_dmabuf_feedback_v1_init_options prev_feedback_options;
};
/** A viewport for an output in the scene-graph */
@@ -183,7 +213,6 @@ struct wlr_scene_output {
bool prev_scanout;
struct wl_listener output_commit;
- struct wl_listener output_mode;
struct wl_listener output_damage;
struct wl_listener output_needs_frame;
@@ -192,6 +221,11 @@ struct wlr_scene_output {
struct wl_array render_list;
};
+struct wlr_scene_timer {
+ int64_t pre_render_duration;
+ struct wlr_render_timer *render_timer;
+};
+
/** A layer shell scene helper */
struct wlr_scene_layer_surface_v1 {
struct wlr_scene_tree *tree;
@@ -269,6 +303,7 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
* Create a new scene-graph.
*/
struct wlr_scene *wlr_scene_create(void);
+
/**
* Handle presentation feedback for all surfaces in the scene, assuming that
* scene outputs and the scene rendering functions are used.
@@ -279,6 +314,15 @@ void wlr_scene_set_presentation(struct wlr_scene *scene,
struct wlr_presentation *presentation);
/**
+ * Handles linux_dmabuf_v1 feedback for all surfaces in the scene.
+ *
+ * Asserts that a struct wlr_linux_dmabuf_v1 hasn't already been set for the scene.
+ */
+void wlr_scene_set_linux_dmabuf_v1(struct wlr_scene *scene,
+ struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1);
+
+
+/**
* Add a node displaying nothing but its children.
*/
struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent);
@@ -295,13 +339,29 @@ 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.
*/
-struct wlr_scene_surface *wlr_scene_surface_from_buffer(
+struct wlr_scene_surface *wlr_scene_surface_try_from_buffer(
struct wlr_scene_buffer *scene_buffer);
/**
@@ -343,14 +403,14 @@ void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
* 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, pixman_region32_t *region);
+ struct wlr_buffer *buffer, const pixman_region32_t *region);
/**
* 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,
- pixman_region32_t *region);
+ const pixman_region32_t *region);
/**
* Set the source rectangle describing the region of the buffer which will be
@@ -384,6 +444,12 @@ 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);
+
+/**
* Sets the corner radius of this buffer
*/
void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer,
@@ -417,10 +483,32 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output);
*/
void wlr_scene_output_set_position(struct wlr_scene_output *scene_output,
int lx, int ly);
+
+struct wlr_scene_output_state_options {
+ struct wlr_scene_timer *timer;
+};
+
/**
* Render and commit an output.
*/
-bool wlr_scene_output_commit(struct wlr_scene_output *scene_output);
+bool wlr_scene_output_commit(struct wlr_scene_output *scene_output,
+ const struct wlr_scene_output_state_options *options);
+
+/**
+ * Render and populate given output state.
+ */
+bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
+ struct wlr_output_state *state, const struct wlr_scene_output_state_options *options);
+
+/**
+ * Retrieve the duration in nanoseconds between the last wlr_scene_output_commit() call and the end
+ * of its operations, including those on the GPU that may have finished after the call returned.
+ *
+ * Returns -1 if the duration is unavailable.
+ */
+int64_t wlr_scene_timer_get_duration_ns(struct wlr_scene_timer *timer);
+void wlr_scene_timer_finish(struct wlr_scene_timer *timer);
+
/**
* Call wlr_surface_send_frame_done() on all surfaces in the scene rendered by
* wlr_scene_output_commit() for which wlr_scene_surface.primary_output
@@ -446,15 +534,24 @@ struct wlr_scene_output *wlr_scene_get_scene_output(struct wlr_scene *scene,
/**
* Attach an output layout to a scene.
*
- * Adding, removing, or repositioning an output in the output layout
- * will respectively add, remove or reposition a corresponding
- * scene-graph output. When the output layout is destroyed, scene-graph
- * outputs which were created by this helper will be destroyed.
+ * The resulting scene output layout allows to synchronize the positions of scene
+ * outputs with the positions of corresponding layout outputs.
+ *
+ * It is automatically destroyed when the scene or the output layout is destroyed.
*/
-bool wlr_scene_attach_output_layout(struct wlr_scene *scene,
+struct wlr_scene_output_layout *wlr_scene_attach_output_layout(struct wlr_scene *scene,
struct wlr_output_layout *output_layout);
/**
+ * Add an output to the scene output layout.
+ *
+ * When the layout output is repositioned, the scene output will be repositioned
+ * accordingly.
+ */
+void wlr_scene_output_layout_add_output(struct wlr_scene_output_layout *sol,
+ struct wlr_output_layout_output *lo, struct wlr_scene_output *so);
+
+/**
* Add a node displaying a surface and all of its sub-surfaces to the
* scene-graph.
*/
@@ -462,6 +559,16 @@ struct wlr_scene_tree *wlr_scene_subsurface_tree_create(
struct wlr_scene_tree *parent, struct wlr_surface *surface);
/**
+ * Sets a cropping region for any subsurface trees that are children of this
+ * scene node. The clip coordinate space will be that of the root surface of
+ * the subsurface tree.
+ *
+ * A NULL or empty clip will disable clipping
+ */
+void wlr_scene_subsurface_tree_set_clip(struct wlr_scene_node *node,
+ struct wlr_box *clip);
+
+/**
* Add a node displaying an xdg_surface and all of its sub-surfaces to the
* scene-graph.
*
@@ -495,4 +602,11 @@ void wlr_scene_layer_surface_v1_configure(
struct wlr_scene_layer_surface_v1 *scene_layer_surface,
const struct wlr_box *full_area, struct wlr_box *usable_area);
+/**
+ * Add a node displaying a drag icon and all its sub-surfaces to the
+ * scene-graph.
+ */
+struct wlr_scene_tree *wlr_scene_drag_icon_create(
+ struct wlr_scene_tree *parent, struct wlr_drag_icon *drag_icon);
+
#endif
diff --git a/meson.build b/meson.build
index e96f2e6..a69a9c6 100644
--- a/meson.build
+++ b/meson.build
@@ -107,7 +107,7 @@ wayland_server = dependency('wayland-server',
)
wlroots_options = [ 'examples=false' ]
-wlroots_version = ['>=0.16.0', '<0.17.0']
+wlroots_version = ['>=0.17.0', '<0.18.0']
subproject(
'wlroots',
default_options: wlroots_options,
diff --git a/render/pixel_format.c b/render/pixel_format.c
index 46bcecf..e303799 100644
--- a/render/pixel_format.c
+++ b/render/pixel_format.c
@@ -1,178 +1,252 @@
-#include "render/pixel_format.h"
#include <drm_fourcc.h>
+#include <wlr/util/log.h>
+
+#include "render/pixel_format.h"
static const struct wlr_pixel_format_info pixel_format_info[] = {
- {
- .drm_format = DRM_FORMAT_XRGB8888,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 32,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_ARGB8888,
- .opaque_substitute = DRM_FORMAT_XRGB8888,
- .bpp = 32,
- .has_alpha = true,
- },
- {
- .drm_format = DRM_FORMAT_XBGR8888,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 32,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_ABGR8888,
- .opaque_substitute = DRM_FORMAT_XBGR8888,
- .bpp = 32,
- .has_alpha = true,
- },
- {
- .drm_format = DRM_FORMAT_RGBX8888,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 32,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_RGBA8888,
- .opaque_substitute = DRM_FORMAT_RGBX8888,
- .bpp = 32,
- .has_alpha = true,
- },
- {
- .drm_format = DRM_FORMAT_BGRX8888,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 32,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_BGRA8888,
- .opaque_substitute = DRM_FORMAT_BGRX8888,
- .bpp = 32,
- .has_alpha = true,
- },
- {
- .drm_format = DRM_FORMAT_BGR888,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 24,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_RGBX4444,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 16,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_RGBA4444,
- .opaque_substitute = DRM_FORMAT_RGBX4444,
- .bpp = 16,
- .has_alpha = true,
- },
- {
- .drm_format = DRM_FORMAT_RGBX5551,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 16,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_RGBA5551,
- .opaque_substitute = DRM_FORMAT_RGBX5551,
- .bpp = 16,
- .has_alpha = true,
- },
- {
- .drm_format = DRM_FORMAT_RGB565,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 16,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_BGR565,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 16,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_XRGB2101010,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 32,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_ARGB2101010,
- .opaque_substitute = DRM_FORMAT_XRGB2101010,
- .bpp = 32,
- .has_alpha = true,
- },
- {
- .drm_format = DRM_FORMAT_XBGR2101010,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 32,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_ABGR2101010,
- .opaque_substitute = DRM_FORMAT_XBGR2101010,
- .bpp = 32,
- .has_alpha = true,
- },
- {
- .drm_format = DRM_FORMAT_XBGR16161616F,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 64,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_ABGR16161616F,
- .opaque_substitute = DRM_FORMAT_XBGR16161616F,
- .bpp = 64,
- .has_alpha = true,
- },
- {
- .drm_format = DRM_FORMAT_XBGR16161616,
- .opaque_substitute = DRM_FORMAT_INVALID,
- .bpp = 64,
- .has_alpha = false,
- },
- {
- .drm_format = DRM_FORMAT_ABGR16161616,
- .opaque_substitute = DRM_FORMAT_XBGR16161616,
- .bpp = 64,
- .has_alpha = true,
- },
+ {
+ .drm_format = DRM_FORMAT_XRGB8888,
+ .bytes_per_block = 4,
+ },
+ {
+ .drm_format = DRM_FORMAT_ARGB8888,
+ .opaque_substitute = DRM_FORMAT_XRGB8888,
+ .bytes_per_block = 4,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_XBGR8888,
+ .bytes_per_block = 4,
+ },
+ {
+ .drm_format = DRM_FORMAT_ABGR8888,
+ .opaque_substitute = DRM_FORMAT_XBGR8888,
+ .bytes_per_block = 4,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_RGBX8888,
+ .bytes_per_block = 4,
+ },
+ {
+ .drm_format = DRM_FORMAT_RGBA8888,
+ .opaque_substitute = DRM_FORMAT_RGBX8888,
+ .bytes_per_block = 4,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_BGRX8888,
+ .bytes_per_block = 4,
+ },
+ {
+ .drm_format = DRM_FORMAT_BGRA8888,
+ .opaque_substitute = DRM_FORMAT_BGRX8888,
+ .bytes_per_block = 4,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_R8,
+ .bytes_per_block = 1,
+ },
+ {
+ .drm_format = DRM_FORMAT_GR88,
+ .bytes_per_block = 2,
+ },
+ {
+ .drm_format = DRM_FORMAT_RGB888,
+ .bytes_per_block = 3,
+ },
+ {
+ .drm_format = DRM_FORMAT_BGR888,
+ .bytes_per_block = 3,
+ },
+ {
+ .drm_format = DRM_FORMAT_RGBX4444,
+ .bytes_per_block = 2,
+ },
+ {
+ .drm_format = DRM_FORMAT_RGBA4444,
+ .opaque_substitute = DRM_FORMAT_RGBX4444,
+ .bytes_per_block = 2,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_BGRX4444,
+ .bytes_per_block = 2,
+ },
+ {
+ .drm_format = DRM_FORMAT_BGRA4444,
+ .opaque_substitute = DRM_FORMAT_BGRX4444,
+ .bytes_per_block = 2,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_RGBX5551,
+ .bytes_per_block = 2,
+ },
+ {
+ .drm_format = DRM_FORMAT_RGBA5551,
+ .opaque_substitute = DRM_FORMAT_RGBX5551,
+ .bytes_per_block = 2,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_BGRX5551,
+ .bytes_per_block = 2,
+ },
+ {
+ .drm_format = DRM_FORMAT_BGRA5551,
+ .opaque_substitute = DRM_FORMAT_BGRX5551,
+ .bytes_per_block = 2,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_XRGB1555,
+ .bytes_per_block = 2,
+ },
+ {
+ .drm_format = DRM_FORMAT_ARGB1555,
+ .opaque_substitute = DRM_FORMAT_XRGB1555,
+ .bytes_per_block = 2,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_RGB565,
+ .bytes_per_block = 2,
+ },
+ {
+ .drm_format = DRM_FORMAT_BGR565,
+ .bytes_per_block = 2,
+ },
+ {
+ .drm_format = DRM_FORMAT_XRGB2101010,
+ .bytes_per_block = 4,
+ },
+ {
+ .drm_format = DRM_FORMAT_ARGB2101010,
+ .opaque_substitute = DRM_FORMAT_XRGB2101010,
+ .bytes_per_block = 4,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_XBGR2101010,
+ .bytes_per_block = 4,
+ },
+ {
+ .drm_format = DRM_FORMAT_ABGR2101010,
+ .opaque_substitute = DRM_FORMAT_XBGR2101010,
+ .bytes_per_block = 4,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_XBGR16161616F,
+ .bytes_per_block = 8,
+ },
+ {
+ .drm_format = DRM_FORMAT_ABGR16161616F,
+ .opaque_substitute = DRM_FORMAT_XBGR16161616F,
+ .bytes_per_block = 8,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_XBGR16161616,
+ .bytes_per_block = 8,
+ },
+ {
+ .drm_format = DRM_FORMAT_ABGR16161616,
+ .opaque_substitute = DRM_FORMAT_XBGR16161616,
+ .bytes_per_block = 8,
+ .has_alpha = true,
+ },
+ {
+ .drm_format = DRM_FORMAT_YVYU,
+ .bytes_per_block = 4,
+ .block_width = 2,
+ .block_height = 1,
+ },
+ {
+ .drm_format = DRM_FORMAT_VYUY,
+ .bytes_per_block = 4,
+ .block_width = 2,
+ .block_height = 1,
+ },
};
static const size_t pixel_format_info_size =
- sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
+ sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
const struct wlr_pixel_format_info *drm_get_pixel_format_info(uint32_t fmt) {
- for (size_t i = 0; i < pixel_format_info_size; ++i) {
- if (pixel_format_info[i].drm_format == fmt) {
- return &pixel_format_info[i];
- }
- }
+ for (size_t i = 0; i < pixel_format_info_size; ++i) {
+ if (pixel_format_info[i].drm_format == fmt) {
+ return &pixel_format_info[i];
+ }
+ }
- return NULL;
+ return NULL;
}
uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
- switch (fmt) {
- case WL_SHM_FORMAT_XRGB8888:
- return DRM_FORMAT_XRGB8888;
- case WL_SHM_FORMAT_ARGB8888:
- return DRM_FORMAT_ARGB8888;
- default:
- return (uint32_t)fmt;
- }
+ switch (fmt) {
+ case WL_SHM_FORMAT_XRGB8888:
+ return DRM_FORMAT_XRGB8888;
+ case WL_SHM_FORMAT_ARGB8888:
+ return DRM_FORMAT_ARGB8888;
+ default:
+ return (uint32_t)fmt;
+ }
}
enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
- switch (fmt) {
- case DRM_FORMAT_XRGB8888:
- return WL_SHM_FORMAT_XRGB8888;
- case DRM_FORMAT_ARGB8888:
- return WL_SHM_FORMAT_ARGB8888;
- default:
- return (enum wl_shm_format)fmt;
- }
+ switch (fmt) {
+ case DRM_FORMAT_XRGB8888:
+ return WL_SHM_FORMAT_XRGB8888;
+ case DRM_FORMAT_ARGB8888:
+ return WL_SHM_FORMAT_ARGB8888;
+ default:
+ return (enum wl_shm_format)fmt;
+ }
+}
+
+uint32_t pixel_format_info_pixels_per_block(const struct wlr_pixel_format_info *info) {
+ uint32_t pixels = info->block_width * info->block_height;
+ return pixels > 0 ? pixels : 1;
+}
+
+static int32_t div_round_up(int32_t dividend, int32_t divisor) {
+ int32_t quotient = dividend / divisor;
+ if (dividend % divisor != 0) {
+ quotient++;
+ }
+ return quotient;
+}
+
+int32_t pixel_format_info_min_stride(const struct wlr_pixel_format_info *fmt, int32_t width) {
+ int32_t pixels_per_block = (int32_t)pixel_format_info_pixels_per_block(fmt);
+ int32_t bytes_per_block = (int32_t)fmt->bytes_per_block;
+ if (width > INT32_MAX / bytes_per_block) {
+ wlr_log(WLR_DEBUG, "Invalid width %d (overflow)", width);
+ return 0;
+ }
+ return div_round_up(width * bytes_per_block, pixels_per_block);
+}
+
+bool pixel_format_info_check_stride(const struct wlr_pixel_format_info *fmt,
+ int32_t stride, int32_t width) {
+ int32_t bytes_per_block = (int32_t)fmt->bytes_per_block;
+ if (stride % bytes_per_block != 0) {
+ wlr_log(WLR_DEBUG, "Invalid stride %d (incompatible with %d "
+ "bytes-per-block)", stride, bytes_per_block);
+ return false;
+ }
+
+ int32_t min_stride = pixel_format_info_min_stride(fmt, width);
+ if (min_stride <= 0) {
+ return false;
+ } else if (stride < min_stride) {
+ wlr_log(WLR_DEBUG, "Invalid stride %d (too small for %d "
+ "bytes-per-block and width %d)", stride, bytes_per_block, width);
+ return false;
+ }
+
+ return true;
}
diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c
index 56091e3..adc7b38 100644
--- a/tinywl/tinywl.c
+++ b/tinywl/tinywl.c
@@ -42,10 +42,11 @@ struct tinywl_server {
struct wlr_renderer *renderer;
struct wlr_allocator *allocator;
struct wlr_scene *scene;
+ struct wlr_scene_output_layout *scene_layout;
struct wlr_xdg_shell *xdg_shell;
struct wl_listener new_xdg_surface;
- struct wl_list views;
+ struct wl_list toplevels;
struct wlr_cursor *cursor;
struct wlr_xcursor_manager *cursor_mgr;
@@ -61,7 +62,7 @@ struct tinywl_server {
struct wl_listener request_set_selection;
struct wl_list keyboards;
enum tinywl_cursor_mode cursor_mode;
- struct tinywl_view *grabbed_view;
+ struct tinywl_toplevel *grabbed_toplevel;
double grab_x, grab_y;
struct wlr_box grab_geobox;
uint32_t resize_edges;
@@ -76,10 +77,11 @@ struct tinywl_output {
struct tinywl_server *server;
struct wlr_output *wlr_output;
struct wl_listener frame;
+ struct wl_listener request_state;
struct wl_listener destroy;
};
-struct tinywl_view {
+struct tinywl_toplevel {
struct wl_list link;
struct tinywl_server *server;
struct wlr_xdg_toplevel *xdg_toplevel;
@@ -91,9 +93,6 @@ struct tinywl_view {
struct wl_listener request_resize;
struct wl_listener request_maximize;
struct wl_listener request_fullscreen;
- int x, y;
-
- struct wlr_addon addon;
float opacity;
int corner_radius;
@@ -110,50 +109,12 @@ struct tinywl_keyboard {
struct wl_listener destroy;
};
-static void tinywl_view_destroy(struct tinywl_view *view) {
- wl_list_remove(&view->map.link);
- wl_list_remove(&view->unmap.link);
- wl_list_remove(&view->destroy.link);
- wl_list_remove(&view->request_move.link);
- wl_list_remove(&view->request_resize.link);
- wl_list_remove(&view->request_maximize.link);
- wl_list_remove(&view->request_fullscreen.link);
-
- free(view);
-}
-
-static void tinywl_view_addon_handle_destroy(struct wlr_addon *addon) {
- struct tinywl_view *view = wl_container_of(addon, view, addon);
-
- tinywl_view_destroy(view);
-}
-static const struct wlr_addon_interface tinywl_view_addon_impl = {
- .name = "tinywl_view",
- .destroy = tinywl_view_addon_handle_destroy,
-};
-
-static void tinywl_view_addon_assign(struct tinywl_view *view, struct wlr_addon_set *addons,
- const void * owner) {
- wlr_addon_init(&view->addon, addons, owner, &tinywl_view_addon_impl);
-}
-
-static struct tinywl_view *tinywl_view_addon_get(struct wlr_addon_set *addons,
- const void * owner) {
- struct wlr_addon *addon =
- wlr_addon_find(addons, owner, &tinywl_view_addon_impl);
- if (addon == NULL) {
- return NULL;
- }
- struct tinywl_view *view = wl_container_of(addon, view, addon);
- return view;
-}
-
-static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) {
+static void focus_toplevel(struct tinywl_toplevel *toplevel, struct wlr_surface *surface) {
/* Note: this function only deals with keyboard focus. */
- if (view == NULL) {
+ if (toplevel == NULL) {
return;
}
- struct tinywl_server *server = view->server;
+ struct tinywl_server *server = toplevel->server;
struct wlr_seat *seat = server->seat;
struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface;
if (prev_surface == surface) {
@@ -166,25 +127,26 @@ static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) {
* it no longer has focus and the client will repaint accordingly, e.g.
* stop displaying a caret.
*/
- struct wlr_xdg_surface *previous = wlr_xdg_surface_from_wlr_surface(
- seat->keyboard_state.focused_surface);
- assert(previous->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- wlr_xdg_toplevel_set_activated(previous->toplevel, false);
+ struct wlr_xdg_toplevel *prev_toplevel =
+ wlr_xdg_toplevel_try_from_wlr_surface(prev_surface);
+ if (prev_toplevel != NULL) {
+ wlr_xdg_toplevel_set_activated(prev_toplevel, false);
+ }
}
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat);
- /* Move the view to the front */
- wlr_scene_node_raise_to_top(&view->scene_tree->node);
- wl_list_remove(&view->link);
- wl_list_insert(&server->views, &view->link);
+ /* Move the toplevel to the front */
+ wlr_scene_node_raise_to_top(&toplevel->scene_tree->node);
+ wl_list_remove(&toplevel->link);
+ wl_list_insert(&server->toplevels, &toplevel->link);
/* Activate the new surface */
- wlr_xdg_toplevel_set_activated(view->xdg_toplevel, true);
+ wlr_xdg_toplevel_set_activated(toplevel->xdg_toplevel, true);
/*
* Tell the seat to have the keyboard enter this surface. wlroots will keep
* track of this and automatically send key events to the appropriate
* clients without additional work on your part.
*/
if (keyboard != NULL) {
- wlr_seat_keyboard_notify_enter(seat, view->xdg_toplevel->base->surface,
+ wlr_seat_keyboard_notify_enter(seat, toplevel->xdg_toplevel->base->surface,
keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
}
}
@@ -220,13 +182,13 @@ static bool handle_keybinding(struct tinywl_server *server, xkb_keysym_t sym) {
wl_display_terminate(server->wl_display);
break;
case XKB_KEY_F1:
- /* Cycle to the next view */
- if (wl_list_length(&server->views) < 2) {
+ /* Cycle to the next toplevel */
+ if (wl_list_length(&server->toplevels) < 2) {
break;
}
- struct tinywl_view *next_view = wl_container_of(
- server->views.prev, next_view, link);
- focus_view(next_view, next_view->xdg_toplevel->base->surface);
+ struct tinywl_toplevel *next_toplevel =
+ wl_container_of(server->toplevels.prev, next_toplevel, link);
+ focus_toplevel(next_toplevel, next_toplevel->xdg_toplevel->base->surface);
break;
default:
return false;
@@ -287,8 +249,7 @@ static void server_new_keyboard(struct tinywl_server *server,
struct wlr_input_device *device) {
struct wlr_keyboard *wlr_keyboard = wlr_keyboard_from_input_device(device);
- struct tinywl_keyboard *keyboard =
- calloc(1, sizeof(struct tinywl_keyboard));
+ struct tinywl_keyboard *keyboard = calloc(1, sizeof(*keyboard));
keyboard->server = server;
keyboard->wlr_keyboard = wlr_keyboard;
@@ -382,12 +343,12 @@ static void seat_request_set_selection(struct wl_listener *listener, void *data)
wlr_seat_set_selection(server->seat, event->source, event->serial);
}
-static struct tinywl_view *desktop_view_at(
+static struct tinywl_toplevel *desktop_toplevel_at(
struct tinywl_server *server, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
/* This returns the topmost node in the scene at the given layout coords.
- * we only care about surface nodes as we are specifically looking for a
- * surface in the surface tree of a tinywl_view. */
+ * 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) {
@@ -395,13 +356,13 @@ static struct tinywl_view *desktop_view_at(
}
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
struct wlr_scene_surface *scene_surface =
- wlr_scene_surface_from_buffer(scene_buffer);
+ wlr_scene_surface_try_from_buffer(scene_buffer);
if (!scene_surface) {
return NULL;
}
*surface = scene_surface->surface;
- /* Find the node corresponding to the tinywl_view at the root of this
+ /* Find the node corresponding to the tinywl_toplevel at the root of this
* surface tree, it is the only one for which we set the data field. */
struct wlr_scene_tree *tree = node->parent;
while (tree != NULL && tree->node.data == NULL) {
@@ -413,29 +374,29 @@ static struct tinywl_view *desktop_view_at(
static void reset_cursor_mode(struct tinywl_server *server) {
/* Reset the cursor mode to passthrough. */
server->cursor_mode = TINYWL_CURSOR_PASSTHROUGH;
- server->grabbed_view = NULL;
+ server->grabbed_toplevel = NULL;
}
static void process_cursor_move(struct tinywl_server *server, uint32_t time) {
- /* Move the grabbed view to the new position. */
- struct tinywl_view *view = server->grabbed_view;
- view->x = server->cursor->x - server->grab_x;
- view->y = server->cursor->y - server->grab_y;
- wlr_scene_node_set_position(&view->scene_tree->node, view->x, view->y);
+ /* Move the grabbed toplevel to the new position. */
+ struct tinywl_toplevel *toplevel = server->grabbed_toplevel;
+ wlr_scene_node_set_position(&toplevel->scene_tree->node,
+ server->cursor->x - server->grab_x,
+ server->cursor->y - server->grab_y);
}
static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
/*
- * Resizing the grabbed view can be a little bit complicated, because we
- * could be resizing from any corner or edge. This not only resizes the view
- * on one or two axes, but can also move the view if you resize from the top
- * or left edges (or top-left corner).
+ * Resizing the grabbed toplevel can be a little bit complicated, because we
+ * could be resizing from any corner or edge. This not only resizes the
+ * toplevel on one or two axes, but can also move the toplevel if you resize
+ * from the top or left edges (or top-left corner).
*
- * Note that I took some shortcuts here. In a more fleshed-out compositor,
- * you'd wait for the client to prepare a buffer at the new size, then
- * commit any movement that was prepared.
+ * Note that some shortcuts are taken here. In a more fleshed-out
+ * compositor, you'd wait for the client to prepare a buffer at the new
+ * size, then commit any movement that was prepared.
*/
- struct tinywl_view *view = server->grabbed_view;
+ struct tinywl_toplevel *toplevel = server->grabbed_toplevel;
double border_x = server->cursor->x - server->grab_x;
double border_y = server->cursor->y - server->grab_y;
int new_left = server->grab_geobox.x;
@@ -467,14 +428,13 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
}
struct wlr_box geo_box;
- wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
- view->x = new_left - geo_box.x;
- view->y = new_top - geo_box.y;
- wlr_scene_node_set_position(&view->scene_tree->node, view->x, view->y);
+ wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
+ wlr_scene_node_set_position(&toplevel->scene_tree->node,
+ new_left - geo_box.x, new_top - geo_box.y);
int new_width = new_right - new_left;
int new_height = new_bottom - new_top;
- wlr_xdg_toplevel_set_size(view->xdg_toplevel, new_width, new_height);
+ wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, new_width, new_height);
}
static void process_cursor_motion(struct tinywl_server *server, uint32_t time) {
@@ -487,18 +447,17 @@ static void process_cursor_motion(struct tinywl_server *server, uint32_t time) {
return;
}
- /* Otherwise, find the view under the pointer and send the event along. */
+ /* Otherwise, find the toplevel under the pointer and send the event along. */
double sx, sy;
struct wlr_seat *seat = server->seat;
struct wlr_surface *surface = NULL;
- struct tinywl_view *view = desktop_view_at(server,
+ struct tinywl_toplevel *toplevel = desktop_toplevel_at(server,
server->cursor->x, server->cursor->y, &surface, &sx, &sy);
- if (!view) {
- /* If there's no view under the cursor, set the cursor image to a
+ if (!toplevel) {
+ /* If there's no toplevel under the cursor, set the cursor image to a
* default. This is what makes the cursor image appear when you move it
- * around the screen, not over any views. */
- wlr_xcursor_manager_set_cursor_image(
- server->cursor_mgr, "left_ptr", server->cursor);
+ * around the screen, not over any toplevels. */
+ wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "default");
}
if (surface) {
/*
@@ -564,14 +523,14 @@ static void server_cursor_button(struct wl_listener *listener, void *data) {
event->time_msec, event->button, event->state);
double sx, sy;
struct wlr_surface *surface = NULL;
- struct tinywl_view *view = desktop_view_at(server,
+ struct tinywl_toplevel *toplevel = desktop_toplevel_at(server,
server->cursor->x, server->cursor->y, &surface, &sx, &sy);
if (event->state == WLR_BUTTON_RELEASED) {
/* If you released any buttons, we exit interactive move/resize mode. */
reset_cursor_mode(server);
} else {
/* Focus that client if the button was _pressed_ */
- focus_view(view, surface);
+ focus_toplevel(toplevel, surface);
}
}
@@ -599,47 +558,45 @@ static void server_cursor_frame(struct wl_listener *listener, void *data) {
}
static void output_configure_scene(struct wlr_scene_node *node,
- struct tinywl_view *view) {
+ struct tinywl_toplevel *toplevel) {
if (!node->enabled) {
return;
}
- struct tinywl_view *_view = tinywl_view_addon_get(&node->addons, node);
- if (_view) {
- view = _view;
+ struct tinywl_toplevel *_toplevel = node->data;
+ if (_toplevel) {
+ toplevel = _toplevel;
}
if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
- struct wlr_scene_surface * scene_surface
- = wlr_scene_surface_from_buffer(buffer);
+ struct wlr_scene_surface * scene_surface =
+ wlr_scene_surface_try_from_buffer(buffer);
if (!scene_surface) {
return;
}
- struct wlr_xdg_surface *xdg_surface = NULL;
- if (wlr_surface_is_xdg_surface(scene_surface->surface)) {
- xdg_surface = wlr_xdg_surface_from_wlr_surface(scene_surface->surface);
- }
+ struct wlr_xdg_surface *xdg_surface =
+ wlr_xdg_surface_try_from_wlr_surface(scene_surface->surface);
- if (view &&
+ if (toplevel &&
xdg_surface &&
xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
// TODO: Be able to set whole decoration_data instead of calling
// each individually?
- wlr_scene_buffer_set_opacity(buffer, view->opacity);
+ wlr_scene_buffer_set_opacity(buffer, toplevel->opacity);
- if (!wlr_surface_is_subsurface(xdg_surface->surface)) {
- wlr_scene_buffer_set_corner_radius(buffer, view->corner_radius);
- wlr_scene_buffer_set_shadow_data(buffer, view->shadow_data);
+ if (!wlr_subsurface_try_from_wlr_surface(xdg_surface->surface)) {
+ wlr_scene_buffer_set_corner_radius(buffer, toplevel->corner_radius);
+ wlr_scene_buffer_set_shadow_data(buffer, toplevel->shadow_data);
}
}
} else if (node->type == WLR_SCENE_NODE_TREE) {
struct wlr_scene_tree *tree = wl_container_of(node, tree, node);
struct wlr_scene_node *node;
wl_list_for_each(node, &tree->children, link) {
- output_configure_scene(node, view);
+ output_configure_scene(node, toplevel);
}
}
}
@@ -656,17 +613,27 @@ static void output_frame(struct wl_listener *listener, void *data) {
output_configure_scene(&scene_output->scene->tree.node, NULL);
/* Render the scene if needed and commit the output */
- wlr_scene_output_commit(scene_output);
+ wlr_scene_output_commit(scene_output, NULL);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_scene_output_send_frame_done(scene_output, &now);
}
+static void output_request_state(struct wl_listener *listener, void *data) {
+ /* This function is called when the backend requests a new state for
+ * the output. For example, Wayland and X11 backends request a new mode
+ * when the output window is resized. */
+ struct tinywl_output *output = wl_container_of(listener, output, request_state);
+ const struct wlr_output_event_request_state *event = data;
+ wlr_output_commit_state(output->wlr_output, event->state);
+}
+
static void output_destroy(struct wl_listener *listener, void *data) {
struct tinywl_output *output = wl_container_of(listener, output, destroy);
wl_list_remove(&output->frame.link);
+ wl_list_remove(&output->request_state.link);
wl_list_remove(&output->destroy.link);
wl_list_remove(&output->link);
free(output);
@@ -683,30 +650,39 @@ static void server_new_output(struct wl_listener *listener, void *data) {
* and our renderer. Must be done once, before commiting the output */
wlr_output_init_render(wlr_output, server->allocator, server->renderer);
+ /* The output may be disabled, switch it on. */
+ struct wlr_output_state state;
+ wlr_output_state_init(&state);
+ wlr_output_state_set_enabled(&state, true);
+
/* Some backends don't have modes. DRM+KMS does, and we need to set a mode
* before we can use the output. The mode is a tuple of (width, height,
* refresh rate), and each monitor supports only a specific set of modes. We
* just pick the monitor's preferred mode, a more sophisticated compositor
* would let the user configure it. */
- if (!wl_list_empty(&wlr_output->modes)) {
- struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
- wlr_output_set_mode(wlr_output, mode);
- wlr_output_enable(wlr_output, true);
- if (!wlr_output_commit(wlr_output)) {
- return;
- }
+ struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
+ if (mode != NULL) {
+ wlr_output_state_set_mode(&state, mode);
}
+ /* Atomically applies the new output state. */
+ wlr_output_commit_state(wlr_output, &state);
+ wlr_output_state_finish(&state);
+
/* Allocates and configures our state for this output */
- struct tinywl_output *output =
- calloc(1, sizeof(struct tinywl_output));
+ struct tinywl_output *output = calloc(1, sizeof(*output));
output->wlr_output = wlr_output;
output->server = server;
- /* Sets up a listener for the frame notify event. */
+
+ /* Sets up a listener for the frame event. */
output->frame.notify = output_frame;
wl_signal_add(&wlr_output->events.frame, &output->frame);
- /* Sets up a listener for the destroy notify event. */
+ /* Sets up a listener for the state request event. */
+ output->request_state.notify = output_request_state;
+ wl_signal_add(&wlr_output->events.request_state, &output->request_state);
+
+ /* Sets up a listener for the destroy event. */
output->destroy.notify = output_destroy;
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
@@ -721,70 +697,81 @@ static void server_new_output(struct wl_listener *listener, void *data) {
* display, which Wayland clients can see to find out information about the
* output (such as DPI, scale factor, manufacturer, etc).
*/
- wlr_output_layout_add_auto(server->output_layout, wlr_output);
+ struct wlr_output_layout_output *l_output = wlr_output_layout_add_auto(server->output_layout,
+ wlr_output);
+ struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output);
+ wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output);
}
static void xdg_toplevel_map(struct wl_listener *listener, void *data) {
/* Called when the surface is mapped, or ready to display on-screen. */
- struct tinywl_view *view = wl_container_of(listener, view, map);
+ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, map);
- wl_list_insert(&view->server->views, &view->link);
+ wl_list_insert(&toplevel->server->toplevels, &toplevel->link);
- focus_view(view, view->xdg_toplevel->base->surface);
+ focus_toplevel(toplevel, toplevel->xdg_toplevel->base->surface);
}
static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) {
/* Called when the surface is unmapped, and should no longer be shown. */
- struct tinywl_view *view = wl_container_of(listener, view, unmap);
+ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, unmap);
- /* Reset the cursor mode if the grabbed view was unmapped. */
- if (view == view->server->grabbed_view) {
- reset_cursor_mode(view->server);
+ /* Reset the cursor mode if the grabbed toplevel was unmapped. */
+ if (toplevel == toplevel->server->grabbed_toplevel) {
+ reset_cursor_mode(toplevel->server);
}
- wl_list_remove(&view->link);
+ wl_list_remove(&toplevel->link);
}
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) {
- /* Called when the surface is destroyed and should never be shown again. */
- struct tinywl_view *view = wl_container_of(listener, view, destroy);
-
- tinywl_view_destroy(view);
+ /* Called when the xdg_toplevel is destroyed. */
+ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, destroy);
+
+ wl_list_remove(&toplevel->map.link);
+ wl_list_remove(&toplevel->unmap.link);
+ wl_list_remove(&toplevel->destroy.link);
+ wl_list_remove(&toplevel->request_move.link);
+ wl_list_remove(&toplevel->request_resize.link);
+ wl_list_remove(&toplevel->request_maximize.link);
+ wl_list_remove(&toplevel->request_fullscreen.link);
+
+ free(toplevel);
}
-static void begin_interactive(struct tinywl_view *view,
+static void begin_interactive(struct tinywl_toplevel *toplevel,
enum tinywl_cursor_mode mode, uint32_t edges) {
/* This function sets up an interactive move or resize operation, where the
* compositor stops propegating pointer events to clients and instead
* consumes them itself, to move or resize windows. */
- struct tinywl_server *server = view->server;
+ struct tinywl_server *server = toplevel->server;
struct wlr_surface *focused_surface =
server->seat->pointer_state.focused_surface;
- if (view->xdg_toplevel->base->surface !=
+ if (toplevel->xdg_toplevel->base->surface !=
wlr_surface_get_root_surface(focused_surface)) {
/* Deny move/resize requests from unfocused clients. */
return;
}
- server->grabbed_view = view;
+ server->grabbed_toplevel = toplevel;
server->cursor_mode = mode;
if (mode == TINYWL_CURSOR_MOVE) {
- server->grab_x = server->cursor->x - view->x;
- server->grab_y = server->cursor->y - view->y;
+ server->grab_x = server->cursor->x - toplevel->scene_tree->node.x;
+ server->grab_y = server->cursor->y - toplevel->scene_tree->node.y;
} else {
struct wlr_box geo_box;
- wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
+ wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
- double border_x = (view->x + geo_box.x) +
+ double border_x = (toplevel->scene_tree->node.x + geo_box.x) +
((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
- double border_y = (view->y + geo_box.y) +
+ double border_y = (toplevel->scene_tree->node.y + geo_box.y) +
((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0);
server->grab_x = server->cursor->x - border_x;
server->grab_y = server->cursor->y - border_y;
server->grab_geobox = geo_box;
- server->grab_geobox.x += view->x;
- server->grab_geobox.y += view->y;
+ server->grab_geobox.x += toplevel->scene_tree->node.x;
+ server->grab_geobox.y += toplevel->scene_tree->node.y;
server->resize_edges = edges;
}
@@ -797,8 +784,8 @@ static void xdg_toplevel_request_move(
* decorations. Note that a more sophisticated compositor should check the
* provided serial against a list of button press serials sent to this
* client, to prevent the client from requesting this whenever they want. */
- struct tinywl_view *view = wl_container_of(listener, view, request_move);
- begin_interactive(view, TINYWL_CURSOR_MOVE, 0);
+ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, request_move);
+ begin_interactive(toplevel, TINYWL_CURSOR_MOVE, 0);
}
static void xdg_toplevel_request_resize(
@@ -809,8 +796,8 @@ static void xdg_toplevel_request_resize(
* provided serial against a list of button press serials sent to this
* client, to prevent the client from requesting this whenever they want. */
struct wlr_xdg_toplevel_resize_event *event = data;
- struct tinywl_view *view = wl_container_of(listener, view, request_resize);
- begin_interactive(view, TINYWL_CURSOR_RESIZE, event->edges);
+ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, request_resize);
+ begin_interactive(toplevel, TINYWL_CURSOR_RESIZE, event->edges);
}
static void xdg_toplevel_request_maximize(
@@ -820,17 +807,17 @@ static void xdg_toplevel_request_maximize(
* client-side decorations. tinywl doesn't support maximization, but
* to conform to xdg-shell protocol we still must send a configure.
* wlr_xdg_surface_schedule_configure() is used to send an empty reply. */
- struct tinywl_view *view =
- wl_container_of(listener, view, request_maximize);
- wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base);
+ struct tinywl_toplevel *toplevel =
+ wl_container_of(listener, toplevel, request_maximize);
+ wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
}
static void xdg_toplevel_request_fullscreen(
struct wl_listener *listener, void *data) {
/* Just as with request_maximize, we must send a configure here. */
- struct tinywl_view *view =
- wl_container_of(listener, view, request_fullscreen);
- wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base);
+ struct tinywl_toplevel *toplevel =
+ wl_container_of(listener, toplevel, request_fullscreen);
+ wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
}
static void server_new_xdg_surface(struct wl_listener *listener, void *data) {
@@ -846,8 +833,9 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) {
* we always set the user data field of xdg_surfaces to the corresponding
* scene node. */
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
- struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(
- xdg_surface->popup->parent);
+ struct wlr_xdg_surface *parent =
+ wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
+ assert(parent != NULL);
struct wlr_scene_tree *parent_tree = parent->data;
xdg_surface->data = wlr_scene_xdg_surface_create(
parent_tree, xdg_surface);
@@ -855,46 +843,42 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) {
}
assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- /* Allocate a tinywl_view for this surface */
- struct tinywl_view *view =
- calloc(1, sizeof(struct tinywl_view));
- view->server = server;
- view->xdg_toplevel = xdg_surface->toplevel;
- view->scene_tree = wlr_scene_xdg_surface_create(
- &view->server->scene->tree, view->xdg_toplevel->base);
- view->scene_tree->node.data = view;
- xdg_surface->data = view->scene_tree;
-
- /* Add the view to the trees addon */
- tinywl_view_addon_assign(view, &view->scene_tree->node.addons, &view->scene_tree->node);
+ /* Allocate a tinywl_toplevel for this surface */
+ struct tinywl_toplevel *toplevel = calloc(1, sizeof(*toplevel));
+ toplevel->server = server;
+ toplevel->xdg_toplevel = xdg_surface->toplevel;
+ toplevel->scene_tree = wlr_scene_xdg_surface_create(
+ &toplevel->server->scene->tree, toplevel->xdg_toplevel->base);
+ toplevel->scene_tree->node.data = toplevel;
+ xdg_surface->data = toplevel->scene_tree;
/* Set the scene_nodes decoration data */
- view->opacity = 1;
- view->corner_radius = 20;
- view->shadow_data = shadow_data_get_default();
- view->shadow_data.enabled = true;
- memcpy(view->shadow_data.color, (float[]) {1.0f, 0.0f, 0.0f, 1.0f}, sizeof(float[4]));
+ toplevel->opacity = 1;
+ toplevel->corner_radius = 20;
+ toplevel->shadow_data = shadow_data_get_default();
+ toplevel->shadow_data.enabled = true;
+ memcpy(toplevel->shadow_data.color, (float[]) {1.0f, 0.0f, 0.0f, 1.0f}, sizeof(float[4]));
/* Listen to the various events it can emit */
- view->map.notify = xdg_toplevel_map;
- wl_signal_add(&xdg_surface->events.map, &view->map);
- view->unmap.notify = xdg_toplevel_unmap;
- wl_signal_add(&xdg_surface->events.unmap, &view->unmap);
- view->destroy.notify = xdg_toplevel_destroy;
- wl_signal_add(&xdg_surface->events.destroy, &view->destroy);
+ toplevel->map.notify = xdg_toplevel_map;
+ wl_signal_add(&xdg_surface->surface->events.map, &toplevel->map);
+ toplevel->unmap.notify = xdg_toplevel_unmap;
+ wl_signal_add(&xdg_surface->surface->events.unmap, &toplevel->unmap);
+ toplevel->destroy.notify = xdg_toplevel_destroy;
+ wl_signal_add(&xdg_surface->events.destroy, &toplevel->destroy);
/* cotd */
- struct wlr_xdg_toplevel *toplevel = xdg_surface->toplevel;
- view->request_move.notify = xdg_toplevel_request_move;
- wl_signal_add(&toplevel->events.request_move, &view->request_move);
- view->request_resize.notify = xdg_toplevel_request_resize;
- wl_signal_add(&toplevel->events.request_resize, &view->request_resize);
- view->request_maximize.notify = xdg_toplevel_request_maximize;
- wl_signal_add(&toplevel->events.request_maximize,
- &view->request_maximize);
- view->request_fullscreen.notify = xdg_toplevel_request_fullscreen;
- wl_signal_add(&toplevel->events.request_fullscreen,
- &view->request_fullscreen);
+ struct wlr_xdg_toplevel *xdg_toplevel = xdg_surface->toplevel;
+ toplevel->request_move.notify = xdg_toplevel_request_move;
+ wl_signal_add(&xdg_toplevel->events.request_move, &toplevel->request_move);
+ toplevel->request_resize.notify = xdg_toplevel_request_resize;
+ wl_signal_add(&xdg_toplevel->events.request_resize, &toplevel->request_resize);
+ toplevel->request_maximize.notify = xdg_toplevel_request_maximize;
+ wl_signal_add(&xdg_toplevel->events.request_maximize,
+ &toplevel->request_maximize);
+ toplevel->request_fullscreen.notify = xdg_toplevel_request_fullscreen;
+ wl_signal_add(&xdg_toplevel->events.request_fullscreen,
+ &toplevel->request_fullscreen);
}
int main(int argc, char *argv[]) {
@@ -917,7 +901,7 @@ int main(int argc, char *argv[]) {
return 0;
}
- struct tinywl_server server;
+ struct tinywl_server server = {0};
/* The Wayland display is managed by libwayland. It handles accepting
* clients from the Unix socket, manging Wayland globals, and so on. */
server.wl_display = wl_display_create();
@@ -925,7 +909,7 @@ int main(int argc, char *argv[]) {
* output hardware. The autocreate option will choose the most suitable
* backend based on the current environment, such as opening an X11 window
* if an X11 server is running. */
- server.backend = wlr_backend_autocreate(server.wl_display);
+ server.backend = wlr_backend_autocreate(server.wl_display, NULL);
if (server.backend == NULL) {
wlr_log(WLR_ERROR, "failed to create wlr_backend");
return 1;
@@ -947,7 +931,7 @@ int main(int argc, char *argv[]) {
* The allocator is the bridge between the renderer and the backend. It
* handles the buffer creation, allowing wlroots to render onto the
* screen */
- server.allocator = wlr_allocator_autocreate(server.backend,
+ server.allocator = wlr_allocator_autocreate(server.backend,
server.renderer);
if (server.allocator == NULL) {
wlr_log(WLR_ERROR, "failed to create wlr_allocator");
@@ -961,7 +945,7 @@ int main(int argc, char *argv[]) {
* to dig your fingers in and play with their behavior if you want. Note that
* the clients cannot set the selection directly without compositor approval,
* see the handling of the request_set_selection event below.*/
- wlr_compositor_create(server.wl_display, server.renderer);
+ wlr_compositor_create(server.wl_display, 5, server.renderer);
wlr_subcompositor_create(server.wl_display);
wlr_data_device_manager_create(server.wl_display);
@@ -982,15 +966,13 @@ int main(int argc, char *argv[]) {
* necessary.
*/
server.scene = wlr_scene_create();
- wlr_scene_attach_output_layout(server.scene, server.output_layout);
+ server.scene_layout = wlr_scene_attach_output_layout(server.scene, server.output_layout);
/* Set up xdg-shell version 3. The xdg-shell is a Wayland protocol which is
- * used for application windows. For more detail on shells, refer to my
- * article:
- *
- * https://drewdevault.com/2018/07/29/Wayland-shells.html
+ * used for application windows. For more detail on shells, refer to
+ * https://drewdevault.com/2018/07/29/Wayland-shells.html.
*/
- wl_list_init(&server.views);
+ wl_list_init(&server.toplevels);
server.xdg_shell = wlr_xdg_shell_create(server.wl_display, 3);
server.new_xdg_surface.notify = server_new_xdg_surface;
wl_signal_add(&server.xdg_shell->events.new_surface,
@@ -1006,19 +988,16 @@ int main(int argc, char *argv[]) {
/* Creates an xcursor manager, another wlroots utility which loads up
* Xcursor themes to source cursor images from and makes sure that cursor
* images are available at all scale factors on the screen (necessary for
- * HiDPI support). We add a cursor theme at scale factor 1 to begin with. */
+ * HiDPI support). */
server.cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
- wlr_xcursor_manager_load(server.cursor_mgr, 1);
/*
* wlr_cursor *only* displays an image on screen. It does not move around
* when the pointer moves. However, we can attach input devices to it, and
* it will generate aggregate events for all of them. In these events, we
* can choose how we want to process them, forwarding them to clients and
- * moving the cursor around. More detail on this process is described in my
- * input handling blog post:
- *
- * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html
+ * moving the cursor around. More detail on this process is described in
+ * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html.
*
* And more comments are sprinkled throughout the notify functions above.
*/
@@ -1083,8 +1062,12 @@ int main(int argc, char *argv[]) {
socket);
wl_display_run(server.wl_display);
- /* Once wl_display_run returns, we shut down the server. */
+ /* Once wl_display_run returns, we destroy all clients then shut down the
+ * server. */
wl_display_destroy_clients(server.wl_display);
+ wlr_scene_node_destroy(&server.scene->tree.node);
+ wlr_xcursor_manager_destroy(server.cursor_mgr);
+ wlr_output_layout_destroy(server.output_layout);
wl_display_destroy(server.wl_display);
return 0;
}
diff --git a/types/buffer/buffer.c b/types/buffer/buffer.c
index d4c47bc..5303927 100644
--- a/types/buffer/buffer.c
+++ b/types/buffer/buffer.c
@@ -2,28 +2,27 @@
#include "types/wlr_buffer.h"
bool buffer_is_opaque(struct wlr_buffer *buffer) {
- void *data;
- uint32_t format;
- size_t stride;
- struct wlr_dmabuf_attributes dmabuf;
- struct wlr_shm_attributes shm;
- if (wlr_buffer_get_dmabuf(buffer, &dmabuf)) {
- format = dmabuf.format;
- } else if (wlr_buffer_get_shm(buffer, &shm)) {
- format = shm.format;
- } else if (wlr_buffer_begin_data_ptr_access(buffer,
- WLR_BUFFER_DATA_PTR_ACCESS_READ,
- &data, &format, &stride)) {
- wlr_buffer_end_data_ptr_access(buffer);
- } else {
- return false;
- }
+ void *data;
+ uint32_t format;
+ size_t stride;
+ struct wlr_dmabuf_attributes dmabuf;
+ struct wlr_shm_attributes shm;
+ if (wlr_buffer_get_dmabuf(buffer, &dmabuf)) {
+ format = dmabuf.format;
+ } else if (wlr_buffer_get_shm(buffer, &shm)) {
+ format = shm.format;
+ } else if (wlr_buffer_begin_data_ptr_access(buffer,
+ WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) {
+ wlr_buffer_end_data_ptr_access(buffer);
+ } else {
+ return false;
+ }
- const struct wlr_pixel_format_info *format_info =
- drm_get_pixel_format_info(format);
- if (format_info == NULL) {
- return false;
- }
+ const struct wlr_pixel_format_info *format_info =
+ drm_get_pixel_format_info(format);
+ if (format_info == NULL) {
+ return false;
+ }
- return !format_info->has_alpha;
+ return !format_info->has_alpha;
}
diff --git a/types/meson.build b/types/meson.build
index b5857d0..0527b7c 100644
--- a/types/meson.build
+++ b/types/meson.build
@@ -1,10 +1,6 @@
wlr_files += files(
- 'scene/subsurface_tree.c',
- 'scene/surface.c',
+ 'output/wlr_output.c',
'scene/wlr_scene.c',
- 'scene/output_layout.c',
- 'scene/xdg_shell.c',
- 'scene/layer_shell_v1.c',
'buffer/buffer.c',
)
diff --git a/types/output/wlr_output.c b/types/output/wlr_output.c
new file mode 100644
index 0000000..43325cf
--- /dev/null
+++ b/types/output/wlr_output.c
@@ -0,0 +1,24 @@
+#define _POSIX_C_SOURCE 200809L
+#include <stdlib.h>
+
+#include "types/wlr_output.h"
+
+void output_pending_resolution(struct wlr_output *output,
+ const struct wlr_output_state *state, int *width, int *height) {
+ if (state->committed & WLR_OUTPUT_STATE_MODE) {
+ switch (state->mode_type) {
+ case WLR_OUTPUT_STATE_MODE_FIXED:
+ *width = state->mode->width;
+ *height = state->mode->height;
+ return;
+ case WLR_OUTPUT_STATE_MODE_CUSTOM:
+ *width = state->custom_mode.width;
+ *height = state->custom_mode.height;
+ return;
+ }
+ abort();
+ } else {
+ *width = output->width;
+ *height = output->height;
+ }
+}
diff --git a/types/scene/layer_shell_v1.c b/types/scene/layer_shell_v1.c
deleted file mode 100644
index 3ed616a..0000000
--- a/types/scene/layer_shell_v1.c
+++ /dev/null
@@ -1,186 +0,0 @@
-#include <stdlib.h>
-#include <wlr/types/wlr_scene.h>
-#include <wlr/types/wlr_layer_shell_v1.h>
-
-static void scene_layer_surface_handle_tree_destroy(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_layer_surface_v1 *scene_layer_surface =
- wl_container_of(listener, scene_layer_surface, tree_destroy);
- // tree and surface_node will be cleaned up by scene_node_finish
- wl_list_remove(&scene_layer_surface->tree_destroy.link);
- wl_list_remove(&scene_layer_surface->layer_surface_destroy.link);
- wl_list_remove(&scene_layer_surface->layer_surface_map.link);
- wl_list_remove(&scene_layer_surface->layer_surface_unmap.link);
- free(scene_layer_surface);
-}
-
-static void scene_layer_surface_handle_layer_surface_destroy(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_layer_surface_v1 *scene_layer_surface =
- wl_container_of(listener, scene_layer_surface, layer_surface_destroy);
- wlr_scene_node_destroy(&scene_layer_surface->tree->node);
-}
-
-static void scene_layer_surface_handle_layer_surface_map(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_layer_surface_v1 *scene_layer_surface =
- wl_container_of(listener, scene_layer_surface, layer_surface_map);
- wlr_scene_node_set_enabled(&scene_layer_surface->tree->node, true);
-}
-
-static void scene_layer_surface_handle_layer_surface_unmap(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_layer_surface_v1 *scene_layer_surface =
- wl_container_of(listener, scene_layer_surface, layer_surface_unmap);
- wlr_scene_node_set_enabled(&scene_layer_surface->tree->node, false);
-}
-
-static void layer_surface_exclusive_zone(
- struct wlr_layer_surface_v1_state *state,
- struct wlr_box *usable_area) {
- switch (state->anchor) {
- case ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP:
- case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT):
- // Anchor top
- usable_area->y += state->exclusive_zone + state->margin.top;
- usable_area->height -= state->exclusive_zone + state->margin.top;
- break;
- case ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM:
- case (ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT):
- // Anchor bottom
- usable_area->height -= state->exclusive_zone + state->margin.bottom;
- break;
- case ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT:
- case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT):
- // Anchor left
- usable_area->x += state->exclusive_zone + state->margin.left;
- usable_area->width -= state->exclusive_zone + state->margin.left;
- break;
- case ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT:
- case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT):
- // Anchor right
- usable_area->width -= state->exclusive_zone + state->margin.right;
- break;
- }
-}
-
-void wlr_scene_layer_surface_v1_configure(
- struct wlr_scene_layer_surface_v1 *scene_layer_surface,
- const struct wlr_box *full_area, struct wlr_box *usable_area) {
- struct wlr_layer_surface_v1 *layer_surface =
- scene_layer_surface->layer_surface;
- struct wlr_layer_surface_v1_state *state = &layer_surface->current;
-
- // If the exclusive zone is set to -1, the layer surface will use the
- // full area of the output, otherwise it is constrained to the
- // remaining usable area.
- struct wlr_box bounds;
- if (state->exclusive_zone == -1) {
- bounds = *full_area;
- } else {
- bounds = *usable_area;
- }
-
- struct wlr_box box = {
- .width = state->desired_width,
- .height = state->desired_height,
- };
-
- // Horizontal positioning
- if (box.width == 0) {
- box.x = bounds.x + state->margin.left;
- box.width = bounds.width -
- (state->margin.left + state->margin.right);
- } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT &&
- state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
- box.x = bounds.x + bounds.width/2 -box.width/2;
- } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
- box.x = bounds.x + state->margin.left;
- } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
- box.x = bounds.x + bounds.width - box.width - state->margin.right;
- } else {
- box.x = bounds.x + bounds.width/2 - box.width/2;
- }
-
- // Vertical positioning
- if (box.height == 0) {
- box.y = bounds.y + state->margin.top;
- box.height = bounds.height -
- (state->margin.top + state->margin.bottom);
- } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP &&
- state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
- box.y = bounds.y + bounds.height/2 - box.height/2;
- } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
- box.y = bounds.y + state->margin.top;
- } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
- box.y = bounds.y + bounds.height - box.height - state->margin.bottom;
- } else {
- box.y = bounds.y + bounds.height/2 - box.height/2;
- }
-
- wlr_scene_node_set_position(&scene_layer_surface->tree->node, box.x, box.y);
- wlr_layer_surface_v1_configure(layer_surface, box.width, box.height);
-
- if (layer_surface->mapped && state->exclusive_zone > 0) {
- layer_surface_exclusive_zone(state, usable_area);
- }
-}
-
-struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create(
- struct wlr_scene_tree *parent,
- struct wlr_layer_surface_v1 *layer_surface) {
- struct wlr_scene_layer_surface_v1 *scene_layer_surface =
- calloc(1, sizeof(*scene_layer_surface));
- if (scene_layer_surface == NULL) {
- return NULL;
- }
-
- scene_layer_surface->layer_surface = layer_surface;
-
- scene_layer_surface->tree = wlr_scene_tree_create(parent);
- if (scene_layer_surface->tree == NULL) {
- free(scene_layer_surface);
- return NULL;
- }
-
- struct wlr_scene_tree *surface_tree = wlr_scene_subsurface_tree_create(
- scene_layer_surface->tree, layer_surface->surface);
- if (surface_tree == NULL) {
- wlr_scene_node_destroy(&scene_layer_surface->tree->node);
- free(scene_layer_surface);
- return NULL;
- }
-
- scene_layer_surface->tree_destroy.notify =
- scene_layer_surface_handle_tree_destroy;
- wl_signal_add(&scene_layer_surface->tree->node.events.destroy,
- &scene_layer_surface->tree_destroy);
-
- scene_layer_surface->layer_surface_destroy.notify =
- scene_layer_surface_handle_layer_surface_destroy;
- wl_signal_add(&layer_surface->events.destroy,
- &scene_layer_surface->layer_surface_destroy);
-
- scene_layer_surface->layer_surface_map.notify =
- scene_layer_surface_handle_layer_surface_map;
- wl_signal_add(&layer_surface->events.map,
- &scene_layer_surface->layer_surface_map);
-
- scene_layer_surface->layer_surface_unmap.notify =
- scene_layer_surface_handle_layer_surface_unmap;
- wl_signal_add(&layer_surface->events.unmap,
- &scene_layer_surface->layer_surface_unmap);
-
- wlr_scene_node_set_enabled(&scene_layer_surface->tree->node,
- layer_surface->mapped);
-
- return scene_layer_surface;
-}
diff --git a/types/scene/output_layout.c b/types/scene/output_layout.c
deleted file mode 100644
index 1d1484a..0000000
--- a/types/scene/output_layout.c
+++ /dev/null
@@ -1,157 +0,0 @@
-#include <stdlib.h>
-#include <wlr/types/wlr_output_layout.h>
-#include <wlr/types/wlr_scene.h>
-
-struct wlr_scene_output_layout {
- struct wlr_output_layout *layout;
- struct wlr_scene *scene;
-
- struct wl_list outputs; // wlr_scene_output_layout_output.link
-
- struct wl_listener layout_add;
- struct wl_listener layout_change;
- struct wl_listener layout_destroy;
- struct wl_listener scene_destroy;
-};
-
-struct wlr_scene_output_layout_output {
- struct wlr_output_layout_output *layout_output;
- struct wlr_scene_output *scene_output;
-
- struct wl_list link; // wlr_scene_output_layout.outputs
-
- struct wl_listener layout_output_destroy;
- struct wl_listener scene_output_destroy;
-};
-
-static void scene_output_layout_output_destroy(
- struct wlr_scene_output_layout_output *solo) {
- wl_list_remove(&solo->layout_output_destroy.link);
- wl_list_remove(&solo->scene_output_destroy.link);
- wl_list_remove(&solo->link);
- wlr_scene_output_destroy(solo->scene_output);
- free(solo);
-}
-
-static void scene_output_layout_output_handle_layout_output_destroy(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_output_layout_output *solo =
- wl_container_of(listener, solo, layout_output_destroy);
- scene_output_layout_output_destroy(solo);
-}
-
-static void scene_output_layout_output_handle_scene_output_destroy(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_output_layout_output *solo =
- wl_container_of(listener, solo, scene_output_destroy);
- solo->scene_output = NULL;
- scene_output_layout_output_destroy(solo);
-}
-
-static void scene_output_layout_destroy(struct wlr_scene_output_layout *sol) {
- struct wlr_scene_output_layout_output *solo, *tmp;
- wl_list_for_each_safe(solo, tmp, &sol->outputs, link) {
- scene_output_layout_output_destroy(solo);
- }
- wl_list_remove(&sol->layout_add.link);
- wl_list_remove(&sol->layout_change.link);
- wl_list_remove(&sol->layout_destroy.link);
- wl_list_remove(&sol->scene_destroy.link);
- free(sol);
-}
-
-static void scene_output_layout_handle_layout_change(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_output_layout *sol =
- wl_container_of(listener, sol, layout_change);
-
- struct wlr_scene_output_layout_output *solo;
- wl_list_for_each(solo, &sol->outputs, link) {
- wlr_scene_output_set_position(solo->scene_output,
- solo->layout_output->x, solo->layout_output->y);
- }
-}
-
-static void scene_output_layout_add(struct wlr_scene_output_layout *sol,
- struct wlr_output_layout_output *lo) {
- struct wlr_scene_output_layout_output *solo = calloc(1, sizeof(*solo));
- if (solo == NULL) {
- return;
- }
-
- solo->scene_output = wlr_scene_output_create(sol->scene, lo->output);
- if (solo->scene_output == NULL) {
- free(solo);
- return;
- }
-
- solo->layout_output = lo;
-
- solo->layout_output_destroy.notify =
- scene_output_layout_output_handle_layout_output_destroy;
- wl_signal_add(&lo->events.destroy, &solo->layout_output_destroy);
-
- solo->scene_output_destroy.notify =
- scene_output_layout_output_handle_scene_output_destroy;
- wl_signal_add(&solo->scene_output->events.destroy,
- &solo->scene_output_destroy);
-
- wl_list_insert(&sol->outputs, &solo->link);
-
- wlr_scene_output_set_position(solo->scene_output, lo->x, lo->y);
-}
-
-static void scene_output_layout_handle_layout_add(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_output_layout *sol =
- wl_container_of(listener, sol, layout_add);
- struct wlr_output_layout_output *lo = data;
-
- scene_output_layout_add(sol, lo);
-}
-
-static void scene_output_layout_handle_layout_destroy(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_output_layout *sol =
- wl_container_of(listener, sol, layout_destroy);
- scene_output_layout_destroy(sol);
-}
-
-static void scene_output_layout_handle_scene_destroy(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_output_layout *sol =
- wl_container_of(listener, sol, scene_destroy);
- scene_output_layout_destroy(sol);
-}
-
-bool wlr_scene_attach_output_layout(struct wlr_scene *scene,
- struct wlr_output_layout *output_layout) {
- struct wlr_scene_output_layout *sol = calloc(1, sizeof(*sol));
- if (sol == NULL) {
- return false;
- }
-
- sol->scene = scene;
- sol->layout = output_layout;
-
- wl_list_init(&sol->outputs);
-
- sol->layout_destroy.notify = scene_output_layout_handle_layout_destroy;
- wl_signal_add(&output_layout->events.destroy, &sol->layout_destroy);
-
- sol->layout_change.notify = scene_output_layout_handle_layout_change;
- wl_signal_add(&output_layout->events.change, &sol->layout_change);
-
- sol->layout_add.notify = scene_output_layout_handle_layout_add;
- wl_signal_add(&output_layout->events.add, &sol->layout_add);
-
- sol->scene_destroy.notify = scene_output_layout_handle_scene_destroy;
- wl_signal_add(&scene->tree.node.events.destroy, &sol->scene_destroy);
-
- struct wlr_output_layout_output *lo;
- wl_list_for_each(lo, &output_layout->outputs, link) {
- scene_output_layout_add(sol, lo);
- }
-
- return true;
-}
diff --git a/types/scene/subsurface_tree.c b/types/scene/subsurface_tree.c
deleted file mode 100644
index 35420ab..0000000
--- a/types/scene/subsurface_tree.c
+++ /dev/null
@@ -1,259 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <wlr/types/wlr_scene.h>
-#include <wlr/types/wlr_subcompositor.h>
-#include <wlr/util/addon.h>
-
-/**
- * A tree for a surface and all of its child sub-surfaces.
- *
- * `tree` contains `scene_surface` and one node per sub-surface.
- */
-struct wlr_scene_subsurface_tree {
- struct wlr_scene_tree *tree;
- struct wlr_surface *surface;
- struct wlr_scene_surface *scene_surface;
-
- struct wl_listener tree_destroy;
- struct wl_listener surface_destroy;
- struct wl_listener surface_commit;
- struct wl_listener surface_new_subsurface;
-
- struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface
-
- // Only valid if the surface is a sub-surface
-
- struct wlr_addon surface_addon;
-
- struct wl_listener subsurface_destroy;
- struct wl_listener subsurface_map;
- struct wl_listener subsurface_unmap;
-};
-
-static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- wl_container_of(listener, subsurface_tree, tree_destroy);
- // tree and scene_surface will be cleaned up by scene_node_finish
- if (subsurface_tree->parent) {
- wlr_addon_finish(&subsurface_tree->surface_addon);
- wl_list_remove(&subsurface_tree->subsurface_destroy.link);
- wl_list_remove(&subsurface_tree->subsurface_map.link);
- wl_list_remove(&subsurface_tree->subsurface_unmap.link);
- }
- wl_list_remove(&subsurface_tree->tree_destroy.link);
- wl_list_remove(&subsurface_tree->surface_destroy.link);
- wl_list_remove(&subsurface_tree->surface_commit.link);
- wl_list_remove(&subsurface_tree->surface_new_subsurface.link);
- free(subsurface_tree);
-}
-
-static const struct wlr_addon_interface subsurface_tree_addon_impl;
-
-static struct wlr_scene_subsurface_tree *subsurface_tree_from_subsurface(
- struct wlr_scene_subsurface_tree *parent,
- struct wlr_subsurface *subsurface) {
- struct wlr_addon *addon = wlr_addon_find(&subsurface->surface->addons,
- parent, &subsurface_tree_addon_impl);
- assert(addon != NULL);
- struct wlr_scene_subsurface_tree *subsurface_tree =
- wl_container_of(addon, subsurface_tree, surface_addon);
- return subsurface_tree;
-}
-
-static void subsurface_tree_reconfigure(
- struct wlr_scene_subsurface_tree *subsurface_tree) {
- struct wlr_surface *surface = subsurface_tree->surface;
-
- struct wlr_scene_node *prev = NULL;
- struct wlr_subsurface *subsurface;
- wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
- current.link) {
- struct wlr_scene_subsurface_tree *child =
- subsurface_tree_from_subsurface(subsurface_tree, subsurface);
- if (prev != NULL) {
- wlr_scene_node_place_above(&child->tree->node, prev);
- }
- prev = &child->tree->node;
-
- wlr_scene_node_set_position(&child->tree->node,
- subsurface->current.x, subsurface->current.y);
- }
-
- if (prev != NULL) {
- wlr_scene_node_place_above(&subsurface_tree->scene_surface->buffer->node, prev);
- }
- prev = &subsurface_tree->scene_surface->buffer->node;
-
- wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
- current.link) {
- struct wlr_scene_subsurface_tree *child =
- subsurface_tree_from_subsurface(subsurface_tree, subsurface);
- wlr_scene_node_place_above(&child->tree->node, prev);
- prev = &child->tree->node;
-
- wlr_scene_node_set_position(&child->tree->node,
- subsurface->current.x, subsurface->current.y);
- }
-}
-
-static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- wl_container_of(listener, subsurface_tree, surface_destroy);
- wlr_scene_node_destroy(&subsurface_tree->tree->node);
-}
-
-static void subsurface_tree_handle_surface_commit(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- wl_container_of(listener, subsurface_tree, surface_commit);
-
- // TODO: only do this on subsurface order or position change
- subsurface_tree_reconfigure(subsurface_tree);
-}
-
-static void subsurface_tree_handle_subsurface_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- wl_container_of(listener, subsurface_tree, subsurface_destroy);
- wlr_scene_node_destroy(&subsurface_tree->tree->node);
-}
-
-static void subsurface_tree_handle_subsurface_map(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- wl_container_of(listener, subsurface_tree, subsurface_map);
-
- wlr_scene_node_set_enabled(&subsurface_tree->tree->node, true);
-}
-
-static void subsurface_tree_handle_subsurface_unmap(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- wl_container_of(listener, subsurface_tree, subsurface_unmap);
-
- wlr_scene_node_set_enabled(&subsurface_tree->tree->node, false);
-}
-
-static void subsurface_tree_addon_destroy(struct wlr_addon *addon) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- wl_container_of(addon, subsurface_tree, surface_addon);
- wlr_scene_node_destroy(&subsurface_tree->tree->node);
-}
-
-static const struct wlr_addon_interface subsurface_tree_addon_impl = {
- .name = "wlr_scene_subsurface_tree",
- .destroy = subsurface_tree_addon_destroy,
-};
-
-static struct wlr_scene_subsurface_tree *scene_surface_tree_create(
- struct wlr_scene_tree *parent, struct wlr_surface *surface);
-
-static bool subsurface_tree_create_subsurface(
- struct wlr_scene_subsurface_tree *parent,
- struct wlr_subsurface *subsurface) {
- struct wlr_scene_subsurface_tree *child = scene_surface_tree_create(
- parent->tree, subsurface->surface);
- if (child == NULL) {
- return false;
- }
-
- child->parent = parent;
- wlr_scene_node_set_enabled(&child->tree->node, subsurface->mapped);
-
- wlr_addon_init(&child->surface_addon, &subsurface->surface->addons,
- parent, &subsurface_tree_addon_impl);
-
- child->subsurface_destroy.notify = subsurface_tree_handle_subsurface_destroy;
- wl_signal_add(&subsurface->events.destroy, &child->subsurface_destroy);
-
- child->subsurface_map.notify = subsurface_tree_handle_subsurface_map;
- wl_signal_add(&subsurface->events.map, &child->subsurface_map);
-
- child->subsurface_unmap.notify = subsurface_tree_handle_subsurface_unmap;
- wl_signal_add(&subsurface->events.unmap, &child->subsurface_unmap);
-
- return true;
-}
-
-static void subsurface_tree_handle_surface_new_subsurface(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- wl_container_of(listener, subsurface_tree, surface_new_subsurface);
- struct wlr_subsurface *subsurface = data;
- if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) {
- wl_resource_post_no_memory(subsurface->resource);
- }
-}
-
-static struct wlr_scene_subsurface_tree *scene_surface_tree_create(
- struct wlr_scene_tree *parent, struct wlr_surface *surface) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- calloc(1, sizeof(*subsurface_tree));
- if (subsurface_tree == NULL) {
- return NULL;
- }
-
- subsurface_tree->tree = wlr_scene_tree_create(parent);
- if (subsurface_tree->tree == NULL) {
- goto error_surface_tree;
- }
-
- subsurface_tree->scene_surface =
- wlr_scene_surface_create(subsurface_tree->tree, surface);
- if (subsurface_tree->scene_surface == NULL) {
- goto error_scene_surface;
- }
-
- subsurface_tree->surface = surface;
-
- struct wlr_subsurface *subsurface;
- wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
- current.link) {
- if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) {
- goto error_scene_surface;
- }
- }
- wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
- current.link) {
- if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) {
- goto error_scene_surface;
- }
- }
-
- subsurface_tree_reconfigure(subsurface_tree);
-
- subsurface_tree->tree_destroy.notify = subsurface_tree_handle_tree_destroy;
- wl_signal_add(&subsurface_tree->tree->node.events.destroy,
- &subsurface_tree->tree_destroy);
-
- subsurface_tree->surface_destroy.notify = subsurface_tree_handle_surface_destroy;
- wl_signal_add(&surface->events.destroy, &subsurface_tree->surface_destroy);
-
- subsurface_tree->surface_commit.notify = subsurface_tree_handle_surface_commit;
- wl_signal_add(&surface->events.commit, &subsurface_tree->surface_commit);
-
- subsurface_tree->surface_new_subsurface.notify =
- subsurface_tree_handle_surface_new_subsurface;
- wl_signal_add(&surface->events.new_subsurface,
- &subsurface_tree->surface_new_subsurface);
-
- return subsurface_tree;
-
-error_scene_surface:
- wlr_scene_node_destroy(&subsurface_tree->tree->node);
-error_surface_tree:
- free(subsurface_tree);
- return NULL;
-}
-
-struct wlr_scene_tree *wlr_scene_subsurface_tree_create(
- struct wlr_scene_tree *parent, struct wlr_surface *surface) {
- struct wlr_scene_subsurface_tree *subsurface_tree =
- scene_surface_tree_create(parent, surface);
- if (subsurface_tree == NULL) {
- return NULL;
- }
- return subsurface_tree->tree;
-}
diff --git a/types/scene/surface.c b/types/scene/surface.c
deleted file mode 100644
index 553cc42..0000000
--- a/types/scene/surface.c
+++ /dev/null
@@ -1,211 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <wlr/types/wlr_scene.h>
-#include <wlr/types/wlr_presentation_time.h>
-#include "types/wlr_scene.h"
-
-static void handle_scene_buffer_output_enter(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_surface *surface =
- wl_container_of(listener, surface, output_enter);
- struct wlr_scene_output *output = data;
-
- wlr_surface_send_enter(surface->surface, output->output);
-}
-
-static void handle_scene_buffer_output_leave(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_surface *surface =
- wl_container_of(listener, surface, output_leave);
- struct wlr_scene_output *output = data;
-
- wlr_surface_send_leave(surface->surface, output->output);
-}
-
-static void handle_scene_buffer_output_present(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_surface *surface =
- wl_container_of(listener, surface, output_present);
- struct wlr_scene_output *scene_output = data;
-
- if (surface->buffer->primary_output == scene_output) {
- struct wlr_scene *root = scene_node_get_root(&surface->buffer->node);
- struct wlr_presentation *presentation = root->presentation;
-
- if (presentation) {
- wlr_presentation_surface_sampled_on_output(
- presentation, surface->surface, scene_output->output);
- }
- }
-}
-
-static void handle_scene_buffer_frame_done(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_surface *surface =
- wl_container_of(listener, surface, frame_done);
- struct timespec *now = data;
-
- wlr_surface_send_frame_done(surface->surface, now);
-}
-
-static void scene_surface_handle_surface_destroy(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_surface *surface =
- wl_container_of(listener, surface, surface_destroy);
-
- wlr_scene_node_destroy(&surface->buffer->node);
-}
-
-// This is used for wlr_scene where it unconditionally locks buffers preventing
-// reuse of the existing texture for shm clients. With the usage pattern of
-// wlr_scene surface handling, we can mark its locked buffer as safe
-// for mutation.
-static void client_buffer_mark_next_can_damage(struct wlr_client_buffer *buffer) {
- buffer->n_ignore_locks++;
-}
-
-static void scene_buffer_unmark_client_buffer(struct wlr_scene_buffer *scene_buffer) {
- if (!scene_buffer->buffer) {
- return;
- }
-
- struct wlr_client_buffer *buffer = wlr_client_buffer_get(scene_buffer->buffer);
- if (!buffer) {
- return;
- }
-
- assert(buffer->n_ignore_locks > 0);
- buffer->n_ignore_locks--;
-}
-
-static void set_buffer_with_surface_state(struct wlr_scene_buffer *scene_buffer,
- struct wlr_surface *surface) {
- struct wlr_surface_state *state = &surface->current;
-
- wlr_scene_buffer_set_opaque_region(scene_buffer, &surface->opaque_region);
-
- struct wlr_fbox src_box;
- wlr_surface_get_buffer_source_box(surface, &src_box);
- wlr_scene_buffer_set_source_box(scene_buffer, &src_box);
-
- wlr_scene_buffer_set_dest_size(scene_buffer, state->width, state->height);
- wlr_scene_buffer_set_transform(scene_buffer, state->transform);
-
- scene_buffer_unmark_client_buffer(scene_buffer);
-
- if (surface->buffer) {
- client_buffer_mark_next_can_damage(surface->buffer);
-
- wlr_scene_buffer_set_buffer_with_damage(scene_buffer,
- &surface->buffer->base, &surface->buffer_damage);
- } else {
- wlr_scene_buffer_set_buffer(scene_buffer, NULL);
- }
-}
-
-static void handle_scene_surface_surface_commit(
- struct wl_listener *listener, void *data) {
- struct wlr_scene_surface *surface =
- wl_container_of(listener, surface, surface_commit);
- struct wlr_scene_buffer *scene_buffer = surface->buffer;
-
- set_buffer_with_surface_state(scene_buffer, surface->surface);
-
- // If the surface has requested a frame done event, honour that. The
- // frame_callback_list will be populated in this case. We should only
- // schedule the frame however if the node is enabled and there is an
- // output intersecting, otherwise the frame done events would never reach
- // the surface anyway.
- int lx, ly;
- bool enabled = wlr_scene_node_coords(&scene_buffer->node, &lx, &ly);
-
- if (!wl_list_empty(&surface->surface->current.frame_callback_list) &&
- surface->buffer->primary_output != NULL && enabled) {
- wlr_output_schedule_frame(surface->buffer->primary_output->output);
- }
-}
-
-static bool scene_buffer_point_accepts_input(struct wlr_scene_buffer *scene_buffer,
- int sx, int sy) {
- struct wlr_scene_surface *scene_surface =
- wlr_scene_surface_from_buffer(scene_buffer);
-
- return wlr_surface_point_accepts_input(scene_surface->surface, sx, sy);
-}
-
-static void surface_addon_destroy(struct wlr_addon *addon) {
- struct wlr_scene_surface *surface = wl_container_of(addon, surface, addon);
-
- scene_buffer_unmark_client_buffer(surface->buffer);
-
- wlr_addon_finish(&surface->addon);
-
- wl_list_remove(&surface->output_enter.link);
- wl_list_remove(&surface->output_leave.link);
- wl_list_remove(&surface->output_present.link);
- wl_list_remove(&surface->frame_done.link);
- wl_list_remove(&surface->surface_destroy.link);
- wl_list_remove(&surface->surface_commit.link);
-
- free(surface);
-}
-
-static const struct wlr_addon_interface surface_addon_impl = {
- .name = "wlr_scene_surface",
- .destroy = surface_addon_destroy,
-};
-
-struct wlr_scene_surface *wlr_scene_surface_from_buffer(
- struct wlr_scene_buffer *scene_buffer) {
- struct wlr_addon *addon = wlr_addon_find(&scene_buffer->node.addons,
- scene_buffer, &surface_addon_impl);
- if (!addon) {
- return NULL;
- }
-
- struct wlr_scene_surface *surface = wl_container_of(addon, surface, addon);
- return surface;
-}
-
-struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent,
- struct wlr_surface *wlr_surface) {
- struct wlr_scene_surface *surface = calloc(1, sizeof(*surface));
- if (surface == NULL) {
- return NULL;
- }
-
- struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create(parent, NULL);
- if (!scene_buffer) {
- free(surface);
- return NULL;
- }
-
- surface->buffer = scene_buffer;
- surface->surface = wlr_surface;
- scene_buffer->point_accepts_input = scene_buffer_point_accepts_input;
-
- surface->output_enter.notify = handle_scene_buffer_output_enter;
- wl_signal_add(&scene_buffer->events.output_enter, &surface->output_enter);
-
- surface->output_leave.notify = handle_scene_buffer_output_leave;
- wl_signal_add(&scene_buffer->events.output_leave, &surface->output_leave);
-
- surface->output_present.notify = handle_scene_buffer_output_present;
- wl_signal_add(&scene_buffer->events.output_present, &surface->output_present);
-
- surface->frame_done.notify = handle_scene_buffer_frame_done;
- wl_signal_add(&scene_buffer->events.frame_done, &surface->frame_done);
-
- surface->surface_destroy.notify = scene_surface_handle_surface_destroy;
- wl_signal_add(&wlr_surface->events.destroy, &surface->surface_destroy);
-
- surface->surface_commit.notify = handle_scene_surface_surface_commit;
- wl_signal_add(&wlr_surface->events.commit, &surface->surface_commit);
-
- wlr_addon_init(&surface->addon, &scene_buffer->node.addons,
- scene_buffer, &surface_addon_impl);
-
- set_buffer_with_surface_state(scene_buffer, wlr_surface);
-
- return surface;
-}
diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
index 4a32a6b..fab40a5 100644
--- a/types/scene/wlr_scene.c
+++ b/types/scene/wlr_scene.c
@@ -4,18 +4,21 @@
#include <string.h>
#include <wlr/backend.h>
#include <wlr/render/gles2.h>
-#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_damage_ring.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_subcompositor.h>
+#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
+#include <wlr/render/swapchain.h>
+
#include "render/fx_renderer/fx_renderer.h"
#include "types/fx/shadow_data.h"
#include "types/wlr_buffer.h"
+#include "types/wlr_output.h"
#include "types/wlr_scene.h"
#include "util/array.h"
#include "util/env.h"
@@ -23,14 +26,13 @@
#define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250
-static struct wlr_scene_tree *scene_tree_from_node(struct wlr_scene_node *node) {
+struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node) {
assert(node->type == WLR_SCENE_NODE_TREE);
struct wlr_scene_tree *tree = wl_container_of(node, tree, node);
return tree;
}
-static struct wlr_scene_rect *scene_rect_from_node(
- struct wlr_scene_node *node) {
+struct wlr_scene_rect *wlr_scene_rect_from_node(struct wlr_scene_node *node) {
assert(node->type == WLR_SCENE_NODE_RECT);
struct wlr_scene_rect *rect = wl_container_of(node, rect, node);
return rect;
@@ -46,7 +48,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_from_node(
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) {
struct wlr_scene_tree *tree;
if (node->type == WLR_SCENE_NODE_TREE) {
- tree = scene_tree_from_node(node);
+ tree = wlr_scene_tree_from_node(node);
} else {
tree = node->parent;
}
@@ -54,15 +56,17 @@ struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) {
while (tree->node.parent != NULL) {
tree = tree->node.parent;
}
- return (struct wlr_scene *)tree;
+ struct wlr_scene *scene = wl_container_of(tree, scene, tree);
+ return scene;
}
static void scene_node_init(struct wlr_scene_node *node,
enum wlr_scene_node_type type, struct wlr_scene_tree *parent) {
- memset(node, 0, sizeof(*node));
- node->type = type;
- node->parent = parent;
- node->enabled = true;
+ *node = (struct wlr_scene_node){
+ .type = type,
+ .parent = parent,
+ .enabled = true,
+ };
wl_list_init(&node->link);
@@ -114,7 +118,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
wlr_buffer_unlock(scene_buffer->buffer);
pixman_region32_fini(&scene_buffer->opaque_region);
} else if (node->type == WLR_SCENE_NODE_TREE) {
- struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
+ struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
if (scene_tree == &scene->tree) {
assert(!node->parent);
@@ -124,6 +128,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
}
wl_list_remove(&scene->presentation_destroy.link);
+ wl_list_remove(&scene->linux_dmabuf_v1_destroy.link);
} else {
assert(node->parent);
}
@@ -142,13 +147,13 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
static void scene_tree_init(struct wlr_scene_tree *tree,
struct wlr_scene_tree *parent) {
- memset(tree, 0, sizeof(*tree));
+ *tree = (struct wlr_scene_tree){0};
scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent);
wl_list_init(&tree->children);
}
struct wlr_scene *wlr_scene_create(void) {
- struct wlr_scene *scene = calloc(1, sizeof(struct wlr_scene));
+ struct wlr_scene *scene = calloc(1, sizeof(*scene));
if (scene == NULL) {
return NULL;
}
@@ -157,6 +162,7 @@ struct wlr_scene *wlr_scene_create(void) {
wl_list_init(&scene->outputs);
wl_list_init(&scene->presentation_destroy.link);
+ wl_list_init(&scene->linux_dmabuf_v1_destroy.link);
const char *debug_damage_options[] = {
"none",
@@ -175,7 +181,7 @@ struct wlr_scene *wlr_scene_create(void) {
struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) {
assert(parent);
- struct wlr_scene_tree *tree = calloc(1, sizeof(struct wlr_scene_tree));
+ struct wlr_scene_tree *tree = calloc(1, sizeof(*tree));
if (tree == NULL) {
return NULL;
}
@@ -197,7 +203,7 @@ static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box
switch (node->type) {
case WLR_SCENE_NODE_TREE:;
- struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
+ 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 (_scene_nodes_in_box(child, box, iterator, user_data, lx + child->x, ly + child->y)) {
@@ -230,8 +236,11 @@ static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
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);
+
if (node->type == WLR_SCENE_NODE_RECT) {
- struct wlr_scene_rect *scene_rect = scene_rect_from_node(node);
+ struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
if (scene_rect->color[3] != 1) {
return;
}
@@ -242,20 +251,22 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
return;
}
- // Buffer is translucent
- if (scene_buffer->opacity != 1 || scene_buffer->corner_radius > 0) {
+ if (scene_buffer->opacity != 1) {
+ return;
+ }
+
+ if (scene_buffer->corner_radius > 0) {
return;
}
if (!buffer_is_opaque(scene_buffer->buffer)) {
pixman_region32_copy(opaque, &scene_buffer->opaque_region);
+ pixman_region32_intersect_rect(opaque, opaque, 0, 0, width, height);
pixman_region32_translate(opaque, x, y);
return;
}
}
- int width, height;
- scene_node_get_size(node, &width, &height);
pixman_region32_fini(opaque);
pixman_region32_init_rect(opaque, x, y, width, height);
}
@@ -287,6 +298,28 @@ static void scale_output_damage(pixman_region32_t *damage, float scale) {
}
}
+struct 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;
+};
+
+static void transform_output_damage(pixman_region32_t *damage, const struct render_data *data) {
+ enum wl_output_transform transform = wlr_output_transform_invert(data->transform);
+ wlr_region_transform(damage, damage, transform, data->trans_width, data->trans_height);
+}
+
+static void transform_output_box(struct wlr_box *box, const struct render_data *data) {
+ enum wl_output_transform transform = wlr_output_transform_invert(data->transform);
+ wlr_box_transform(box, box, transform, data->trans_width, data->trans_height);
+}
+
static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *damage) {
if (!pixman_region32_not_empty(damage)) {
return;
@@ -308,7 +341,8 @@ static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *dam
}
static void update_node_update_outputs(struct wlr_scene_node *node,
- struct wl_list *outputs, struct wlr_scene_output *ignore) {
+ struct wl_list *outputs, struct wlr_scene_output *ignore,
+ struct wlr_scene_output *force) {
if (node->type != WLR_SCENE_NODE_BUFFER) {
return;
}
@@ -316,8 +350,10 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
uint32_t largest_overlap = 0;
+ struct wlr_scene_output *old_primary_output = scene_buffer->primary_output;
scene_buffer->primary_output = NULL;
+ size_t count = 0;
uint64_t active_outputs = 0;
// let's update the outputs in two steps:
@@ -356,11 +392,17 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
}
active_outputs |= 1ull << scene_output->index;
+ count++;
}
pixman_region32_fini(&intersection);
}
+ if (old_primary_output != scene_buffer->primary_output) {
+ scene_buffer->prev_feedback_options =
+ (struct wlr_linux_dmabuf_feedback_v1_init_options){0};
+ }
+
uint64_t old_active = scene_buffer->active_outputs;
scene_buffer->active_outputs = active_outputs;
@@ -379,6 +421,31 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
// if there are active outputs on this node, we should always have a primary
// output
assert(!scene_buffer->active_outputs || scene_buffer->primary_output);
+
+ // Skip output update event if nothing was updated
+ if (old_active == active_outputs &&
+ (!force || ((1ull << force->index) & ~active_outputs)) &&
+ old_primary_output == scene_buffer->primary_output) {
+ return;
+ }
+
+ struct wlr_scene_output *outputs_array[64];
+ struct wlr_scene_outputs_update_event event = {
+ .active = outputs_array,
+ .size = count,
+ };
+
+ size_t i = 0;
+ wl_list_for_each(scene_output, outputs, link) {
+ if (~active_outputs & (1ull << scene_output->index)) {
+ continue;
+ }
+
+ assert(i < count);
+ outputs_array[i++] = scene_output;
+ }
+
+ wl_signal_emit_mutable(&scene_buffer->events.outputs_update, &event);
}
static bool scene_node_update_iterator(struct wlr_scene_node *node,
@@ -410,7 +477,7 @@ static bool scene_node_update_iterator(struct wlr_scene_node *node,
}
}
- update_node_update_outputs(node, data->outputs, NULL);
+ update_node_update_outputs(node, data->outputs, NULL, NULL);
return false;
}
@@ -422,7 +489,7 @@ static void scene_node_visibility(struct wlr_scene_node *node,
}
if (node->type == WLR_SCENE_NODE_TREE) {
- struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
+ 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) {
scene_node_visibility(child, visible);
@@ -440,7 +507,7 @@ static void scene_node_bounds(struct wlr_scene_node *node,
}
if (node->type == WLR_SCENE_NODE_TREE) {
- struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
+ 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) {
scene_node_bounds(child, x + child->x, y + child->y, visible);
@@ -517,8 +584,7 @@ static void scene_node_update(struct wlr_scene_node *node,
struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent,
int width, int height, const float color[static 4]) {
- struct wlr_scene_rect *scene_rect =
- calloc(1, sizeof(struct wlr_scene_rect));
+ struct wlr_scene_rect *scene_rect = calloc(1, sizeof(*scene_rect));
if (scene_rect == NULL) {
return NULL;
}
@@ -566,12 +632,12 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
scene_buffer->buffer = wlr_buffer_lock(buffer);
}
+ wl_signal_init(&scene_buffer->events.outputs_update);
wl_signal_init(&scene_buffer->events.output_enter);
wl_signal_init(&scene_buffer->events.output_leave);
- wl_signal_init(&scene_buffer->events.output_present);
+ wl_signal_init(&scene_buffer->events.output_sample);
wl_signal_init(&scene_buffer->events.frame_done);
pixman_region32_init(&scene_buffer->opaque_region);
-
scene_buffer->opacity = 1;
scene_buffer->corner_radius = 0;
scene_buffer->shadow_data = shadow_data_get_default();
@@ -582,14 +648,13 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
}
void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer,
- struct wlr_buffer *buffer, pixman_region32_t *damage) {
+ struct wlr_buffer *buffer, const pixman_region32_t *damage) {
// specifying a region for a NULL buffer doesn't make sense. We need to know
// about the buffer to scale the buffer local coordinates down to scene
// coordinates.
assert(buffer || !damage);
bool update = false;
- wlr_buffer_unlock(scene_buffer->buffer);
wlr_texture_destroy(scene_buffer->texture);
scene_buffer->texture = NULL;
@@ -603,8 +668,10 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff
(scene_buffer->buffer->width != buffer->width ||
scene_buffer->buffer->height != buffer->height));
+ wlr_buffer_unlock(scene_buffer->buffer);
scene_buffer->buffer = wlr_buffer_lock(buffer);
} else {
+ wlr_buffer_unlock(scene_buffer->buffer);
update = true;
scene_buffer->buffer = NULL;
}
@@ -694,8 +761,8 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff
pixman_region32_fini(&cull_region);
pixman_region32_translate(&output_damage,
- (lx - scene_output->x) * output_scale,
- (ly - scene_output->y) * output_scale);
+ (int)round((lx - scene_output->x) * output_scale),
+ (int)round((ly - scene_output->y) * output_scale));
if (wlr_damage_ring_add(&scene_output->damage_ring, &output_damage)) {
wlr_output_schedule_frame(scene_output->output);
}
@@ -712,27 +779,35 @@ void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
}
void wlr_scene_buffer_set_opaque_region(struct wlr_scene_buffer *scene_buffer,
- pixman_region32_t *region) {
+ const pixman_region32_t *region) {
if (pixman_region32_equal(&scene_buffer->opaque_region, region)) {
return;
}
pixman_region32_copy(&scene_buffer->opaque_region, region);
- scene_node_update(&scene_buffer->node, NULL);
+
+ int x, y;
+ if (!wlr_scene_node_coords(&scene_buffer->node, &x, &y)) {
+ return;
+ }
+
+ pixman_region32_t update_region;
+ pixman_region32_init(&update_region);
+ scene_node_bounds(&scene_buffer->node, x, y, &update_region);
+ scene_update_region(scene_node_get_root(&scene_buffer->node), &update_region);
+ pixman_region32_fini(&update_region);
}
void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer,
const struct wlr_fbox *box) {
- struct wlr_fbox *cur = &scene_buffer->src_box;
- if ((wlr_fbox_empty(box) && wlr_fbox_empty(cur)) ||
- (box != NULL && wlr_fbox_equal(cur, box))) {
+ if (wlr_fbox_equal(&scene_buffer->src_box, box)) {
return;
}
if (box != NULL) {
- memcpy(cur, box, sizeof(*box));
+ scene_buffer->src_box = *box;
} else {
- memset(cur, 0, sizeof(*cur));
+ scene_buffer->src_box = (struct wlr_fbox){0};
}
scene_node_update(&scene_buffer->node, NULL);
@@ -776,6 +851,16 @@ void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
scene_node_update(&scene_buffer->node, NULL);
}
+void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
+ enum wlr_scale_filter_mode filter_mode) {
+ if (scene_buffer->filter_mode == filter_mode) {
+ return;
+ }
+
+ scene_buffer->filter_mode = filter_mode;
+ scene_node_update(&scene_buffer->node, NULL);
+}
+
void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer,
int radii) {
if (scene_buffer->corner_radius == radii) {
@@ -826,7 +911,7 @@ static void scene_node_get_size(struct wlr_scene_node *node,
case WLR_SCENE_NODE_TREE:
return;
case WLR_SCENE_NODE_RECT:;
- struct wlr_scene_rect *scene_rect = scene_rect_from_node(node);
+ struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
*width = scene_rect->width;
*height = scene_rect->height;
break;
@@ -995,7 +1080,7 @@ static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node,
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
user_iterator(scene_buffer, lx, ly, user_data);
} else if (node->type == WLR_SCENE_NODE_TREE) {
- struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
+ 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) {
scene_node_for_each_scene_buffer(child, lx, ly, user_iterator, user_data);
@@ -1025,7 +1110,7 @@ static bool scene_node_at_iterator(struct wlr_scene_node *node,
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
if (scene_buffer->point_accepts_input &&
- !scene_buffer->point_accepts_input(scene_buffer, rx, ry)) {
+ !scene_buffer->point_accepts_input(scene_buffer, &rx, &ry)) {
return false;
}
}
@@ -1063,208 +1148,300 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
return NULL;
}
-static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) {
- struct wlr_box box = {
- .x = rect->x1,
- .y = rect->y1,
- .width = rect->x2 - rect->x1,
- .height = rect->y2 - rect->y1,
- };
-
- int ow, oh;
- wlr_output_transformed_resolution(output, &ow, &oh);
-
- enum wl_output_transform transform =
- wlr_output_transform_invert(output->transform);
- wlr_box_transform(&box, &box, transform, ow, oh);
-
- fx_renderer_scissor(&box);
-}
-
-static void render_rect(struct fx_renderer *fx_renderer, struct wlr_output *output,
- pixman_region32_t *damage, const float color[static 4],
- const struct wlr_box *box, const float matrix[static 9]) {
- assert(fx_renderer);
-
- int nrects;
- pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
- for (int i = 0; i < nrects; ++i) {
- scissor_output(output, &rects[i]);
- fx_render_rect(fx_renderer, box, color, matrix);
- }
-}
-
-static void render_texture(struct fx_renderer *fx_renderer, struct wlr_output *output,
- pixman_region32_t *damage, struct wlr_texture *texture,
- const struct wlr_fbox *src_box, const struct wlr_box *dst_box,
- const float matrix[static 9], float opacity, int corner_radius) {
- assert(fx_renderer);
-
- struct wlr_fbox default_src_box = {0};
- if (wlr_fbox_empty(src_box)) {
- default_src_box.width = texture->width;
- default_src_box.height = texture->height;
- src_box = &default_src_box;
- }
-
- // ensure the box is updated as per the output orientation
- struct wlr_box transformed_box;
- int width, height;
- wlr_output_transformed_resolution(output, &width, &height);
- wlr_box_transform(&transformed_box, dst_box,
- wlr_output_transform_invert(output->transform), width, height);
-
- int nrects;
- pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
- for (int i = 0; i < nrects; ++i) {
- scissor_output(output, &rects[i]);
-
- fx_render_subtexture_with_matrix(fx_renderer, texture, src_box,
- &transformed_box, matrix, opacity, corner_radius);
- }
-}
-
-static void render_box_shadow(struct fx_renderer *fx_renderer,
- struct wlr_output *output, pixman_region32_t *surface_damage,
- const struct wlr_box *surface_box, int corner_radius,
- struct shadow_data *shadow_data) {
- // don't damage area behind window since we dont render it anyway
- pixman_region32_t inner_region;
- pixman_region32_init(&inner_region);
- pixman_region32_union_rect(&inner_region, &inner_region,
- surface_box->x + corner_radius * 0.5,
- surface_box->y + corner_radius * 0.5,
- surface_box->width - corner_radius,
- surface_box->height - corner_radius);
- pixman_region32_intersect(&inner_region, &inner_region, surface_damage);
-
- pixman_region32_t damage;
- pixman_region32_init(&damage);
- pixman_region32_subtract(&damage, surface_damage, &inner_region);
- if (!pixman_region32_not_empty(&damage)) {
- goto damage_finish;
- }
-
- struct wlr_box shadow_box = {
- .x = surface_box->x - shadow_data->blur_sigma,
- .y = surface_box->y - shadow_data->blur_sigma,
- .width = surface_box->width + 2 * shadow_data->blur_sigma,
- .height = surface_box->height + 2 * shadow_data->blur_sigma,
- };
- float matrix[9];
- wlr_matrix_project_box(matrix, &shadow_box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
- output->transform_matrix);
-
- // ensure the box is updated as per the output orientation
- struct wlr_box transformed_box;
- int width, height;
- wlr_output_transformed_resolution(output, &width, &height);
- wlr_box_transform(&transformed_box, &shadow_box,
- wlr_output_transform_invert(output->transform), width, height);
-
- int nrects;
- pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
- for (int i = 0; i < nrects; ++i) {
- scissor_output(output, &rects[i]);
- fx_render_box_shadow(fx_renderer, &transformed_box, surface_box, matrix,
- corner_radius, shadow_data);
- }
-
-damage_finish:
- pixman_region32_fini(&damage);
- pixman_region32_fini(&inner_region);
-}
-
-static void scene_node_render(struct fx_renderer *fx_renderer, struct wlr_scene_node *node,
- struct wlr_scene_output *scene_output, pixman_region32_t *damage) {
+// static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) {
+// struct wlr_box box = {
+// .x = rect->x1,
+// .y = rect->y1,
+// .width = rect->x2 - rect->x1,
+// .height = rect->y2 - rect->y1,
+// };
+//
+// int ow, oh;
+// wlr_output_transformed_resolution(output, &ow, &oh);
+//
+// enum wl_output_transform transform =
+// wlr_output_transform_invert(output->transform);
+// wlr_box_transform(&box, &box, transform, ow, oh);
+//
+// fx_renderer_scissor(&box);
+// }
+//
+// static void render_rect(struct fx_renderer *fx_renderer, struct wlr_output *output,
+// pixman_region32_t *damage, const float color[static 4],
+// const struct wlr_box *box, const float matrix[static 9]) {
+// assert(fx_renderer);
+//
+// int nrects;
+// pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
+// for (int i = 0; i < nrects; ++i) {
+// scissor_output(output, &rects[i]);
+// fx_render_rect(fx_renderer, box, color, matrix);
+// }
+// }
+//
+// static void render_texture(struct fx_renderer *fx_renderer, struct wlr_output *output,
+// pixman_region32_t *damage, struct wlr_texture *texture,
+// const struct wlr_fbox *src_box, const struct wlr_box *dst_box,
+// const float matrix[static 9], float opacity, int corner_radius) {
+// assert(fx_renderer);
+//
+// struct wlr_fbox default_src_box = {0};
+// if (wlr_fbox_empty(src_box)) {
+// default_src_box.width = texture->width;
+// default_src_box.height = texture->height;
+// src_box = &default_src_box;
+// }
+//
+// // ensure the box is updated as per the output orientation
+// struct wlr_box transformed_box;
+// int width, height;
+// wlr_output_transformed_resolution(output, &width, &height);
+// wlr_box_transform(&transformed_box, dst_box,
+// wlr_output_transform_invert(output->transform), width, height);
+//
+// int nrects;
+// pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
+// for (int i = 0; i < nrects; ++i) {
+// scissor_output(output, &rects[i]);
+//
+// fx_render_subtexture_with_matrix(fx_renderer, texture, src_box,
+// &transformed_box, matrix, opacity, corner_radius);
+// }
+// }
+//
+// static void render_box_shadow(struct fx_renderer *fx_renderer,
+// struct wlr_output *output, pixman_region32_t *surface_damage,
+// const struct wlr_box *surface_box, int corner_radius,
+// struct shadow_data *shadow_data) {
+// // don't damage area behind window since we dont render it anyway
+// pixman_region32_t inner_region;
+// pixman_region32_init(&inner_region);
+// pixman_region32_union_rect(&inner_region, &inner_region,
+// surface_box->x + corner_radius * 0.5,
+// surface_box->y + corner_radius * 0.5,
+// surface_box->width - corner_radius,
+// surface_box->height - corner_radius);
+// pixman_region32_intersect(&inner_region, &inner_region, surface_damage);
+//
+// pixman_region32_t damage;
+// pixman_region32_init(&damage);
+// pixman_region32_subtract(&damage, surface_damage, &inner_region);
+// if (!pixman_region32_not_empty(&damage)) {
+// goto damage_finish;
+// }
+//
+// struct wlr_box shadow_box = {
+// .x = surface_box->x - shadow_data->blur_sigma,
+// .y = surface_box->y - shadow_data->blur_sigma,
+// .width = surface_box->width + 2 * shadow_data->blur_sigma,
+// .height = surface_box->height + 2 * shadow_data->blur_sigma,
+// };
+// float matrix[9];
+// wlr_matrix_project_box(matrix, &shadow_box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
+// output->transform_matrix);
+//
+// // ensure the box is updated as per the output orientation
+// struct wlr_box transformed_box;
+// int width, height;
+// wlr_output_transformed_resolution(output, &width, &height);
+// wlr_box_transform(&transformed_box, &shadow_box,
+// wlr_output_transform_invert(output->transform), width, height);
+//
+// int nrects;
+// pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
+// for (int i = 0; i < nrects; ++i) {
+// scissor_output(output, &rects[i]);
+// fx_render_box_shadow(fx_renderer, &transformed_box, surface_box, matrix,
+// corner_radius, shadow_data);
+// }
+//
+// damage_finish:
+// pixman_region32_fini(&damage);
+// pixman_region32_fini(&inner_region);
+// }
+//
+// static void scene_node_render(struct fx_renderer *fx_renderer, struct wlr_scene_node *node,
+// struct wlr_scene_output *scene_output, pixman_region32_t *damage) {
+// int x, y;
+// wlr_scene_node_coords(node, &x, &y);
+// x -= scene_output->x;
+// y -= scene_output->y;
+//
+// struct wlr_output *output = scene_output->output;
+//
+// pixman_region32_t render_region;
+// pixman_region32_init(&render_region);
+// pixman_region32_copy(&render_region, &node->visible);
+// pixman_region32_translate(&render_region, -scene_output->x, -scene_output->y);
+// scale_output_damage(&render_region, output->scale);
+// pixman_region32_intersect(&render_region, &render_region, damage);
+// if (!pixman_region32_not_empty(&render_region)) {
+// pixman_region32_fini(&render_region);
+// return;
+// }
+//
+// struct wlr_box dst_box = {
+// .x = x,
+// .y = y,
+// };
+// scene_node_get_size(node, &dst_box.width, &dst_box.height);
+// scale_box(&dst_box, output->scale);
+//
+// struct wlr_texture *texture;
+// float matrix[9];
+// enum wl_output_transform transform;
+// switch (node->type) {
+// case WLR_SCENE_NODE_TREE:
+// assert(false);
+// break;
+// case WLR_SCENE_NODE_RECT:;
+// struct wlr_scene_rect *scene_rect = scene_rect_from_node(node);
+//
+// render_rect(fx_renderer, output, &render_region, scene_rect->color, &dst_box,
+// output->transform_matrix);
+// break;
+// case WLR_SCENE_NODE_BUFFER:;
+// struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
+// assert(scene_buffer->buffer);
+//
+// struct wlr_renderer *renderer = output->renderer;
+// texture = scene_buffer_get_texture(scene_buffer, renderer);
+//
+// transform = wlr_output_transform_invert(scene_buffer->transform);
+// wlr_matrix_project_box(matrix, &dst_box, transform, 0.0,
+// output->transform_matrix);
+//
+// // Some surfaces (mostly GTK 4) decorate their windows with shadows
+// // which extends the node size past the actual window size. This gets
+// // the actual surface geometry, mostly ignoring CSD decorations
+// // but only if we need to.
+// if (scene_buffer->corner_radius != 0 ||
+// scene_buffer_has_shadow(&scene_buffer->shadow_data)) {
+// struct wlr_scene_surface *scene_surface = NULL;
+// if ((scene_surface = wlr_scene_surface_from_buffer(scene_buffer)) &&
+// wlr_surface_is_xdg_surface(scene_surface->surface)) {
+// struct wlr_xdg_surface *xdg_surface =
+// wlr_xdg_surface_from_wlr_surface(scene_surface->surface);
+//
+// struct wlr_box geometry;
+// wlr_xdg_surface_get_geometry(xdg_surface, &geometry);
+// dst_box.width = fmin(dst_box.width, geometry.width);
+// dst_box.height = fmin(dst_box.height, geometry.height);
+// dst_box.x = fmax(dst_box.x, geometry.x + x);
+// dst_box.y = fmax(dst_box.y, geometry.y + y);
+// }
+// }
+//
+// // Shadow
+// if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) {
+// // TODO: Compensate for SSD borders here
+// render_box_shadow(fx_renderer, output, &render_region, &dst_box,
+// scene_buffer->corner_radius, &scene_buffer->shadow_data);
+// }
+//
+// // Clip the damage to the dst_box before rendering the texture
+// pixman_region32_intersect_rect(&render_region, &render_region,
+// dst_box.x, dst_box.y, dst_box.width, dst_box.height);
+//
+// render_texture(fx_renderer, output, &render_region, texture, &scene_buffer->src_box,
+// &dst_box, matrix, scene_buffer->opacity, scene_buffer->corner_radius);
+//
+// wl_signal_emit_mutable(&scene_buffer->events.output_present, scene_output);
+// break;
+// }
+//
+// pixman_region32_fini(&render_region);
+// }
+
+struct render_list_entry {
+ struct wlr_scene_node *node;
+ bool sent_dmabuf_feedback;
int x, y;
- wlr_scene_node_coords(node, &x, &y);
- x -= scene_output->x;
- y -= scene_output->y;
+};
- struct wlr_output *output = scene_output->output;
+static void scene_entry_render(struct render_list_entry *entry, const struct 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, -scene_output->x, -scene_output->y);
- scale_output_damage(&render_region, output->scale);
- pixman_region32_intersect(&render_region, &render_region, damage);
+ pixman_region32_translate(&render_region, -data->logical.x, -data->logical.y);
+ scale_output_damage(&render_region, data->scale);
+ pixman_region32_intersect(&render_region, &render_region, &data->damage);
if (!pixman_region32_not_empty(&render_region)) {
pixman_region32_fini(&render_region);
return;
}
struct wlr_box dst_box = {
- .x = x,
- .y = y,
+ .x = entry->x - data->logical.x,
+ .y = entry->y - data->logical.y,
};
scene_node_get_size(node, &dst_box.width, &dst_box.height);
- scale_box(&dst_box, output->scale);
+ scale_box(&dst_box, data->scale);
+
+ pixman_region32_t opaque;
+ pixman_region32_init(&opaque);
+ scene_node_opaque_region(node, dst_box.x, dst_box.y, &opaque);
+ scale_output_damage(&opaque, data->scale);
+ pixman_region32_subtract(&opaque, &render_region, &opaque);
+
+ transform_output_box(&dst_box, data);
+ transform_output_damage(&render_region, data);
- struct wlr_texture *texture;
- float matrix[9];
- enum wl_output_transform transform;
switch (node->type) {
case WLR_SCENE_NODE_TREE:
assert(false);
break;
case WLR_SCENE_NODE_RECT:;
- struct wlr_scene_rect *scene_rect = scene_rect_from_node(node);
-
- render_rect(fx_renderer, output, &render_region, scene_rect->color, &dst_box,
- output->transform_matrix);
+ 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,
+ });
break;
case WLR_SCENE_NODE_BUFFER:;
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
assert(scene_buffer->buffer);
- struct wlr_renderer *renderer = output->renderer;
- texture = scene_buffer_get_texture(scene_buffer, renderer);
-
- transform = wlr_output_transform_invert(scene_buffer->transform);
- wlr_matrix_project_box(matrix, &dst_box, transform, 0.0,
- output->transform_matrix);
-
- // Some surfaces (mostly GTK 4) decorate their windows with shadows
- // which extends the node size past the actual window size. This gets
- // the actual surface geometry, mostly ignoring CSD decorations
- // but only if we need to.
- if (scene_buffer->corner_radius != 0 ||
- scene_buffer_has_shadow(&scene_buffer->shadow_data)) {
- struct wlr_scene_surface *scene_surface = NULL;
- if ((scene_surface = wlr_scene_surface_from_buffer(scene_buffer)) &&
- wlr_surface_is_xdg_surface(scene_surface->surface)) {
- struct wlr_xdg_surface *xdg_surface =
- wlr_xdg_surface_from_wlr_surface(scene_surface->surface);
-
- struct wlr_box geometry;
- wlr_xdg_surface_get_geometry(xdg_surface, &geometry);
- dst_box.width = fmin(dst_box.width, geometry.width);
- dst_box.height = fmin(dst_box.height, geometry.height);
- dst_box.x = fmax(dst_box.x, geometry.x + x);
- dst_box.y = fmax(dst_box.y, geometry.y + y);
- }
- }
-
- // Shadow
- if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) {
- // TODO: Compensate for SSD borders here
- render_box_shadow(fx_renderer, output, &render_region, &dst_box,
- scene_buffer->corner_radius, &scene_buffer->shadow_data);
+ struct wlr_texture *texture = scene_buffer_get_texture(scene_buffer,
+ data->output->output->renderer);
+ if (texture == NULL) {
+ break;
}
- // Clip the damage to the dst_box before rendering the texture
- pixman_region32_intersect_rect(&render_region, &render_region,
- dst_box.x, dst_box.y, dst_box.width, dst_box.height);
-
- render_texture(fx_renderer, output, &render_region, texture, &scene_buffer->src_box,
- &dst_box, matrix, scene_buffer->opacity, scene_buffer->corner_radius);
-
- wl_signal_emit_mutable(&scene_buffer->events.output_present, scene_output);
+ enum wl_output_transform transform =
+ wlr_output_transform_invert(scene_buffer->transform);
+ transform = wlr_output_transform_compose(transform, data->transform);
+
+ wlr_render_pass_add_texture(data->render_pass, &(struct wlr_render_texture_options) {
+ .texture = texture,
+ .src_box = scene_buffer->src_box,
+ .dst_box = dst_box,
+ .transform = transform,
+ .clip = &render_region,
+ .alpha = &scene_buffer->opacity,
+ .filter_mode = scene_buffer->filter_mode,
+ .blend_mode = pixman_region32_not_empty(&opaque) ?
+ WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE,
+ });
+
+ struct wlr_scene_output_sample_event sample_event = {
+ .output = data->output,
+ .direct_scanout = false,
+ };
+ wl_signal_emit_mutable(&scene_buffer->events.output_sample, &sample_event);
break;
}
+ pixman_region32_fini(&opaque);
pixman_region32_fini(&render_region);
}
@@ -1285,6 +1462,23 @@ void wlr_scene_set_presentation(struct wlr_scene *scene,
wl_signal_add(&presentation->events.destroy, &scene->presentation_destroy);
}
+static void scene_handle_linux_dmabuf_v1_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_scene *scene =
+ wl_container_of(listener, scene, linux_dmabuf_v1_destroy);
+ wl_list_remove(&scene->linux_dmabuf_v1_destroy.link);
+ wl_list_init(&scene->linux_dmabuf_v1_destroy.link);
+ scene->linux_dmabuf_v1 = NULL;
+}
+
+void wlr_scene_set_linux_dmabuf_v1(struct wlr_scene *scene,
+ struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1) {
+ assert(scene->linux_dmabuf_v1 == NULL);
+ scene->linux_dmabuf_v1 = linux_dmabuf_v1;
+ scene->linux_dmabuf_v1_destroy.notify = scene_handle_linux_dmabuf_v1_destroy;
+ wl_signal_add(&linux_dmabuf_v1->events.destroy, &scene->linux_dmabuf_v1_destroy);
+}
+
static void scene_output_handle_destroy(struct wlr_addon *addon) {
struct wlr_scene_output *scene_output =
wl_container_of(addon, scene_output, addon);
@@ -1296,50 +1490,47 @@ static const struct wlr_addon_interface output_addon_impl = {
.destroy = scene_output_handle_destroy,
};
-
static void scene_node_output_update(struct wlr_scene_node *node,
- struct wl_list *outputs, struct wlr_scene_output *ignore) {
+ struct wl_list *outputs, struct wlr_scene_output *ignore,
+ struct wlr_scene_output *force) {
if (node->type == WLR_SCENE_NODE_TREE) {
- struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
+ 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) {
- scene_node_output_update(child, outputs, ignore);
+ scene_node_output_update(child, outputs, ignore, force);
}
return;
}
- update_node_update_outputs(node, outputs, ignore);
+ update_node_update_outputs(node, outputs, ignore, force);
}
-static void scene_output_update_geometry(struct wlr_scene_output *scene_output) {
- int width, height;
- wlr_output_transformed_resolution(scene_output->output, &width, &height);
- wlr_damage_ring_set_bounds(&scene_output->damage_ring, width, height);
+static void scene_output_update_geometry(struct wlr_scene_output *scene_output,
+ bool force_update) {
+ wlr_damage_ring_add_whole(&scene_output->damage_ring);
wlr_output_schedule_frame(scene_output->output);
scene_node_output_update(&scene_output->scene->tree.node,
- &scene_output->scene->outputs, NULL);
+ &scene_output->scene->outputs, NULL, force_update ? scene_output : NULL);
}
static void scene_output_handle_commit(struct wl_listener *listener, void *data) {
struct wlr_scene_output *scene_output = wl_container_of(listener,
scene_output, output_commit);
struct wlr_output_event_commit *event = data;
+ const struct wlr_output_state *state = event->state;
- if (event->committed & (WLR_OUTPUT_STATE_MODE |
- WLR_OUTPUT_STATE_TRANSFORM |
- WLR_OUTPUT_STATE_SCALE |
+ bool force_update = state->committed & (
+ WLR_OUTPUT_STATE_TRANSFORM |
+ WLR_OUTPUT_STATE_SCALE |
+ WLR_OUTPUT_STATE_SUBPIXEL);
+
+ if (force_update || state->committed & (WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_ENABLED)) {
- scene_output_update_geometry(scene_output);
+ scene_output_update_geometry(scene_output, force_update);
}
}
-static void scene_output_handle_mode(struct wl_listener *listener, void *data) {
- struct wlr_scene_output *scene_output = wl_container_of(listener,
- scene_output, output_mode);
- scene_output_update_geometry(scene_output);
-}
-
static void scene_output_handle_damage(struct wl_listener *listener, void *data) {
struct wlr_scene_output *scene_output = wl_container_of(listener,
scene_output, output_damage);
@@ -1395,16 +1586,13 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene,
scene_output->output_commit.notify = scene_output_handle_commit;
wl_signal_add(&output->events.commit, &scene_output->output_commit);
- scene_output->output_mode.notify = scene_output_handle_mode;
- wl_signal_add(&output->events.mode, &scene_output->output_mode);
-
scene_output->output_damage.notify = scene_output_handle_damage;
wl_signal_add(&output->events.damage, &scene_output->output_damage);
scene_output->output_needs_frame.notify = scene_output_handle_needs_frame;
wl_signal_add(&output->events.needs_frame, &scene_output->output_needs_frame);
- scene_output_update_geometry(scene_output);
+ scene_output_update_geometry(scene_output, false);
return scene_output;
}
@@ -1423,18 +1611,21 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) {
wl_signal_emit_mutable(&scene_output->events.destroy, NULL);
scene_node_output_update(&scene_output->scene->tree.node,
- &scene_output->scene->outputs, scene_output);
+ &scene_output->scene->outputs, scene_output, NULL);
struct highlight_region *damage, *tmp_damage;
wl_list_for_each_safe(damage, tmp_damage, &scene_output->damage_highlight_regions, link) {
highlight_region_destroy(damage);
}
+ struct fx_renderer *fx_renderer =
+ fx_renderer_addon_find(&scene_output->output->addons, scene_output->scene);
+ wlr_addon_finish(&fx_renderer->addon);
+
wlr_addon_finish(&scene_output->addon);
wlr_damage_ring_finish(&scene_output->damage_ring);
wl_list_remove(&scene_output->link);
wl_list_remove(&scene_output->output_commit.link);
- wl_list_remove(&scene_output->output_mode.link);
wl_list_remove(&scene_output->output_damage.link);
wl_list_remove(&scene_output->output_needs_frame.link);
@@ -1463,14 +1654,14 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output,
scene_output->x = lx;
scene_output->y = ly;
- scene_output_update_geometry(scene_output);
+ scene_output_update_geometry(scene_output, false);
}
static bool scene_node_invisible(struct wlr_scene_node *node) {
if (node->type == WLR_SCENE_NODE_TREE) {
return true;
} else if (node->type == WLR_SCENE_NODE_RECT) {
- struct wlr_scene_rect *rect = scene_rect_from_node(node);
+ struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
return rect->color[3] == 0.f;
} else if (node->type == WLR_SCENE_NODE_BUFFER) {
@@ -1500,7 +1691,7 @@ static bool construct_render_list_iterator(struct wlr_scene_node *node,
// If we see a black rect, we can ignore rendering everything under the rect
// and even the rect itself.
if (node->type == WLR_SCENE_NODE_RECT && data->calculate_visibility) {
- struct wlr_scene_rect *rect = scene_rect_from_node(node);
+ 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) {
@@ -1520,16 +1711,66 @@ static bool construct_render_list_iterator(struct wlr_scene_node *node,
pixman_region32_fini(&intersection);
- struct wlr_scene_node **entry = wl_array_add(data->render_list,
- sizeof(struct wlr_scene_node *));
- if (entry) {
- *entry = node;
+ struct render_list_entry *entry = wl_array_add(data->render_list, sizeof(*entry));
+ if (!entry) {
+ return false;
}
+
+ *entry = (struct render_list_entry){
+ .node = node,
+ .x = lx,
+ .y = ly,
+ };
+
return false;
}
-static bool scene_node_try_direct_scanout(struct wlr_scene_node *node,
- struct wlr_scene_output *scene_output, struct wlr_box *box) {
+static void output_state_apply_damage(const struct render_data *data,
+ struct wlr_output_state *state) {
+ pixman_region32_t frame_damage;
+ pixman_region32_init(&frame_damage);
+ pixman_region32_copy(&frame_damage, &data->output->damage_ring.current);
+ transform_output_damage(&frame_damage, data);
+ wlr_output_state_set_damage(state, &frame_damage);
+ pixman_region32_fini(&frame_damage);
+}
+
+static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene,
+ struct wlr_scene_buffer *scene_buffer,
+ const struct wlr_linux_dmabuf_feedback_v1_init_options *options) {
+ if (!scene->linux_dmabuf_v1) {
+ return;
+ }
+
+ struct wlr_scene_surface *surface = wlr_scene_surface_try_from_buffer(scene_buffer);
+ if (!surface) {
+ return;
+ }
+
+ // compare to the previous options so that we don't send
+ // duplicate feedback events.
+ if (memcmp(options, &scene_buffer->prev_feedback_options, sizeof(*options)) == 0) {
+ return;
+ }
+
+ scene_buffer->prev_feedback_options = *options;
+
+ struct wlr_linux_dmabuf_feedback_v1 feedback = {0};
+ if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, options)) {
+ return;
+ }
+
+ wlr_linux_dmabuf_v1_set_surface_feedback(scene->linux_dmabuf_v1,
+ surface->surface, &feedback);
+
+ wlr_linux_dmabuf_feedback_v1_finish(&feedback);
+}
+
+static bool scene_entry_try_direct_scanout(struct render_list_entry *entry,
+ struct wlr_output_state *state, const struct render_data *data) {
+ struct wlr_scene_output *scene_output = data->output;
+ struct wlr_scene_node *node = entry->node;
+
if (!scene_output->scene->direct_scanout) {
return false;
}
@@ -1545,8 +1786,18 @@ static bool scene_node_try_direct_scanout(struct wlr_scene_node *node,
return false;
}
+ if (state->committed & (WLR_OUTPUT_STATE_MODE |
+ WLR_OUTPUT_STATE_ENABLED |
+ WLR_OUTPUT_STATE_RENDER_FORMAT)) {
+ // Legacy DRM will explode if we try to modeset with a direct scanout buffer
+ return false;
+ }
+
+ if (!wlr_output_is_direct_scanout_allowed(scene_output->output)) {
+ return false;
+ }
+
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
- struct wlr_output *output = scene_output->output;
struct wlr_fbox default_box = {0};
if (buffer->transform & WL_OUTPUT_TRANSFORM_90) {
@@ -1562,75 +1813,396 @@ static bool scene_node_try_direct_scanout(struct wlr_scene_node *node,
return false;
}
- if (buffer->transform != output->transform) {
+ if (buffer->transform != data->transform) {
return false;
}
- struct wlr_box node_box;
- wlr_scene_node_coords(node, &node_box.x, &node_box.y);
+ struct wlr_box node_box = { .x = entry->x, .y = entry->y };
scene_node_get_size(node, &node_box.width, &node_box.height);
- if (!wlr_box_equal(box, &node_box)) {
+ if (!wlr_box_equal(&data->logical, &node_box)) {
+ return false;
+ }
+
+ if (buffer->primary_output == scene_output) {
+ struct wlr_linux_dmabuf_feedback_v1_init_options options = {
+ .main_renderer = scene_output->output->renderer,
+ .scanout_primary_output = scene_output->output,
+ };
+
+ scene_buffer_send_dmabuf_feedback(scene_output->scene, buffer, &options);
+ entry->sent_dmabuf_feedback = true;
+ }
+
+ struct wlr_output_state pending;
+ wlr_output_state_init(&pending);
+ if (!wlr_output_state_copy(&pending, state)) {
return false;
}
- wlr_output_attach_buffer(output, buffer->buffer);
- if (!wlr_output_test(output)) {
- wlr_output_rollback(output);
+ wlr_output_state_set_buffer(&pending, buffer->buffer);
+ output_state_apply_damage(data, &pending);
+
+ if (!wlr_output_test_state(scene_output->output, &pending)) {
+ wlr_output_state_finish(&pending);
return false;
}
- return wlr_output_commit(output);
+ wlr_output_state_copy(state, &pending);
+ wlr_output_state_finish(&pending);
+
+ struct wlr_scene_output_sample_event sample_event = {
+ .output = scene_output,
+ .direct_scanout = true,
+ };
+ wl_signal_emit_mutable(&buffer->events.output_sample, &sample_event);
+ return true;
}
-bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
+// bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
+// struct wlr_output *output = scene_output->output;
+// enum wlr_scene_debug_damage_option debug_damage =
+// scene_output->scene->debug_damage_option;
+//
+// // Find the fx_renderer addon
+// struct fx_renderer *renderer =
+// fx_renderer_addon_find(&output->addons, scene_output->scene);
+// assert(renderer != NULL);
+//
+// struct render_list_constructor_data list_con = {
+// .box = { .x = scene_output->x, .y = scene_output->y },
+// .render_list = &scene_output->render_list,
+// .calculate_visibility = scene_output->scene->calculate_visibility,
+// };
+// wlr_output_effective_resolution(output,
+// &list_con.box.width, &list_con.box.height);
+//
+// list_con.render_list->size = 0;
+// scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box,
+// construct_render_list_iterator, &list_con);
+// array_realloc(list_con.render_list, list_con.render_list->size);
+//
+// int list_len = list_con.render_list->size / sizeof(struct wlr_scene_node *);
+// struct wlr_scene_node **list_data = list_con.render_list->data;
+//
+// // if there is only one thing to render let's see if that thing can be
+// // directly scanned out
+// bool scanout = false;
+// if (list_len == 1) {
+// struct wlr_scene_node *node = list_data[0];
+// scanout = scene_node_try_direct_scanout(node, scene_output, &list_con.box);
+// }
+//
+// if (scene_output->prev_scanout != scanout) {
+// scene_output->prev_scanout = scanout;
+// wlr_log(WLR_DEBUG, "Direct scan-out %s",
+// scanout ? "enabled" : "disabled");
+// // When exiting direct scan-out, damage everything
+// wlr_damage_ring_add_whole(&scene_output->damage_ring);
+// }
+//
+// if (scanout) {
+// struct wlr_scene_node *node = list_data[0];
+//
+// assert(node->type == WLR_SCENE_NODE_BUFFER);
+// struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
+// wl_signal_emit_mutable(&buffer->events.output_present, scene_output);
+// return true;
+// }
+//
+// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_RERENDER) {
+// wlr_damage_ring_add_whole(&scene_output->damage_ring);
+// }
+//
+// struct timespec now;
+// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
+// struct wl_list *regions = &scene_output->damage_highlight_regions;
+// clock_gettime(CLOCK_MONOTONIC, &now);
+//
+// // add the current frame's damage if there is damage
+// if (pixman_region32_not_empty(&scene_output->damage_ring.current)) {
+// struct highlight_region *current_damage =
+// calloc(1, sizeof(*current_damage));
+// if (current_damage) {
+// pixman_region32_init(&current_damage->region);
+// pixman_region32_copy(&current_damage->region,
+// &scene_output->damage_ring.current);
+// current_damage->when = now;
+// wl_list_insert(regions, &current_damage->link);
+// }
+// }
+//
+// pixman_region32_t acc_damage;
+// pixman_region32_init(&acc_damage);
+// struct highlight_region *damage, *tmp_damage;
+// wl_list_for_each_safe(damage, tmp_damage, regions, link) {
+// // remove overlaping damage regions
+// pixman_region32_subtract(&damage->region, &damage->region, &acc_damage);
+// pixman_region32_union(&acc_damage, &acc_damage, &damage->region);
+//
+// // if this damage is too old or has nothing in it, get rid of it
+// struct timespec time_diff;
+// timespec_sub(&time_diff, &now, &damage->when);
+// if (timespec_to_msec(&time_diff) >= HIGHLIGHT_DAMAGE_FADEOUT_TIME ||
+// !pixman_region32_not_empty(&damage->region)) {
+// highlight_region_destroy(damage);
+// }
+// }
+//
+// wlr_damage_ring_add(&scene_output->damage_ring, &acc_damage);
+// pixman_region32_fini(&acc_damage);
+// }
+//
+// int buffer_age;
+// if (!wlr_output_attach_render(output, &buffer_age)) {
+// return false;
+// }
+//
+// pixman_region32_t damage;
+// pixman_region32_init(&damage);
+// wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring,
+// buffer_age, &damage);
+// if (!output->needs_frame && !pixman_region32_not_empty(
+// &scene_output->damage_ring.current)) {
+// pixman_region32_fini(&damage);
+// wlr_output_rollback(output);
+// return true;
+// }
+//
+// fx_renderer_begin(renderer, output->width, output->height);
+//
+// pixman_region32_t background;
+// pixman_region32_init(&background);
+// pixman_region32_copy(&background, &damage);
+//
+// // Cull areas of the background that are occluded by opaque regions of
+// // scene nodes above. Those scene nodes will just render atop having us
+// // never see the background.
+// if (scene_output->scene->calculate_visibility) {
+// float output_scale = scene_output->output->scale;
+//
+// for (int i = list_len - 1; i >= 0; i--) {
+// struct wlr_scene_node *node = list_data[i];
+// int x, y;
+// wlr_scene_node_coords(node, &x, &y);
+//
+// // We must only cull opaque regions that are visible by the node.
+// // The node's visibility will have the knowledge of a black rect
+// // that may have been omitted from the render list via the black
+// // rect optimization. In order to ensure we don't cull background
+// // rendering in that black rect region, consider the node's visibility.
+// pixman_region32_t opaque;
+// pixman_region32_init(&opaque);
+// scene_node_opaque_region(node, x, y, &opaque);
+// pixman_region32_intersect(&opaque, &opaque, &node->visible);
+//
+// pixman_region32_translate(&opaque, -scene_output->x, -scene_output->y);
+// wlr_region_scale(&opaque, &opaque, output_scale);
+// pixman_region32_subtract(&background, &background, &opaque);
+// pixman_region32_fini(&opaque);
+// }
+//
+// if (floor(output_scale) != output_scale) {
+// wlr_region_expand(&background, &background, 1);
+//
+// // reintersect with the damage because we never want to render
+// // outside of the damage region
+// pixman_region32_intersect(&background, &background, &damage);
+// }
+// }
+//
+// int nrects;
+// pixman_box32_t *rects = pixman_region32_rectangles(&background, &nrects);
+// for (int i = 0; i < nrects; ++i) {
+// scissor_output(output, &rects[i]);
+// fx_renderer_clear((float[4]){ 0.0, 0.0, 0.0, 1.0 });
+// }
+// pixman_region32_fini(&background);
+//
+// for (int i = list_len - 1; i >= 0; i--) {
+// struct wlr_scene_node *node = list_data[i];
+// scene_node_render(renderer, node, scene_output, &damage);
+// }
+//
+// fx_renderer_scissor(NULL);
+//
+// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
+// struct highlight_region *damage;
+// wl_list_for_each(damage, &scene_output->damage_highlight_regions, link) {
+// struct timespec time_diff;
+// timespec_sub(&time_diff, &now, &damage->when);
+// int64_t time_diff_ms = timespec_to_msec(&time_diff);
+// float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME;
+//
+// int nrects;
+// pixman_box32_t *rects = pixman_region32_rectangles(&damage->region, &nrects);
+// for (int i = 0; i < nrects; ++i) {
+// struct wlr_box box = {
+// .x = rects[i].x1,
+// .y = rects[i].y1,
+// .width = rects[i].x2 - rects[i].x1,
+// .height = rects[i].y2 - rects[i].y1,
+// };
+//
+// float color[4] = { alpha * .5, 0.0, 0.0, alpha * .5 };
+// fx_render_rect(renderer, &box, color, output->transform_matrix);
+// }
+// }
+// }
+//
+// // Draw the software cursors
+// wlr_renderer_begin(output->renderer, output->width, output->height);
+// wlr_output_render_software_cursors(output, &damage);
+// wlr_renderer_end(output->renderer);
+//
+// pixman_region32_fini(&damage);
+//
+// int tr_width, tr_height;
+// wlr_output_transformed_resolution(output, &tr_width, &tr_height);
+//
+// enum wl_output_transform transform =
+// wlr_output_transform_invert(output->transform);
+//
+// pixman_region32_t frame_damage;
+// pixman_region32_init(&frame_damage);
+// wlr_region_transform(&frame_damage,
+// &scene_output->damage_ring.current,
+// transform, tr_width, tr_height);
+// wlr_output_set_damage(output, &frame_damage);
+// pixman_region32_fini(&frame_damage);
+//
+// bool success = wlr_output_commit(output);
+//
+// if (success) {
+// wlr_damage_ring_rotate(&scene_output->damage_ring);
+// }
+//
+// if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT &&
+// !wl_list_empty(&scene_output->damage_highlight_regions)) {
+// wlr_output_schedule_frame(scene_output->output);
+// }
+//
+// return success;
+// }
+
+bool wlr_scene_output_commit(struct wlr_scene_output *scene_output,
+ const struct wlr_scene_output_state_options *options) {
+ if (!scene_output->output->needs_frame && !pixman_region32_not_empty(
+ &scene_output->damage_ring.current)) {
+ return true;
+ }
+
+ bool ok = false;
+ struct wlr_output_state state;
+ wlr_output_state_init(&state);
+ if (!wlr_scene_output_build_state(scene_output, &state, options)) {
+ goto out;
+ }
+
+ ok = wlr_output_commit_state(scene_output->output, &state);
+ if (!ok) {
+ goto out;
+ }
+
+ wlr_damage_ring_rotate(&scene_output->damage_ring);
+
+out:
+ wlr_output_state_finish(&state);
+ return ok;
+}
+
+bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
+ struct wlr_output_state *state, const struct wlr_scene_output_state_options *options) {
+ struct wlr_scene_output_state_options default_options = {0};
+ if (!options) {
+ options = &default_options;
+ }
+ struct wlr_scene_timer *timer = options->timer;
+ struct timespec start_time;
+ if (timer) {
+ clock_gettime(CLOCK_MONOTONIC, &start_time);
+ wlr_scene_timer_finish(timer);
+ *timer = (struct wlr_scene_timer){0};
+ }
+
+ if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && !state->enabled) {
+ // if the state is being disabled, do nothing.
+ return true;
+ }
+
struct wlr_output *output = scene_output->output;
enum wlr_scene_debug_damage_option debug_damage =
scene_output->scene->debug_damage_option;
- // Find the fx_renderer addon
- struct fx_renderer *renderer =
- fx_renderer_addon_find(&output->addons, scene_output->scene);
- assert(renderer != NULL);
+ struct render_data render_data = {
+ .transform = output->transform,
+ .scale = output->scale,
+ .logical = { .x = scene_output->x, .y = scene_output->y },
+ .output = scene_output,
+ };
+
+ output_pending_resolution(output, state,
+ &render_data.trans_width, &render_data.trans_height);
+
+ if (state->committed & WLR_OUTPUT_STATE_TRANSFORM) {
+ if (render_data.transform != state->transform) {
+ wlr_damage_ring_add_whole(&scene_output->damage_ring);
+ }
+
+ render_data.transform = state->transform;
+ }
+
+ if (state->committed & WLR_OUTPUT_STATE_SCALE) {
+ if (render_data.scale != state->scale) {
+ wlr_damage_ring_add_whole(&scene_output->damage_ring);
+ }
+
+ render_data.scale = state->scale;
+ }
+
+ if (render_data.transform & WL_OUTPUT_TRANSFORM_90) {
+ int tmp = render_data.trans_width;
+ render_data.trans_width = render_data.trans_height;
+ render_data.trans_height = tmp;
+ }
+
+ render_data.logical.width = render_data.trans_width / render_data.scale;
+ render_data.logical.height = render_data.trans_height / render_data.scale;
struct render_list_constructor_data list_con = {
- .box = { .x = scene_output->x, .y = scene_output->y },
+ .box = render_data.logical,
.render_list = &scene_output->render_list,
.calculate_visibility = scene_output->scene->calculate_visibility,
};
- wlr_output_effective_resolution(output,
- &list_con.box.width, &list_con.box.height);
list_con.render_list->size = 0;
scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box,
construct_render_list_iterator, &list_con);
array_realloc(list_con.render_list, list_con.render_list->size);
- int list_len = list_con.render_list->size / sizeof(struct wlr_scene_node *);
- struct wlr_scene_node **list_data = list_con.render_list->data;
+ struct render_list_entry *list_data = list_con.render_list->data;
+ int list_len = list_con.render_list->size / sizeof(*list_data);
- // if there is only one thing to render let's see if that thing can be
- // directly scanned out
- bool scanout = false;
- if (list_len == 1) {
- struct wlr_scene_node *node = list_data[0];
- scanout = scene_node_try_direct_scanout(node, scene_output, &list_con.box);
- }
+ bool scanout = list_len == 1 &&
+ scene_entry_try_direct_scanout(&list_data[0], state, &render_data);
if (scene_output->prev_scanout != scanout) {
scene_output->prev_scanout = scanout;
wlr_log(WLR_DEBUG, "Direct scan-out %s",
scanout ? "enabled" : "disabled");
- // When exiting direct scan-out, damage everything
- wlr_damage_ring_add_whole(&scene_output->damage_ring);
+ if (!scanout) {
+ // When exiting direct scan-out, damage everything
+ wlr_damage_ring_add_whole(&scene_output->damage_ring);
+ }
}
if (scanout) {
- struct wlr_scene_node *node = list_data[0];
-
- assert(node->type == WLR_SCENE_NODE_BUFFER);
- struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
- wl_signal_emit_mutable(&buffer->events.output_present, scene_output);
+ if (timer) {
+ struct timespec end_time, duration;
+ clock_gettime(CLOCK_MONOTONIC, &end_time);
+ timespec_sub(&duration, &end_time, &start_time);
+ timer->pre_render_duration = timespec_to_nsec(&duration);
+ }
return true;
}
@@ -1645,8 +2217,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
// add the current frame's damage if there is damage
if (pixman_region32_not_empty(&scene_output->damage_ring.current)) {
- struct highlight_region *current_damage =
- calloc(1, sizeof(*current_damage));
+ struct highlight_region *current_damage = calloc(1, sizeof(*current_damage));
if (current_damage) {
pixman_region32_init(&current_damage->region);
pixman_region32_copy(&current_damage->region,
@@ -1677,38 +2248,52 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
pixman_region32_fini(&acc_damage);
}
+ wlr_damage_ring_set_bounds(&scene_output->damage_ring,
+ render_data.trans_width, render_data.trans_height);
+
+ if (!wlr_output_configure_primary_swapchain(output, state, &output->swapchain)) {
+ return false;
+ }
+
int buffer_age;
- if (!wlr_output_attach_render(output, &buffer_age)) {
+ struct wlr_buffer *buffer = wlr_swapchain_acquire(output->swapchain, &buffer_age);
+ if (buffer == NULL) {
return false;
}
- pixman_region32_t damage;
- pixman_region32_init(&damage);
- wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring,
- buffer_age, &damage);
- if (!output->needs_frame && !pixman_region32_not_empty(
- &scene_output->damage_ring.current)) {
- pixman_region32_fini(&damage);
- wlr_output_rollback(output);
- return true;
+ if (timer) {
+ timer->render_timer = wlr_render_timer_create(output->renderer);
+
+ struct timespec end_time, duration;
+ clock_gettime(CLOCK_MONOTONIC, &end_time);
+ timespec_sub(&duration, &end_time, &start_time);
+ timer->pre_render_duration = timespec_to_nsec(&duration);
}
- fx_renderer_begin(renderer, output->width, output->height);
+ struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer,
+ &(struct wlr_buffer_pass_options){
+ .timer = timer ? timer->render_timer : NULL,
+ });
+ if (render_pass == NULL) {
+ wlr_buffer_unlock(buffer);
+ return false;
+ }
+
+ render_data.render_pass = render_pass;
+ pixman_region32_init(&render_data.damage);
+ wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring,
+ buffer_age, &render_data.damage);
pixman_region32_t background;
pixman_region32_init(&background);
- pixman_region32_copy(&background, &damage);
+ pixman_region32_copy(&background, &render_data.damage);
// Cull areas of the background that are occluded by opaque regions of
// scene nodes above. Those scene nodes will just render atop having us
// never see the background.
if (scene_output->scene->calculate_visibility) {
- float output_scale = scene_output->output->scale;
-
for (int i = list_len - 1; i >= 0; i--) {
- struct wlr_scene_node *node = list_data[i];
- int x, y;
- wlr_scene_node_coords(node, &x, &y);
+ struct render_list_entry *entry = &list_data[i];
// We must only cull opaque regions that are visible by the node.
// The node's visibility will have the knowledge of a black rect
@@ -1717,38 +2302,49 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
// rendering in that black rect region, consider the node's visibility.
pixman_region32_t opaque;
pixman_region32_init(&opaque);
- scene_node_opaque_region(node, x, y, &opaque);
- pixman_region32_intersect(&opaque, &opaque, &node->visible);
+ scene_node_opaque_region(entry->node, entry->x, entry->y, &opaque);
+ pixman_region32_intersect(&opaque, &opaque, &entry->node->visible);
pixman_region32_translate(&opaque, -scene_output->x, -scene_output->y);
- wlr_region_scale(&opaque, &opaque, output_scale);
+ wlr_region_scale(&opaque, &opaque, render_data.scale);
pixman_region32_subtract(&background, &background, &opaque);
pixman_region32_fini(&opaque);
}
- if (floor(output_scale) != output_scale) {
+ if (floor(render_data.scale) != render_data.scale) {
wlr_region_expand(&background, &background, 1);
// reintersect with the damage because we never want to render
// outside of the damage region
- pixman_region32_intersect(&background, &background, &damage);
+ pixman_region32_intersect(&background, &background, &render_data.damage);
}
}
- int nrects;
- pixman_box32_t *rects = pixman_region32_rectangles(&background, &nrects);
- for (int i = 0; i < nrects; ++i) {
- scissor_output(output, &rects[i]);
- fx_renderer_clear((float[4]){ 0.0, 0.0, 0.0, 1.0 });
- }
+ transform_output_damage(&background, &render_data);
+ wlr_render_pass_add_rect(render_pass, &(struct wlr_render_rect_options){
+ .box = { .width = buffer->width, .height = buffer->height },
+ .color = { .r = 0, .g = 0, .b = 0, .a = 1 },
+ .clip = &background,
+ });
pixman_region32_fini(&background);
for (int i = list_len - 1; i >= 0; i--) {
- struct wlr_scene_node *node = list_data[i];
- scene_node_render(renderer, node, scene_output, &damage);
- }
+ struct render_list_entry *entry = &list_data[i];
+ scene_entry_render(entry, &render_data);
+
+ if (entry->node->type == WLR_SCENE_NODE_BUFFER) {
+ struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(entry->node);
- fx_renderer_scissor(NULL);
+ if (buffer->primary_output == scene_output && !entry->sent_dmabuf_feedback) {
+ struct wlr_linux_dmabuf_feedback_v1_init_options options = {
+ .main_renderer = output->renderer,
+ .scanout_primary_output = NULL,
+ };
+
+ scene_buffer_send_dmabuf_feedback(scene_output->scene, buffer, &options);
+ }
+ }
+ }
if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
struct highlight_region *damage;
@@ -1758,55 +2354,48 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
int64_t time_diff_ms = timespec_to_msec(&time_diff);
float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME;
- int nrects;
- pixman_box32_t *rects = pixman_region32_rectangles(&damage->region, &nrects);
- for (int i = 0; i < nrects; ++i) {
- struct wlr_box box = {
- .x = rects[i].x1,
- .y = rects[i].y1,
- .width = rects[i].x2 - rects[i].x1,
- .height = rects[i].y2 - rects[i].y1,
- };
-
- float color[4] = { alpha * .5, 0.0, 0.0, alpha * .5 };
- fx_render_rect(renderer, &box, color, output->transform_matrix);
- }
+ wlr_render_pass_add_rect(render_pass, &(struct wlr_render_rect_options){
+ .box = { .width = buffer->width, .height = buffer->height },
+ .color = { .r = alpha * 0.5, .g = 0, .b = 0, .a = alpha * 0.5 },
+ .clip = &damage->region,
+ });
}
}
- // Draw the software cursors
- wlr_renderer_begin(output->renderer, output->width, output->height);
- wlr_output_render_software_cursors(output, &damage);
- wlr_renderer_end(output->renderer);
-
- pixman_region32_fini(&damage);
+ wlr_output_add_software_cursors_to_render_pass(output, render_pass, &render_data.damage);
- int tr_width, tr_height;
- wlr_output_transformed_resolution(output, &tr_width, &tr_height);
+ pixman_region32_fini(&render_data.damage);
- enum wl_output_transform transform =
- wlr_output_transform_invert(output->transform);
-
- pixman_region32_t frame_damage;
- pixman_region32_init(&frame_damage);
- wlr_region_transform(&frame_damage,
- &scene_output->damage_ring.current,
- transform, tr_width, tr_height);
- wlr_output_set_damage(output, &frame_damage);
- pixman_region32_fini(&frame_damage);
-
- bool success = wlr_output_commit(output);
-
- if (success) {
- wlr_damage_ring_rotate(&scene_output->damage_ring);
+ if (!wlr_render_pass_submit(render_pass)) {
+ wlr_buffer_unlock(buffer);
+ return false;
}
+ wlr_output_state_set_buffer(state, buffer);
+ wlr_buffer_unlock(buffer);
+ output_state_apply_damage(&render_data, state);
+
if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT &&
!wl_list_empty(&scene_output->damage_highlight_regions)) {
wlr_output_schedule_frame(scene_output->output);
}
- return success;
+ return true;
+}
+
+int64_t wlr_scene_timer_get_duration_ns(struct wlr_scene_timer *timer) {
+ int64_t pre_render = timer->pre_render_duration;
+ if (!timer->render_timer) {
+ return pre_render;
+ }
+ int64_t render = wlr_render_timer_get_duration_ns(timer->render_timer);
+ return render != -1 ? pre_render + render : -1;
+}
+
+void wlr_scene_timer_finish(struct wlr_scene_timer *timer) {
+ if (timer->render_timer) {
+ wlr_render_timer_destroy(timer->render_timer);
+ }
}
static void scene_node_send_frame_done(struct wlr_scene_node *node,
@@ -1823,7 +2412,7 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node,
wlr_scene_buffer_send_frame_done(scene_buffer, now);
}
} else if (node->type == WLR_SCENE_NODE_TREE) {
- struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
+ 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) {
scene_node_send_frame_done(child, scene_output, now);
@@ -1858,7 +2447,7 @@ static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box,
user_iterator(scene_buffer, lx, ly, user_data);
}
} else if (node->type == WLR_SCENE_NODE_TREE) {
- struct wlr_scene_tree *scene_tree = scene_tree_from_node(node);
+ 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) {
scene_output_for_each_scene_buffer(output_box, child, lx, ly,
diff --git a/types/scene/xdg_shell.c b/types/scene/xdg_shell.c
deleted file mode 100644
index 1688348..0000000
--- a/types/scene/xdg_shell.c
+++ /dev/null
@@ -1,124 +0,0 @@
-#include <stdlib.h>
-#include <wlr/types/wlr_scene.h>
-#include <wlr/types/wlr_xdg_shell.h>
-
-struct wlr_scene_xdg_surface {
- struct wlr_scene_tree *tree;
- struct wlr_xdg_surface *xdg_surface;
- struct wlr_scene_tree *surface_tree;
-
- struct wl_listener tree_destroy;
- struct wl_listener xdg_surface_destroy;
- struct wl_listener xdg_surface_map;
- struct wl_listener xdg_surface_unmap;
- struct wl_listener xdg_surface_commit;
-};
-
-static void scene_xdg_surface_handle_tree_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_xdg_surface *scene_xdg_surface =
- wl_container_of(listener, scene_xdg_surface, tree_destroy);
- // tree and surface_node will be cleaned up by scene_node_finish
- wl_list_remove(&scene_xdg_surface->tree_destroy.link);
- wl_list_remove(&scene_xdg_surface->xdg_surface_destroy.link);
- wl_list_remove(&scene_xdg_surface->xdg_surface_map.link);
- wl_list_remove(&scene_xdg_surface->xdg_surface_unmap.link);
- wl_list_remove(&scene_xdg_surface->xdg_surface_commit.link);
- free(scene_xdg_surface);
-}
-
-static void scene_xdg_surface_handle_xdg_surface_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_xdg_surface *scene_xdg_surface =
- wl_container_of(listener, scene_xdg_surface, xdg_surface_destroy);
- wlr_scene_node_destroy(&scene_xdg_surface->tree->node);
-}
-
-static void scene_xdg_surface_handle_xdg_surface_map(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_xdg_surface *scene_xdg_surface =
- wl_container_of(listener, scene_xdg_surface, xdg_surface_map);
- wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, true);
-}
-
-static void scene_xdg_surface_handle_xdg_surface_unmap(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_xdg_surface *scene_xdg_surface =
- wl_container_of(listener, scene_xdg_surface, xdg_surface_unmap);
- wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, false);
-}
-
-static void scene_xdg_surface_update_position(
- struct wlr_scene_xdg_surface *scene_xdg_surface) {
- struct wlr_xdg_surface *xdg_surface = scene_xdg_surface->xdg_surface;
-
- struct wlr_box geo = {0};
- wlr_xdg_surface_get_geometry(xdg_surface, &geo);
- wlr_scene_node_set_position(&scene_xdg_surface->surface_tree->node,
- -geo.x, -geo.y);
-
- if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
- struct wlr_xdg_popup *popup = xdg_surface->popup;
- wlr_scene_node_set_position(&scene_xdg_surface->tree->node,
- popup->current.geometry.x, popup->current.geometry.y);
- }
-}
-
-static void scene_xdg_surface_handle_xdg_surface_commit(struct wl_listener *listener,
- void *data) {
- struct wlr_scene_xdg_surface *scene_xdg_surface =
- wl_container_of(listener, scene_xdg_surface, xdg_surface_commit);
- scene_xdg_surface_update_position(scene_xdg_surface);
-}
-
-struct wlr_scene_tree *wlr_scene_xdg_surface_create(
- struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface) {
- struct wlr_scene_xdg_surface *scene_xdg_surface =
- calloc(1, sizeof(*scene_xdg_surface));
- if (scene_xdg_surface == NULL) {
- return NULL;
- }
-
- scene_xdg_surface->xdg_surface = xdg_surface;
-
- scene_xdg_surface->tree = wlr_scene_tree_create(parent);
- if (scene_xdg_surface->tree == NULL) {
- free(scene_xdg_surface);
- return NULL;
- }
-
- scene_xdg_surface->surface_tree = wlr_scene_subsurface_tree_create(
- scene_xdg_surface->tree, xdg_surface->surface);
- if (scene_xdg_surface->surface_tree == NULL) {
- wlr_scene_node_destroy(&scene_xdg_surface->tree->node);
- free(scene_xdg_surface);
- return NULL;
- }
-
- scene_xdg_surface->tree_destroy.notify =
- scene_xdg_surface_handle_tree_destroy;
- wl_signal_add(&scene_xdg_surface->tree->node.events.destroy,
- &scene_xdg_surface->tree_destroy);
-
- scene_xdg_surface->xdg_surface_destroy.notify =
- scene_xdg_surface_handle_xdg_surface_destroy;
- wl_signal_add(&xdg_surface->events.destroy, &scene_xdg_surface->xdg_surface_destroy);
-
- scene_xdg_surface->xdg_surface_map.notify =
- scene_xdg_surface_handle_xdg_surface_map;
- wl_signal_add(&xdg_surface->events.map, &scene_xdg_surface->xdg_surface_map);
-
- scene_xdg_surface->xdg_surface_unmap.notify =
- scene_xdg_surface_handle_xdg_surface_unmap;
- wl_signal_add(&xdg_surface->events.unmap, &scene_xdg_surface->xdg_surface_unmap);
-
- scene_xdg_surface->xdg_surface_commit.notify =
- scene_xdg_surface_handle_xdg_surface_commit;
- wl_signal_add(&xdg_surface->surface->events.commit,
- &scene_xdg_surface->xdg_surface_commit);
-
- wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, xdg_surface->mapped);
- scene_xdg_surface_update_position(scene_xdg_surface);
-
- return scene_xdg_surface->tree;
-}
diff --git a/util/env.c b/util/env.c
index b0a9efd..77911a2 100644
--- a/util/env.c
+++ b/util/env.c
@@ -19,7 +19,7 @@ bool env_parse_bool(const char *option) {
return false;
}
-ssize_t env_parse_switch(const char *option, const char **switches) {
+size_t env_parse_switch(const char *option, const char **switches) {
const char *env = getenv(option);
if (env) {
wlr_log(WLR_INFO, "Loading %s option: %s", option, env);
diff --git a/util/time.c b/util/time.c
index 06e42b4..78faac5 100644
--- a/util/time.c
+++ b/util/time.c
@@ -10,12 +10,16 @@ int64_t timespec_to_msec(const struct timespec *a) {
return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000;
}
+int64_t timespec_to_nsec(const struct timespec *a) {
+ return (int64_t)a->tv_sec * NSEC_PER_SEC + a->tv_nsec;
+}
+
void timespec_from_nsec(struct timespec *r, int64_t nsec) {
r->tv_sec = nsec / NSEC_PER_SEC;
r->tv_nsec = nsec % NSEC_PER_SEC;
}
-uint32_t get_current_time_msec(void) {
+int64_t get_current_time_msec(void) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return timespec_to_msec(&now);