aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/fullscreen-shell.c4
-rw-r--r--examples/multi-pointer.c4
-rw-r--r--examples/output-layout.c4
-rw-r--r--examples/pointer.c4
-rw-r--r--examples/rotation.c4
-rw-r--r--examples/simple.c4
-rw-r--r--examples/tablet.c4
-rw-r--r--examples/touch.c4
-rw-r--r--include/wlr/types/wlr_output.h53
-rw-r--r--tinywl/tinywl.c6
-rw-r--r--types/wlr_output.c89
-rw-r--r--types/wlr_output_damage.c7
12 files changed, 114 insertions, 73 deletions
diff --git a/examples/fullscreen-shell.c b/examples/fullscreen-shell.c
index 7f2c9c2b..e9e64ce1 100644
--- a/examples/fullscreen-shell.c
+++ b/examples/fullscreen-shell.c
@@ -89,7 +89,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) {
int width, height;
wlr_output_effective_resolution(output->wlr_output, &width, &height);
- if (!wlr_output_make_current(output->wlr_output, NULL)) {
+ if (!wlr_output_attach_render(output->wlr_output, NULL)) {
return;
}
@@ -108,7 +108,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) {
}
wlr_renderer_end(renderer);
- wlr_output_swap_buffers(output->wlr_output, NULL, NULL);
+ wlr_output_commit(output->wlr_output);
}
static void output_set_surface(struct fullscreen_output *output,
diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c
index a007f712..44cf26d5 100644
--- a/examples/multi-pointer.c
+++ b/examples/multi-pointer.c
@@ -94,14 +94,14 @@ void output_frame_notify(struct wl_listener *listener, void *data) {
struct sample_state *sample = output->sample;
struct wlr_output *wlr_output = output->output;
- wlr_output_make_current(wlr_output, NULL);
+ wlr_output_attach_render(wlr_output, NULL);
glClearColor(sample->clear_color[0], sample->clear_color[1],
sample->clear_color[2], sample->clear_color[3]);
glClear(GL_COLOR_BUFFER_BIT);
wlr_output_render_software_cursors(wlr_output, NULL);
- wlr_output_swap_buffers(wlr_output, NULL, NULL);
+ wlr_output_commit(wlr_output);
}
static void handle_cursor_motion(struct wl_listener *listener, void *data) {
diff --git a/examples/output-layout.c b/examples/output-layout.c
index 440b3188..5e406af0 100644
--- a/examples/output-layout.c
+++ b/examples/output-layout.c
@@ -115,7 +115,7 @@ void output_frame_notify(struct wl_listener *listener, void *data) {
struct wlr_output *wlr_output = output->output;
- wlr_output_make_current(wlr_output, NULL);
+ wlr_output_attach_render(wlr_output, NULL);
wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
@@ -137,7 +137,7 @@ void output_frame_notify(struct wl_listener *listener, void *data) {
}
wlr_renderer_end(sample->renderer);
- wlr_output_swap_buffers(wlr_output, NULL, NULL);
+ wlr_output_commit(wlr_output);
}
static void update_velocities(struct sample_state *sample,
diff --git a/examples/pointer.c b/examples/pointer.c
index c7140d97..cf4b122d 100644
--- a/examples/pointer.c
+++ b/examples/pointer.c
@@ -98,11 +98,11 @@ void output_frame_notify(struct wl_listener *listener, void *data) {
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
assert(renderer);
- wlr_output_make_current(wlr_output, NULL);
+ wlr_output_attach_render(wlr_output, NULL);
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(renderer, state->clear_color);
wlr_output_render_software_cursors(wlr_output, NULL);
- wlr_output_swap_buffers(wlr_output, NULL, NULL);
+ wlr_output_commit(wlr_output);
wlr_renderer_end(renderer);
}
diff --git a/examples/rotation.c b/examples/rotation.c
index 7cf5727b..cfcd001b 100644
--- a/examples/rotation.c
+++ b/examples/rotation.c
@@ -60,7 +60,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
int32_t width, height;
wlr_output_effective_resolution(wlr_output, &width, &height);
- wlr_output_make_current(wlr_output, NULL);
+ wlr_output_attach_render(wlr_output, NULL);
wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
@@ -72,7 +72,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
}
wlr_renderer_end(sample->renderer);
- wlr_output_swap_buffers(wlr_output, NULL, NULL);
+ wlr_output_commit(wlr_output);
long ms = (now.tv_sec - sample->last_frame.tv_sec) * 1000 +
(now.tv_nsec - sample->last_frame.tv_nsec) / 1000000;
diff --git a/examples/simple.c b/examples/simple.c
index e1c10906..27eb6c20 100644
--- a/examples/simple.c
+++ b/examples/simple.c
@@ -56,12 +56,12 @@ void output_frame_notify(struct wl_listener *listener, void *data) {
sample->dec = inc;
}
- wlr_output_make_current(sample_output->output, NULL);
+ wlr_output_attach_render(sample_output->output, NULL);
glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0);
glClear(GL_COLOR_BUFFER_BIT);
- wlr_output_swap_buffers(sample_output->output, NULL, NULL);
+ wlr_output_commit(sample_output->output);
sample->last_frame = now;
}
diff --git a/examples/tablet.c b/examples/tablet.c
index fad30d52..6df28586 100644
--- a/examples/tablet.c
+++ b/examples/tablet.c
@@ -86,7 +86,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
int32_t width, height;
wlr_output_effective_resolution(wlr_output, &width, &height);
- wlr_output_make_current(wlr_output, NULL);
+ wlr_output_attach_render(wlr_output, NULL);
wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
@@ -129,7 +129,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
}
wlr_renderer_end(sample->renderer);
- wlr_output_swap_buffers(wlr_output, NULL, NULL);
+ wlr_output_commit(wlr_output);
sample->last_frame = now;
}
diff --git a/examples/touch.c b/examples/touch.c
index 9ed20a28..4ca9b993 100644
--- a/examples/touch.c
+++ b/examples/touch.c
@@ -73,7 +73,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
int32_t width, height;
wlr_output_effective_resolution(wlr_output, &width, &height);
- wlr_output_make_current(wlr_output, NULL);
+ wlr_output_attach_render(wlr_output, NULL);
wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
@@ -89,7 +89,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
}
wlr_renderer_end(sample->renderer);
- wlr_output_swap_buffers(wlr_output, NULL, NULL);
+ wlr_output_commit(wlr_output);
sample->last_frame = now;
}
diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h
index 820b7740..cd34dc99 100644
--- a/include/wlr/types/wlr_output.h
+++ b/include/wlr/types/wlr_output.h
@@ -46,16 +46,31 @@ struct wlr_output_cursor {
} events;
};
+enum wlr_output_state_field {
+ WLR_OUTPUT_STATE_BUFFER = 1 << 0,
+ WLR_OUTPUT_STATE_DAMAGE = 1 << 1,
+};
+
+/**
+ * Holds the double-buffered output state.
+ */
+struct wlr_output_state {
+ uint32_t committed; // enum wlr_output_state_field
+ pixman_region32_t damage;
+};
+
struct wlr_output_impl;
/**
* A compositor output region. This typically corresponds to a monitor that
* displays part of the compositor space.
*
- * Compositors should listen to the `frame` event to render an output. They
- * should call `wlr_output_make_current`, render and then call
- * `wlr_output_swap_buffers`. No rendering should happen outside a `frame` event
- * handler.
+ * The `frame` event will be emitted when it is a good time for the compositor
+ * to submit a new frame.
+ *
+ * To render a new frame, compositors should call `wlr_output_attach_render`,
+ * render and call `wlr_output_commit`. No rendering should happen outside a
+ * `frame` event handler or before `wlr_output_attach_render`.
*/
struct wlr_output {
const struct wlr_output_impl *impl;
@@ -88,6 +103,8 @@ struct wlr_output {
bool frame_pending;
float transform_matrix[9];
+ struct wlr_output_state pending;
+
struct {
// Request to render a frame
struct wl_signal frame;
@@ -189,12 +206,14 @@ void wlr_output_transformed_resolution(struct wlr_output *output,
void wlr_output_effective_resolution(struct wlr_output *output,
int *width, int *height);
/**
- * Makes the output rendering context current.
+ * Attach the renderer's buffer to the output. Compositors must call this
+ * function before rendering. After they are done rendering, they should call
+ * `wlr_output_commit` to submit the new frame.
*
- * `buffer_age` is set to the drawing buffer age in number of frames or -1 if
- * unknown. This is useful for damage tracking.
+ * If non-NULL, `buffer_age` is set to the drawing buffer age in number of
+ * frames or -1 if unknown. This is useful for damage tracking.
*/
-bool wlr_output_make_current(struct wlr_output *output, int *buffer_age);
+bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age);
/**
* Get the preferred format for reading pixels.
* This function might change the current rendering context.
@@ -202,18 +221,22 @@ bool wlr_output_make_current(struct wlr_output *output, int *buffer_age);
bool wlr_output_preferred_read_format(struct wlr_output *output,
enum wl_shm_format *fmt);
/**
- * Swaps the output buffers. If the time of the frame isn't known, set `when` to
- * NULL. If the compositor doesn't support damage tracking, set `damage` to
- * NULL.
+ * Set the damage region for the frame to be submitted.
*
- * Damage is given in output-buffer-local coordinates (ie. scaled and
+ * Compositors implementing damage tracking should call this function with the
+ * damaged region in output-buffer-local coordinates (ie. scaled and
* transformed).
- *
- * Swapping buffers schedules a `frame` event.
*/
-bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when,
+void wlr_output_set_damage(struct wlr_output *output,
pixman_region32_t *damage);
/**
+ * Commit the pending output state. If `wlr_output_attach_render` has been
+ * called, the pending frame will be submitted for display.
+ *
+ * This function schedules a `frame` event.
+ */
+bool wlr_output_commit(struct wlr_output *output);
+/**
* Manually schedules a `frame` event. If a `frame` event is already pending,
* it is a no-op.
*/
diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c
index 16c1f85c..ca5cdc91 100644
--- a/tinywl/tinywl.c
+++ b/tinywl/tinywl.c
@@ -591,8 +591,8 @@ static void output_frame(struct wl_listener *listener, void *data) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
- /* wlr_output_make_current makes the OpenGL context current. */
- if (!wlr_output_make_current(output->wlr_output, NULL)) {
+ /* wlr_output_attach_render makes the OpenGL context current. */
+ if (!wlr_output_attach_render(output->wlr_output, NULL)) {
return;
}
/* The "effective" resolution can change if you rotate your outputs. */
@@ -635,7 +635,7 @@ static void output_frame(struct wl_listener *listener, void *data) {
/* Conclude rendering and swap the buffers, showing the final frame
* on-screen. */
wlr_renderer_end(renderer);
- wlr_output_swap_buffers(output->wlr_output, NULL, NULL);
+ wlr_output_commit(output->wlr_output);
}
static void server_new_output(struct wl_listener *listener, void *data) {
diff --git a/types/wlr_output.c b/types/wlr_output.c
index a2d7c16e..c9b2689e 100644
--- a/types/wlr_output.c
+++ b/types/wlr_output.c
@@ -282,6 +282,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
wl_signal_init(&output->events.transform);
wl_signal_init(&output->events.destroy);
pixman_region32_init(&output->damage);
+ pixman_region32_init(&output->pending.damage);
const char *no_hardware_cursors = getenv("WLR_NO_HARDWARE_CURSORS");
if (no_hardware_cursors != NULL && strcmp(no_hardware_cursors, "1") == 0) {
@@ -317,6 +318,7 @@ void wlr_output_destroy(struct wlr_output *output) {
wl_event_source_remove(output->idle_frame);
}
+ pixman_region32_fini(&output->pending.damage);
pixman_region32_fini(&output->damage);
if (output->impl && output->impl->destroy) {
@@ -360,13 +362,18 @@ struct wlr_output_mode *wlr_output_preferred_mode(struct wlr_output *output) {
return mode;
}
-bool wlr_output_make_current(struct wlr_output *output, int *buffer_age) {
- return output->impl->make_current(output, buffer_age);
+bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age) {
+ if (!output->impl->make_current(output, buffer_age)) {
+ return false;
+ }
+
+ output->pending.committed |= WLR_OUTPUT_STATE_BUFFER;
+ return true;
}
bool wlr_output_preferred_read_format(struct wlr_output *output,
enum wl_shm_format *fmt) {
- if (!wlr_output_make_current(output, NULL)) {
+ if (!output->impl->make_current(output, NULL)) {
return false;
}
@@ -378,10 +385,21 @@ bool wlr_output_preferred_read_format(struct wlr_output *output,
return true;
}
-bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when,
+void wlr_output_set_damage(struct wlr_output *output,
pixman_region32_t *damage) {
+ pixman_region32_intersect_rect(&output->pending.damage, damage,
+ 0, 0, output->width, output->height);
+ output->pending.committed |= WLR_OUTPUT_STATE_DAMAGE;
+}
+
+static void output_state_clear(struct wlr_output_state *state) {
+ state->committed = 0;
+ pixman_region32_clear(&state->damage);
+}
+
+bool wlr_output_commit(struct wlr_output *output) {
if (output->frame_pending) {
- wlr_log(WLR_ERROR, "Tried to swap buffers when a frame is pending");
+ wlr_log(WLR_ERROR, "Tried to commit when a frame is pending");
return false;
}
if (output->idle_frame != NULL) {
@@ -389,46 +407,43 @@ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when,
output->idle_frame = NULL;
}
- struct timespec now;
- if (when == NULL) {
+ if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
+ struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
- when = &now;
- }
-
- struct wlr_output_event_swap_buffers event = {
- .output = output,
- .when = when,
- .damage = damage,
- };
- wlr_signal_emit_safe(&output->events.swap_buffers, &event);
- pixman_region32_t render_damage;
- pixman_region32_init(&render_damage);
- pixman_region32_union_rect(&render_damage, &render_damage, 0, 0,
- output->width, output->height);
- if (damage != NULL) {
- // Damage tracking supported
- pixman_region32_intersect(&render_damage, &render_damage, damage);
- }
+ pixman_region32_t *damage = NULL;
+ if (output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) {
+ damage = &output->pending.damage;
+ }
- if (!output->impl->swap_buffers(output, damage ? &render_damage : NULL)) {
- pixman_region32_fini(&render_damage);
- return false;
- }
+ struct wlr_output_event_swap_buffers event = {
+ .output = output,
+ .when = &now,
+ .damage = damage,
+ };
+ wlr_signal_emit_safe(&output->events.swap_buffers, &event);
- pixman_region32_fini(&render_damage);
+ if (!output->impl->swap_buffers(output, damage)) {
+ return false;
+ }
- struct wlr_output_cursor *cursor;
- wl_list_for_each(cursor, &output->cursors, link) {
- if (!cursor->enabled || !cursor->visible || cursor->surface == NULL) {
- continue;
+ struct wlr_output_cursor *cursor;
+ wl_list_for_each(cursor, &output->cursors, link) {
+ if (!cursor->enabled || !cursor->visible || cursor->surface == NULL) {
+ continue;
+ }
+ wlr_surface_send_frame_done(cursor->surface, &now);
}
- wlr_surface_send_frame_done(cursor->surface, when);
+
+ output->frame_pending = true;
+ output->needs_swap = false;
+ output_state_clear(&output->pending);
+ return true;
+ } else {
+ wlr_log(WLR_ERROR, "Tried to commit without attaching a buffer");
+ return false;
}
- output->frame_pending = true;
- output->needs_swap = false;
- pixman_region32_clear(&output->damage);
return true;
}
diff --git a/types/wlr_output_damage.c b/types/wlr_output_damage.c
index bf3a671d..d7949769 100644
--- a/types/wlr_output_damage.c
+++ b/types/wlr_output_damage.c
@@ -106,7 +106,7 @@ bool wlr_output_damage_make_current(struct wlr_output_damage *output_damage,
struct wlr_output *output = output_damage->output;
int buffer_age = -1;
- if (!wlr_output_make_current(output, &buffer_age)) {
+ if (!wlr_output_attach_render(output, &buffer_age)) {
return false;
}
@@ -142,7 +142,10 @@ bool wlr_output_damage_make_current(struct wlr_output_damage *output_damage,
bool wlr_output_damage_swap_buffers(struct wlr_output_damage *output_damage,
struct timespec *when, pixman_region32_t *damage) {
- if (!wlr_output_swap_buffers(output_damage->output, when, damage)) {
+ if (damage != NULL) {
+ wlr_output_set_damage(output_damage->output, damage);
+ }
+ if (!wlr_output_commit(output_damage->output)) {
return false;
}