diff options
Diffstat (limited to 'types')
-rw-r--r-- | types/buffer/buffer.c | 43 | ||||
-rw-r--r-- | types/meson.build | 6 | ||||
-rw-r--r-- | types/output/wlr_output.c | 24 | ||||
-rw-r--r-- | types/scene/layer_shell_v1.c | 186 | ||||
-rw-r--r-- | types/scene/output_layout.c | 157 | ||||
-rw-r--r-- | types/scene/subsurface_tree.c | 259 | ||||
-rw-r--r-- | types/scene/surface.c | 211 | ||||
-rw-r--r-- | types/scene/wlr_scene.c | 1299 | ||||
-rw-r--r-- | types/scene/xdg_shell.c | 124 |
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(¤t_damage->region); +// pixman_region32_copy(¤t_damage->region, +// &scene_output->damage_ring.current); +// current_damage->when = now; +// wl_list_insert(regions, ¤t_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(¤t_damage->region); pixman_region32_copy(¤t_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; -} |