aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Orzechowski <alex@ozal.ski>2023-12-04 06:33:57 -0500
committerKirill Primak <vyivel@eclair.cafe>2024-01-18 18:36:54 +0300
commit9c17cba0b29979ae23c4521b884f7419fd558770 (patch)
treedb563b9ebcc9eda7afed3e5cd263fb13f531caac
parent0e1a02bf0aad3d743985602b55043c5de019d1f0 (diff)
renderer: Render scene_graph
-rw-r--r--include/sway/output.h3
-rw-r--r--include/sway/scene_descriptor.h1
-rw-r--r--include/sway/server.h2
-rw-r--r--include/sway/surface.h14
-rw-r--r--sway/desktop/output.c420
-rw-r--r--sway/desktop/surface.c43
-rw-r--r--sway/server.c3
7 files changed, 80 insertions, 406 deletions
diff --git a/include/sway/output.h b/include/sway/output.h
index 691ac8dd..b35f1366 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -41,7 +41,6 @@ struct sway_output {
struct wl_list shell_layers[4]; // sway_layer_surface::link
struct wlr_box usable_area;
- struct timespec last_frame;
struct wlr_damage_ring damage_ring;
int lx, ly; // layout coords
@@ -58,9 +57,7 @@ struct sway_output {
struct wl_listener destroy;
struct wl_listener commit;
struct wl_listener present;
- struct wl_listener damage;
struct wl_listener frame;
- struct wl_listener needs_frame;
struct wl_listener request_state;
struct {
diff --git a/include/sway/scene_descriptor.h b/include/sway/scene_descriptor.h
index 13ae81a3..9761c2c0 100644
--- a/include/sway/scene_descriptor.h
+++ b/include/sway/scene_descriptor.h
@@ -11,6 +11,7 @@
#include <wlr/types/wlr_scene.h>
enum sway_scene_descriptor_type {
+ SWAY_SCENE_DESC_BUFFER_TIMER,
};
bool scene_descriptor_assign(struct wlr_scene_node *node,
diff --git a/include/sway/server.h b/include/sway/server.h
index b0e8dfd6..f3d25980 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -41,7 +41,6 @@ struct sway_server {
struct wlr_allocator *allocator;
struct wlr_compositor *compositor;
- struct wl_listener compositor_new_surface;
struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
@@ -170,7 +169,6 @@ void server_run(struct sway_server *server);
void restore_nofile_limit(void);
-void handle_compositor_new_surface(struct wl_listener *listener, void *data);
void handle_new_output(struct wl_listener *listener, void *data);
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
diff --git a/include/sway/surface.h b/include/sway/surface.h
index a7a8ec3f..81eb80d5 100644
--- a/include/sway/surface.h
+++ b/include/sway/surface.h
@@ -2,20 +2,6 @@
#define _SWAY_SURFACE_H
#include <wlr/types/wlr_compositor.h>
-struct sway_surface {
- struct wlr_surface *wlr_surface;
-
- struct wl_listener destroy;
-
- /**
- * This timer can be used for issuing delayed frame done callbacks (for
- * example, to improve presentation latency). Its handler is set to a
- * function that issues a frame done callback to this surface.
- */
- struct wl_event_source *frame_done_timer;
-};
-
-void surface_update_outputs(struct wlr_surface *surface);
void surface_enter_output(struct wlr_surface *surface,
struct sway_output *output);
void surface_leave_output(struct wlr_surface *surface,
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 288ccc7c..11de25fb 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -26,8 +26,8 @@
#include "sway/ipc-server.h"
#include "sway/layers.h"
#include "sway/output.h"
+#include "sway/scene_descriptor.h"
#include "sway/server.h"
-#include "sway/surface.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h"
@@ -275,104 +275,6 @@ void output_drag_icons_for_each_surface(struct sway_output *output,
}
}
-static void for_each_surface_container_iterator(struct sway_container *con,
- void *_data) {
- if (!con->view || !view_is_visible(con->view)) {
- return;
- }
-
- struct surface_iterator_data *data = _data;
- output_view_for_each_surface(data->output, con->view,
- data->user_iterator, data->user_data);
-}
-
-static void output_for_each_surface(struct sway_output *output,
- sway_surface_iterator_func_t iterator, void *user_data) {
- if (server.session_lock.locked) {
- if (server.session_lock.lock == NULL) {
- return;
- }
- struct wlr_session_lock_surface_v1 *lock_surface;
- wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) {
- if (lock_surface->output != output->wlr_output) {
- continue;
- }
- if (!lock_surface->surface->mapped) {
- continue;
- }
-
- output_surface_for_each_surface(output, lock_surface->surface,
- 0.0, 0.0, iterator, user_data);
- }
- return;
- }
-
- if (output_has_opaque_overlay_layer_surface(output)) {
- goto overlay;
- }
-
- struct surface_iterator_data data = {
- .user_iterator = iterator,
- .user_data = user_data,
- .output = output,
- .view = NULL,
- };
-
- struct sway_workspace *workspace = output_get_active_workspace(output);
- struct sway_container *fullscreen_con = root->fullscreen_global;
- if (!fullscreen_con) {
- if (!workspace) {
- return;
- }
- fullscreen_con = workspace->current.fullscreen;
- }
- if (fullscreen_con) {
- for_each_surface_container_iterator(fullscreen_con, &data);
- container_for_each_child(fullscreen_con,
- for_each_surface_container_iterator, &data);
-
- // TODO: Show transient containers for fullscreen global
- if (fullscreen_con == workspace->current.fullscreen) {
- for (int i = 0; i < workspace->current.floating->length; ++i) {
- struct sway_container *floater =
- workspace->current.floating->items[i];
- if (container_is_transient_for(floater, fullscreen_con)) {
- for_each_surface_container_iterator(floater, &data);
- }
- }
- }
-#if HAVE_XWAYLAND
- output_unmanaged_for_each_surface(output, &root->xwayland_unmanaged,
- iterator, user_data);
-#endif
- } else {
- output_layer_for_each_surface(output,
- &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
- iterator, user_data);
- output_layer_for_each_surface(output,
- &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
- iterator, user_data);
-
- workspace_for_each_container(workspace,
- for_each_surface_container_iterator, &data);
-
-#if HAVE_XWAYLAND
- output_unmanaged_for_each_surface(output, &root->xwayland_unmanaged,
- iterator, user_data);
-#endif
- output_layer_for_each_surface(output,
- &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
- iterator, user_data);
- }
-
-overlay:
- output_layer_for_each_surface(output,
- &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
- iterator, user_data);
- output_drag_icons_for_each_surface(output, &root->drag_icons,
- iterator, user_data);
-}
-
static int scale_length(int length, int offset, float scale) {
return roundf((offset + length) * scale) - roundf(offset * scale);
}
@@ -424,276 +326,137 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output) {
struct send_frame_done_data {
struct timespec when;
int msec_until_refresh;
+ struct sway_output *output;
};
-static void send_frame_done_iterator(struct sway_output *output,
- struct sway_view *view, struct wlr_surface *surface,
- struct wlr_box *box, void *user_data) {
- int view_max_render_time = 0;
- if (view != NULL) {
- view_max_render_time = view->max_render_time;
- }
-
- struct send_frame_done_data *data = user_data;
+struct buffer_timer {
+ struct wl_listener destroy;
+ struct wl_event_source *frame_done_timer;
+};
- int delay = data->msec_until_refresh - output->max_render_time
- - view_max_render_time;
+static int handle_buffer_timer(void *data) {
+ struct wlr_scene_buffer *buffer = data;
- if (output->max_render_time == 0 || view_max_render_time == 0 || delay < 1) {
- wlr_surface_send_frame_done(surface, &data->when);
- } else {
- struct sway_surface *sway_surface = surface->data;
- wl_event_source_timer_update(sway_surface->frame_done_timer, delay);
- }
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ wlr_scene_buffer_send_frame_done(buffer, &now);
+ return 0;
}
-static void send_frame_done(struct sway_output *output, struct send_frame_done_data *data) {
- output_for_each_surface(output, send_frame_done_iterator, data);
-}
+static void handle_buffer_timer_destroy(struct wl_listener *listener,
+ void *data) {
+ struct buffer_timer *timer = wl_container_of(listener, timer, destroy);
-static void count_surface_iterator(struct sway_output *output,
- struct sway_view *view, struct wlr_surface *surface,
- struct wlr_box *box, void *data) {
- size_t *n = data;
- (*n)++;
+ wl_list_remove(&timer->destroy.link);
+ wl_event_source_remove(timer->frame_done_timer);
+ free(timer);
}
-static bool scan_out_fullscreen_view(struct sway_output *output,
- struct wlr_output_state *pending, struct sway_view *view) {
- struct wlr_output *wlr_output = output->wlr_output;
- struct sway_workspace *workspace = output->current.active_workspace;
- if (!sway_assert(workspace, "Expected an active workspace")) {
- return false;
- }
-
- if (server.session_lock.locked) {
- return false;
+static struct buffer_timer *buffer_timer_get_or_create(struct wlr_scene_buffer *buffer) {
+ struct buffer_timer *timer =
+ scene_descriptor_try_get(&buffer->node, SWAY_SCENE_DESC_BUFFER_TIMER);
+ if (timer) {
+ return timer;
}
- if (!wl_list_empty(&view->saved_buffers)) {
- return false;
+ timer = calloc(1, sizeof(struct buffer_timer));
+ if (!timer) {
+ return NULL;
}
- for (int i = 0; i < workspace->current.floating->length; ++i) {
- struct sway_container *floater =
- workspace->current.floating->items[i];
- if (container_is_transient_for(floater, view->container)) {
- return false;
- }
+ timer->frame_done_timer = wl_event_loop_add_timer(server.wl_event_loop,
+ handle_buffer_timer, buffer);
+ if (!timer->frame_done_timer) {
+ free(timer);
+ return NULL;
}
-#if HAVE_XWAYLAND
- if (!wl_list_empty(&root->xwayland_unmanaged)) {
- return false;
- }
-#endif
+ scene_descriptor_assign(&buffer->node, SWAY_SCENE_DESC_BUFFER_TIMER, timer);
- if (!wl_list_empty(&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY])) {
- return false;
- }
- if (!wl_list_empty(&root->drag_icons)) {
- return false;
- }
+ timer->destroy.notify = handle_buffer_timer_destroy;
+ wl_signal_add(&buffer->node.events.destroy, &timer->destroy);
- struct wlr_surface *surface = view->surface;
- if (surface == NULL) {
- return false;
- }
- size_t n_surfaces = 0;
- output_view_for_each_surface(output, view,
- count_surface_iterator, &n_surfaces);
- if (n_surfaces != 1) {
- return false;
- }
- size_t n_popups = 0;
- output_view_for_each_popup_surface(output, view,
- count_surface_iterator, &n_popups);
- if (n_popups > 0) {
- return false;
- }
+ return timer;
+}
- if (surface->buffer == NULL) {
- return false;
- }
+static void send_frame_done_iterator(struct wlr_scene_buffer *buffer,
+ int x, int y, void *user_data) {
+ struct send_frame_done_data *data = user_data;
+ struct sway_output *output = data->output;
+ int view_max_render_time = 0;
- if ((float)surface->current.scale != wlr_output->scale ||
- surface->current.transform != wlr_output->transform) {
- return false;
+ if (buffer->primary_output != data->output->scene_output) {
+ return;
}
- if (!wlr_output_is_direct_scanout_allowed(wlr_output)) {
- return false;
- }
+ struct wlr_scene_node *current = &buffer->node;
- wlr_output_state_set_buffer(pending, &surface->buffer->base);
+ while (true) {
+ if (!current->parent) {
+ break;
+ }
- if (!wlr_output_test_state(wlr_output, pending)) {
- return false;
+ current = &current->parent->node;
}
- wlr_presentation_surface_scanned_out_on_output(surface,
- wlr_output);
-
- return wlr_output_commit_state(wlr_output, pending);
-}
-
-static void get_frame_damage(struct sway_output *output,
- pixman_region32_t *frame_damage) {
- struct wlr_output *wlr_output = output->wlr_output;
-
- int width, height;
- wlr_output_transformed_resolution(wlr_output, &width, &height);
+ int delay = data->msec_until_refresh - output->max_render_time
+ - view_max_render_time;
- pixman_region32_init(frame_damage);
+ struct buffer_timer *timer = NULL;
- enum wl_output_transform transform =
- wlr_output_transform_invert(wlr_output->transform);
- wlr_region_transform(frame_damage, &output->damage_ring.current,
- transform, width, height);
+ if (output->max_render_time != 0 && view_max_render_time != 0 && delay > 0) {
+ timer = buffer_timer_get_or_create(buffer);
+ }
- if (debug.damage != DAMAGE_DEFAULT) {
- pixman_region32_union_rect(frame_damage, frame_damage,
- 0, 0, wlr_output->width, wlr_output->height);
+ if (timer) {
+ wl_event_source_timer_update(timer->frame_done_timer, delay);
+ } else {
+ wlr_scene_buffer_send_frame_done(buffer, &data->when);
}
}
static int output_repaint_timer_handler(void *data) {
struct sway_output *output = data;
- struct wlr_output *wlr_output = output->wlr_output;
- if (wlr_output == NULL) {
- return 0;
- }
- wlr_output->frame_pending = false;
-
- if (!wlr_output->needs_frame &&
- !output->gamma_lut_changed &&
- !pixman_region32_not_empty(&output->damage_ring.current)) {
- return 0;
- }
-
- struct sway_workspace *workspace = output->current.active_workspace;
- if (workspace == NULL) {
+ if (!output->enabled) {
return 0;
}
- struct sway_container *fullscreen_con = root->fullscreen_global;
- if (!fullscreen_con) {
- fullscreen_con = workspace->current.fullscreen;
- }
-
- struct wlr_output_state pending = {0};
+ output->wlr_output->frame_pending = false;
if (output->gamma_lut_changed) {
+ struct wlr_output_state pending;
+ wlr_output_state_init(&pending);
+ if (!wlr_scene_output_build_state(output->scene_output, &pending, NULL)) {
+ return 0;
+ }
+
output->gamma_lut_changed = false;
struct wlr_gamma_control_v1 *gamma_control =
wlr_gamma_control_manager_v1_get_control(
- server.gamma_control_manager_v1, wlr_output);
+ server.gamma_control_manager_v1, output->wlr_output);
if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) {
- goto out;
- }
- if (!wlr_output_test_state(wlr_output, &pending)) {
wlr_output_state_finish(&pending);
- pending = (struct wlr_output_state){0};
- wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
- }
- }
-
- pending.committed |= WLR_OUTPUT_STATE_DAMAGE;
- get_frame_damage(output, &pending.damage);
-
- if (fullscreen_con && fullscreen_con->view && !debug.noscanout) {
- // Try to scan-out the fullscreen view
- static bool last_scanned_out = false;
- bool scanned_out =
- scan_out_fullscreen_view(output, &pending, fullscreen_con->view);
-
- if (scanned_out && !last_scanned_out) {
- sway_log(SWAY_DEBUG, "Scanning out fullscreen view on %s",
- output->wlr_output->name);
- }
- if (last_scanned_out && !scanned_out) {
- sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out on %s",
- output->wlr_output->name);
- output_damage_whole(output);
+ return 0;
}
- last_scanned_out = scanned_out;
- if (scanned_out) {
- goto out;
+ if (!wlr_output_commit_state(output->wlr_output, &pending)) {
+ wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
+ wlr_output_state_finish(&pending);
+ return 0;
}
- }
- if (!wlr_output_configure_primary_swapchain(wlr_output, &pending, &wlr_output->swapchain)) {
- goto out;
- }
-
- int buffer_age;
- struct wlr_buffer *buffer = wlr_swapchain_acquire(wlr_output->swapchain, &buffer_age);
- if (buffer == NULL) {
- goto out;
- }
-
- struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(
- wlr_output->renderer, buffer, NULL);
- if (render_pass == NULL) {
- wlr_buffer_unlock(buffer);
- goto out;
- }
-
- pixman_region32_t damage;
- pixman_region32_init(&damage);
- wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage);
-
- if (debug.damage == DAMAGE_RERENDER) {
- int width, height;
- wlr_output_transformed_resolution(wlr_output, &width, &height);
- pixman_region32_union_rect(&damage, &damage, 0, 0, width, height);
- }
-
- struct render_context ctx = {
- .output_damage = &damage,
- .renderer = wlr_output->renderer,
- .output = output,
- .pass = render_pass,
- };
-
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- output_render(&ctx);
-
- pixman_region32_fini(&damage);
-
- if (!wlr_render_pass_submit(render_pass)) {
- wlr_buffer_unlock(buffer);
- goto out;
+ wlr_output_state_finish(&pending);
+ return 0;
}
- wlr_output_state_set_buffer(&pending, buffer);
- wlr_buffer_unlock(buffer);
-
- if (!wlr_output_commit_state(wlr_output, &pending)) {
- goto out;
- }
+ wlr_scene_output_commit(output->scene_output, NULL);
wlr_damage_ring_rotate(&output->damage_ring);
- output->last_frame = now;
-out:
- wlr_output_state_finish(&pending);
return 0;
}
-static void handle_damage(struct wl_listener *listener, void *user_data) {
- struct sway_output *output =
- wl_container_of(listener, output, damage);
- struct wlr_output_event_damage *event = user_data;
- if (wlr_damage_ring_add(&output->damage_ring, event->damage)) {
- wlr_output_schedule_frame(output->wlr_output);
- }
-}
-
static void handle_frame(struct wl_listener *listener, void *user_data) {
struct sway_output *output =
wl_container_of(listener, output, frame);
@@ -754,13 +517,8 @@ static void handle_frame(struct wl_listener *listener, void *user_data) {
struct send_frame_done_data data = {0};
clock_gettime(CLOCK_MONOTONIC, &data.when);
data.msec_until_refresh = msec_until_refresh;
- send_frame_done(output, &data);
-}
-
-static void handle_needs_frame(struct wl_listener *listener, void *user_data) {
- struct sway_output *output =
- wl_container_of(listener, output, needs_frame);
- wlr_output_schedule_frame(output->wlr_output);
+ data.output = output;
+ wlr_scene_output_for_each_buffer(output->scene_output, send_frame_done_iterator, &data);
}
void output_damage_whole(struct sway_output *output) {
@@ -904,9 +662,7 @@ static void begin_destroy(struct sway_output *output) {
wl_list_remove(&output->destroy.link);
wl_list_remove(&output->commit.link);
wl_list_remove(&output->present.link);
- wl_list_remove(&output->damage.link);
wl_list_remove(&output->frame.link);
- wl_list_remove(&output->needs_frame.link);
wl_list_remove(&output->request_state.link);
wlr_damage_ring_finish(&output->damage_ring);
@@ -931,17 +687,6 @@ static void handle_layout_destroy(struct wl_listener *listener, void *data) {
begin_destroy(output);
}
-static void update_textures(struct sway_container *con, void *data) {
- container_update_title_textures(con);
- container_update_marks_textures(con);
-}
-
-static void update_output_scale_iterator(struct sway_output *output,
- struct sway_view *view, struct wlr_surface *surface,
- struct wlr_box *box, void *user_data) {
- surface_update_outputs(surface);
-}
-
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, commit);
struct wlr_output_event_commit *event = data;
@@ -950,11 +695,6 @@ static void handle_commit(struct wl_listener *listener, void *data) {
return;
}
- if (event->state->committed & WLR_OUTPUT_STATE_SCALE) {
- output_for_each_container(output, update_textures, NULL);
- output_for_each_surface(output, update_output_scale_iterator, NULL);
- }
-
if (event->state->committed & (
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_TRANSFORM |
@@ -1066,12 +806,8 @@ void handle_new_output(struct wl_listener *listener, void *data) {
output->commit.notify = handle_commit;
wl_signal_add(&wlr_output->events.present, &output->present);
output->present.notify = handle_present;
- wl_signal_add(&wlr_output->events.damage, &output->damage);
- output->damage.notify = handle_damage;
wl_signal_add(&wlr_output->events.frame, &output->frame);
output->frame.notify = handle_frame;
- wl_signal_add(&wlr_output->events.needs_frame, &output->needs_frame);
- output->needs_frame.notify = handle_needs_frame;
wl_signal_add(&wlr_output->events.request_state, &output->request_state);
output->request_state.notify = handle_request_state;
diff --git a/sway/desktop/surface.c b/sway/desktop/surface.c
index 5932eaa2..af17a8bb 100644
--- a/sway/desktop/surface.c
+++ b/sway/desktop/surface.c
@@ -1,53 +1,12 @@
#define _POSIX_C_SOURCE 200112L
#include <stdlib.h>
-#include <time.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_fractional_scale_v1.h>
#include "sway/server.h"
#include "sway/surface.h"
#include "sway/output.h"
-static void handle_destroy(struct wl_listener *listener, void *data) {
- struct sway_surface *surface = wl_container_of(listener, surface, destroy);
-
- surface->wlr_surface->data = NULL;
- wl_list_remove(&surface->destroy.link);
-
- if (surface->frame_done_timer) {
- wl_event_source_remove(surface->frame_done_timer);
- }
-
- free(surface);
-}
-
-static int surface_frame_done_timer_handler(void *data) {
- struct sway_surface *surface = data;
-
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- wlr_surface_send_frame_done(surface->wlr_surface, &now);
-
- return 0;
-}
-
-void handle_compositor_new_surface(struct wl_listener *listener, void *data) {
- struct wlr_surface *wlr_surface = data;
-
- struct sway_surface *surface = calloc(1, sizeof(struct sway_surface));
- surface->wlr_surface = wlr_surface;
- wlr_surface->data = surface;
-
- surface->destroy.notify = handle_destroy;
- wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);
-
- surface->frame_done_timer = wl_event_loop_add_timer(server.wl_event_loop,
- surface_frame_done_timer_handler, surface);
- if (!surface->frame_done_timer) {
- wl_resource_post_no_memory(wlr_surface->resource);
- }
-}
-
-void surface_update_outputs(struct wlr_surface *surface) {
+static void surface_update_outputs(struct wlr_surface *surface) {
float scale = 1;
struct wlr_surface_output *surface_output;
wl_list_for_each(surface_output, &surface->current_outputs, link) {
diff --git a/sway/server.c b/sway/server.c
index 4bef4588..33b25000 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -201,9 +201,6 @@ bool server_init(struct sway_server *server) {
server->compositor = wlr_compositor_create(server->wl_display, 6,
server->renderer);
- server->compositor_new_surface.notify = handle_compositor_new_surface;
- wl_signal_add(&server->compositor->events.new_surface,
- &server->compositor_new_surface);
wlr_subcompositor_create(server->wl_display);