aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRose Hudson <rose@krx.sh>2023-06-08 10:42:25 +0100
committerSimon Ser <contact@emersion.fr>2023-07-10 09:57:02 +0000
commit214df8eda07d18b032abfcf525c8344e077c0c7e (patch)
tree29c2d58df0474fc47e5bf4d7eae0df0b1961d068
parentf4eaab12a056e339b1b7548f211bb463ad064392 (diff)
scene_output: optionally record and report timings
-rw-r--r--examples/scene-graph.c2
-rw-r--r--include/wlr/types/wlr_scene.h23
-rw-r--r--tinywl/tinywl.c2
-rw-r--r--types/scene/wlr_scene.c54
4 files changed, 73 insertions, 8 deletions
diff --git a/examples/scene-graph.c b/examples/scene-graph.c
index 3cf150d0..7b7e14d6 100644
--- a/examples/scene-graph.c
+++ b/examples/scene-graph.c
@@ -57,7 +57,7 @@ struct output {
static void output_handle_frame(struct wl_listener *listener, void *data) {
struct output *output = wl_container_of(listener, output, frame);
- if (!wlr_scene_output_commit(output->scene_output)) {
+ if (!wlr_scene_output_commit(output->scene_output, NULL)) {
return;
}
diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
index 36ad2361..b5487528 100644
--- a/include/wlr/types/wlr_scene.h
+++ b/include/wlr/types/wlr_scene.h
@@ -209,6 +209,11 @@ struct wlr_scene_output {
struct wl_array render_list;
};
+struct wlr_scene_timer {
+ int64_t pre_render_duration;
+ struct wlr_render_timer *render_timer;
+};
+
/** A layer shell scene helper */
struct wlr_scene_layer_surface_v1 {
struct wlr_scene_tree *tree;
@@ -455,16 +460,30 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output);
void wlr_scene_output_set_position(struct wlr_scene_output *scene_output,
int lx, int ly);
+struct wlr_scene_output_state_options {
+ struct wlr_scene_timer *timer;
+};
+
/**
* Render and commit an output.
*/
-bool wlr_scene_output_commit(struct wlr_scene_output *scene_output);
+bool wlr_scene_output_commit(struct wlr_scene_output *scene_output,
+ const struct wlr_scene_output_state_options *options);
/**
* Render and populate given output state.
*/
bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
- struct wlr_output_state *state);
+ struct wlr_output_state *state, const struct wlr_scene_output_state_options *options);
+
+/**
+ * Retrieve the duration in nanoseconds between the last wlr_scene_output_commit() call and the end
+ * of its operations, including those on the GPU that may have finished after the call returned.
+ *
+ * Returns -1 if the duration is unavailable.
+ */
+int64_t wlr_scene_timer_get_duration_ns(struct wlr_scene_timer *timer);
+void wlr_scene_timer_finish(struct wlr_scene_timer *timer);
/**
* Call wlr_surface_send_frame_done() on all surfaces in the scene rendered by
diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c
index 8324c500..61c08928 100644
--- a/tinywl/tinywl.c
+++ b/tinywl/tinywl.c
@@ -559,7 +559,7 @@ static void output_frame(struct wl_listener *listener, void *data) {
scene, output->wlr_output);
/* Render the scene if needed and commit the output */
- wlr_scene_output_commit(scene_output);
+ wlr_scene_output_commit(scene_output, NULL);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
index 3f901669..a6a786f5 100644
--- a/types/scene/wlr_scene.c
+++ b/types/scene/wlr_scene.c
@@ -1584,7 +1584,8 @@ static bool scene_entry_try_direct_scanout(struct render_list_entry *entry,
return true;
}
-bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
+bool wlr_scene_output_commit(struct wlr_scene_output *scene_output,
+ const struct wlr_scene_output_state_options *options) {
if (!scene_output->output->needs_frame && !pixman_region32_not_empty(
&scene_output->damage_ring.current)) {
return true;
@@ -1593,7 +1594,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
bool ok = false;
struct wlr_output_state state;
wlr_output_state_init(&state);
- if (!wlr_scene_output_build_state(scene_output, &state)) {
+ if (!wlr_scene_output_build_state(scene_output, &state, options)) {
goto out;
}
@@ -1610,7 +1611,19 @@ out:
}
bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
- struct wlr_output_state *state) {
+ 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;
@@ -1683,6 +1696,12 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
}
if (scanout) {
+ 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;
}
@@ -1742,7 +1761,19 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
return false;
}
- struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer, NULL);
+ 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);
+ }
+
+ 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;
@@ -1859,6 +1890,21 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
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,
struct wlr_scene_output *scene_output, struct timespec *now) {
if (!node->enabled) {