summaryrefslogtreecommitdiff
path: root/types
diff options
context:
space:
mode:
authorErik Reider <[email protected]>2023-12-30 11:25:16 +0100
committerErik Reider <[email protected]>2024-01-02 11:21:58 +0100
commit0b52aa9d137b03017313e028accc92dc5d536440 (patch)
tree06649993526e0a339fff34f0ae8b4c8ec2fa4d13 /types
parentb929a2bbadf467864796ad4ec90882ce86cfebff (diff)
Initial rebase without effects
Diffstat (limited to 'types')
-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
9 files changed, 990 insertions, 1319 deletions
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;
-}