From f59706ecc00c75a47675f2a510f8c67dbb9b9a4a Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 21 Aug 2024 11:12:39 -0400 Subject: [PATCH 1/7] tinywl: Enable output with buffer --- tinywl/tinywl.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 89837b4fb..404aedc98 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -604,6 +604,20 @@ static void server_new_output(struct wl_listener *listener, void *data) { * and our renderer. Must be done once, before commiting the output */ wlr_output_init_render(wlr_output, server->allocator, server->renderer); + /* Adds this to the output layout. The add_auto function arranges outputs + * from left-to-right in the order they appear. A more sophisticated + * compositor would let the user configure the arrangement of outputs in the + * layout. + * + * The output layout utility automatically adds a wl_output global to the + * display, which Wayland clients can see to find out information about the + * output (such as DPI, scale factor, manufacturer, etc). + */ + struct wlr_output_layout_output *l_output = wlr_output_layout_add_auto(server->output_layout, + wlr_output); + struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output); + wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output); + /* The output may be disabled, switch it on. */ struct wlr_output_state state; wlr_output_state_init(&state); @@ -619,6 +633,11 @@ static void server_new_output(struct wl_listener *listener, void *data) { wlr_output_state_set_mode(&state, mode); } + /* When enabling an output, wlroots requires that a buffer is also included + * in that commit to enable the output. + */ + wlr_scene_output_build_state(scene_output, &state, NULL); + /* Atomically applies the new output state. */ wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); @@ -641,20 +660,6 @@ static void server_new_output(struct wl_listener *listener, void *data) { wl_signal_add(&wlr_output->events.destroy, &output->destroy); wl_list_insert(&server->outputs, &output->link); - - /* Adds this to the output layout. The add_auto function arranges outputs - * from left-to-right in the order they appear. A more sophisticated - * compositor would let the user configure the arrangement of outputs in the - * layout. - * - * The output layout utility automatically adds a wl_output global to the - * display, which Wayland clients can see to find out information about the - * output (such as DPI, scale factor, manufacturer, etc). - */ - struct wlr_output_layout_output *l_output = wlr_output_layout_add_auto(server->output_layout, - wlr_output); - struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output); - wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output); } static void xdg_toplevel_map(struct wl_listener *listener, void *data) { From c3b5e710f49d099706d62423f973d0fb3a2606e4 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 21 Aug 2024 11:11:49 -0400 Subject: [PATCH 2/7] wlr_output: Make wlr_output_transformed_resolution take a state --- backend/drm/drm.c | 2 +- include/wlr/types/wlr_output.h | 2 +- types/output/cursor.c | 5 +++-- types/output/output.c | 23 ++++++++++++++--------- types/scene/wlr_scene.c | 4 ++-- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 6ae9dcbf3..d49517c98 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1179,7 +1179,7 @@ static bool drm_connector_move_cursor(struct wlr_output *output, struct wlr_box box = { .x = x, .y = y }; int width, height; - wlr_output_transformed_resolution(output, &width, &height); + wlr_output_transformed_resolution(output, NULL, &width, &height); enum wl_output_transform transform = wlr_output_transform_invert(output->transform); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 9c08a2c34..1de0673f9 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -339,7 +339,7 @@ void wlr_output_destroy(struct wlr_output *output); * Computes the transformed output resolution. */ void wlr_output_transformed_resolution(struct wlr_output *output, - int *width, int *height); + const struct wlr_output_state *state, int *width, int *height); /** * Computes the transformed and scaled output resolution. */ diff --git a/types/output/cursor.c b/types/output/cursor.c index af1663574..d399f7288 100644 --- a/types/output/cursor.c +++ b/types/output/cursor.c @@ -89,8 +89,9 @@ static void output_cursor_get_box(struct wlr_output_cursor *cursor, void wlr_output_add_software_cursors_to_render_pass(struct wlr_output *output, struct wlr_render_pass *render_pass, const pixman_region32_t *damage) { + // TODO: pass output state from caller int width, height; - wlr_output_transformed_resolution(output, &width, &height); + wlr_output_transformed_resolution(output, NULL, &width, &height); struct wlr_output_cursor *cursor; wl_list_for_each(cursor, &output->cursors, link) { @@ -158,7 +159,7 @@ static void output_cursor_reset(struct wlr_output_cursor *cursor) { static void output_cursor_update_visible(struct wlr_output_cursor *cursor) { struct wlr_box output_box; output_box.x = output_box.y = 0; - wlr_output_transformed_resolution(cursor->output, &output_box.width, + wlr_output_transformed_resolution(cursor->output, NULL, &output_box.width, &output_box.height); struct wlr_box cursor_box; diff --git a/types/output/output.c b/types/output/output.c index a352a5e59..1a0df6c2b 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -441,19 +441,24 @@ void wlr_output_destroy(struct wlr_output *output) { } void wlr_output_transformed_resolution(struct wlr_output *output, - int *width, int *height) { - if (output->transform % 2 == 0) { - *width = output->width; - *height = output->height; - } else { - *width = output->height; - *height = output->width; + const struct wlr_output_state *state, int *width, int *height) { + output_pending_resolution(output, state, width, height); + + enum wl_output_transform transform = output->transform; + if (state && state->committed & WLR_OUTPUT_STATE_TRANSFORM) { + transform = state->transform; + } + + if (transform % 2 != 0) { + int tmp = *width; + *width = *height; + *height = tmp; } } void wlr_output_effective_resolution(struct wlr_output *output, int *width, int *height) { - wlr_output_transformed_resolution(output, width, height); + wlr_output_transformed_resolution(output, NULL, width, height); *width /= output->scale; *height /= output->scale; } @@ -476,7 +481,7 @@ struct wlr_output_mode *wlr_output_preferred_mode(struct wlr_output *output) { 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) { + if (state && state->committed & WLR_OUTPUT_STATE_MODE) { switch (state->mode_type) { case WLR_OUTPUT_STATE_MODE_FIXED: *width = state->mode->width; diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 62ff576bf..bb5faa9f2 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -339,7 +339,7 @@ static void logical_to_buffer_coords(pixman_region32_t *damage, const struct ren static void output_to_buffer_coords(pixman_region32_t *damage, struct wlr_output *output) { int width, height; - wlr_output_transformed_resolution(output, &width, &height); + wlr_output_transformed_resolution(output, NULL, &width, &height); wlr_region_transform(damage, damage, wlr_output_transform_invert(output->transform), width, height); @@ -1579,7 +1579,7 @@ static void scene_output_handle_damage(struct wl_listener *listener, void *data) struct wlr_output_event_damage *event = data; int width, height; - wlr_output_transformed_resolution(output, &width, &height); + wlr_output_transformed_resolution(output, NULL, &width, &height); pixman_region32_t damage; pixman_region32_init(&damage); From 34ec9319d0bd4705366fd880950643f35c8cfdcc Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 5 Dec 2023 20:36:52 -0500 Subject: [PATCH 3/7] wlr_output: Make wlr_output_effective_resolution take state --- examples/fullscreen-shell.c | 2 +- examples/output-layers.c | 2 +- examples/rotation.c | 2 +- examples/tablet.c | 2 +- examples/touch.c | 2 +- include/wlr/types/wlr_output.h | 2 +- types/output/output.c | 14 ++++++++++---- types/scene/wlr_scene.c | 4 ++-- types/wlr_output_layout.c | 2 +- types/wlr_screencopy_v1.c | 2 +- types/wlr_xdg_output_v1.c | 2 +- 11 files changed, 21 insertions(+), 15 deletions(-) diff --git a/examples/fullscreen-shell.c b/examples/fullscreen-shell.c index 956d851af..6a758f22f 100644 --- a/examples/fullscreen-shell.c +++ b/examples/fullscreen-shell.c @@ -86,7 +86,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); int width, height; - wlr_output_effective_resolution(output->wlr_output, &width, &height); + wlr_output_effective_resolution(output->wlr_output, NULL, &width, &height); struct wlr_output_state state; wlr_output_state_init(&state); diff --git a/examples/output-layers.c b/examples/output-layers.c index 0535ff0b1..dc1a83f6a 100644 --- a/examples/output-layers.c +++ b/examples/output-layers.c @@ -92,7 +92,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { } int width, height; - wlr_output_effective_resolution(output->wlr_output, &width, &height); + wlr_output_effective_resolution(output->wlr_output, NULL, &width, &height); struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &output_state, NULL); wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ diff --git a/examples/rotation.c b/examples/rotation.c index 18bfbd38d..a50297f70 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -55,7 +55,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { clock_gettime(CLOCK_MONOTONIC, &now); int32_t width, height; - wlr_output_effective_resolution(wlr_output, &width, &height); + wlr_output_effective_resolution(wlr_output, NULL, &width, &height); struct wlr_output_state output_state; wlr_output_state_init(&output_state); diff --git a/examples/tablet.c b/examples/tablet.c index 78666fff7..658895a1d 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -85,7 +85,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { clock_gettime(CLOCK_MONOTONIC, &now); int32_t width, height; - wlr_output_effective_resolution(wlr_output, &width, &height); + wlr_output_effective_resolution(wlr_output, NULL, &width, &height); struct wlr_output_state output_state; wlr_output_state_init(&output_state); diff --git a/examples/touch.c b/examples/touch.c index b891837a4..03ce2dee0 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -72,7 +72,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = sample_output->output; int32_t width, height; - wlr_output_effective_resolution(wlr_output, &width, &height); + wlr_output_effective_resolution(wlr_output, NULL, &width, &height); struct wlr_output_state output_state; wlr_output_state_init(&output_state); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 1de0673f9..0e45f4697 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -344,7 +344,7 @@ void wlr_output_transformed_resolution(struct wlr_output *output, * Computes the transformed and scaled output resolution. */ void wlr_output_effective_resolution(struct wlr_output *output, - int *width, int *height); + const struct wlr_output_state *state, int *width, int *height); /** * Test whether this output state would be accepted by the backend. If this * function returns true, wlr_output_commit_state() will only fail due to a diff --git a/types/output/output.c b/types/output/output.c index 1a0df6c2b..c388e8a9b 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -457,10 +457,16 @@ void wlr_output_transformed_resolution(struct wlr_output *output, } void wlr_output_effective_resolution(struct wlr_output *output, - int *width, int *height) { - wlr_output_transformed_resolution(output, NULL, width, height); - *width /= output->scale; - *height /= output->scale; + const struct wlr_output_state *state, int *width, int *height) { + wlr_output_transformed_resolution(output, state, width, height); + + float scale = output->scale; + if (state && state->committed & WLR_OUTPUT_STATE_SCALE) { + scale = state->scale; + } + + *width /= scale; + *height /= scale; } struct wlr_output_mode *wlr_output_preferred_mode(struct wlr_output *output) { diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index bb5faa9f2..65be89631 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -445,7 +445,7 @@ static void update_node_update_outputs(struct wlr_scene_node *node, .x = scene_output->x, .y = scene_output->y, }; - wlr_output_effective_resolution(scene_output->output, + wlr_output_effective_resolution(scene_output->output, NULL, &output_box.width, &output_box.height); pixman_region32_t intersection; @@ -2337,7 +2337,7 @@ static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box, void wlr_scene_output_for_each_buffer(struct wlr_scene_output *scene_output, wlr_scene_buffer_iterator_func_t iterator, void *user_data) { struct wlr_box box = { .x = scene_output->x, .y = scene_output->y }; - wlr_output_effective_resolution(scene_output->output, + wlr_output_effective_resolution(scene_output->output, NULL, &box.width, &box.height); scene_output_for_each_scene_buffer(&box, &scene_output->scene->tree.node, 0, 0, iterator, user_data); diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index ef2751179..fe4a297fd 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -71,7 +71,7 @@ static void output_layout_output_get_box( struct wlr_box *box) { box->x = l_output->x; box->y = l_output->y; - wlr_output_effective_resolution(l_output->output, + wlr_output_effective_resolution(l_output->output, NULL, &box->width, &box->height); } diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index d039659d4..97a7e5675 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -584,7 +584,7 @@ static void capture_output(struct wl_client *wl_client, buffer_box.height = output->height; } else { int ow, oh; - wlr_output_effective_resolution(output, &ow, &oh); + wlr_output_effective_resolution(output, NULL, &ow, &oh); buffer_box = *box; diff --git a/types/wlr_xdg_output_v1.c b/types/wlr_xdg_output_v1.c index 262123987..6b86d2d68 100644 --- a/types/wlr_xdg_output_v1.c +++ b/types/wlr_xdg_output_v1.c @@ -46,7 +46,7 @@ static void output_update(struct wlr_xdg_output_v1 *xdg_output) { } int width, height; - wlr_output_effective_resolution(layout_output->output, &width, &height); + wlr_output_effective_resolution(layout_output->output, NULL, &width, &height); if (xdg_output->width != width || xdg_output->height != height) { xdg_output->width = width; xdg_output->height = height; From 9b1bdf74750fc52bb702d51d76fc6531818d4f93 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 21 Aug 2024 11:12:22 -0400 Subject: [PATCH 4/7] examples: Modeset with a buffer This means that for most examples, rendering code had to be extracted so that it could be called during modeset and during a regular refresh. --- examples/cairo-buffer.c | 1 + examples/fullscreen-shell.c | 21 +++++++++------ examples/output-layers.c | 41 ++++++++++++++++------------- examples/output-layout.c | 21 ++++++++------- examples/pointer.c | 34 +++++++++++++------------ examples/rotation.c | 51 +++++++++++++++++++++---------------- examples/scene-graph.c | 1 + examples/simple.c | 32 +++++++++++++---------- examples/tablet.c | 29 ++++++++++++--------- examples/touch.c | 27 +++++++++++--------- 10 files changed, 147 insertions(+), 111 deletions(-) diff --git a/examples/cairo-buffer.c b/examples/cairo-buffer.c index 6392b2ac5..0000744ae 100644 --- a/examples/cairo-buffer.c +++ b/examples/cairo-buffer.c @@ -116,6 +116,7 @@ static void server_handle_new_output(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } + wlr_scene_output_build_state(output->scene_output, &state, NULL); wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); } diff --git a/examples/fullscreen-shell.c b/examples/fullscreen-shell.c index 6a758f22f..084f25138 100644 --- a/examples/fullscreen-shell.c +++ b/examples/fullscreen-shell.c @@ -79,18 +79,13 @@ static void render_surface(struct wlr_surface *surface, wlr_surface_send_frame_done(surface, rdata->when); } -static void output_handle_frame(struct wl_listener *listener, void *data) { - struct fullscreen_output *output = - wl_container_of(listener, output, frame); - +static void render(struct fullscreen_output *output, struct wlr_output_state *state) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); int width, height; - wlr_output_effective_resolution(output->wlr_output, NULL, &width, &height); + wlr_output_effective_resolution(output->wlr_output, state, &width, &height); - struct wlr_output_state state; - wlr_output_state_init(&state); - struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &state, NULL); + struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, state, NULL); if (pass == NULL) { return; } @@ -110,6 +105,15 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { } wlr_render_pass_submit(pass); +} + +static void output_handle_frame(struct wl_listener *listener, void *data) { + struct fullscreen_output *output = + wl_container_of(listener, output, frame); + + struct wlr_output_state state; + wlr_output_state_init(&state); + render(output, &state); wlr_output_commit_state(output->wlr_output, &state); wlr_output_state_finish(&state); } @@ -169,6 +173,7 @@ static void server_handle_new_output(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } + render(output, &state); wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); } diff --git a/examples/output-layers.c b/examples/output-layers.c index dc1a83f6a..ec2b16bf5 100644 --- a/examples/output-layers.c +++ b/examples/output-layers.c @@ -61,8 +61,9 @@ struct output { struct wl_listener frame; }; -static void output_handle_frame(struct wl_listener *listener, void *data) { - struct output *output = wl_container_of(listener, output, frame); +static void render_and_commit(struct output *output, struct wlr_output_state *state) { + int width, height; + wlr_output_effective_resolution(output->wlr_output, state, &width, &height); struct wl_array layers_arr = {0}; struct output_surface *output_surface; @@ -81,22 +82,19 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { }; } - struct wlr_output_state output_state; - wlr_output_state_init(&output_state); - wlr_output_state_set_layers(&output_state, layers_arr.data, - layers_arr.size / sizeof(struct wlr_output_layer_state)); + // don't submit output layers for modeset or enable. + if ((state->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_ENABLED)) == 0) { + wlr_output_state_set_layers(state, layers_arr.data, + layers_arr.size / sizeof(struct wlr_output_layer_state)); - if (!wlr_output_test_state(output->wlr_output, &output_state)) { - wlr_log(WLR_ERROR, "wlr_output_test_state() failed"); - return; + if (!wlr_output_test_state(output->wlr_output, state)) { + wlr_log(WLR_ERROR, "wlr_output_test_state() failed"); + return; + } } - int width, height; - wlr_output_effective_resolution(output->wlr_output, NULL, &width, &height); - - struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &output_state, NULL); + struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, state, NULL); wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ - .box = { .width = width, .height = height }, .color = { 0.3, 0.3, 0.3, 1 }, }); @@ -125,9 +123,6 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { wlr_render_pass_submit(pass); - wlr_output_commit_state(output->wlr_output, &output_state); - wlr_output_state_finish(&output_state); - struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -154,9 +149,19 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { output_surface->first_commit = false; } + wlr_output_commit_state(output->wlr_output, state); wl_array_release(&layers_arr); } +static void output_handle_frame(struct wl_listener *listener, void *data) { + struct output *output = wl_container_of(listener, output, frame); + + struct wlr_output_state output_state; + wlr_output_state_init(&output_state); + render_and_commit(output, &output_state); + wlr_output_state_finish(&output_state); +} + static void server_handle_new_output(struct wl_listener *listener, void *data) { struct server *server = wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; @@ -178,7 +183,7 @@ static void server_handle_new_output(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } - wlr_output_commit_state(wlr_output, &state); + render_and_commit(output, &state); wlr_output_state_finish(&state); wlr_output_create_global(wlr_output, server->wl_display); diff --git a/examples/output-layout.c b/examples/output-layout.c index c481ddf80..dca532584 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -107,17 +107,11 @@ static void animate_cat(struct sample_state *sample, sample->ts_last = ts; } -static void output_frame_notify(struct wl_listener *listener, void *data) { - struct sample_output *output = wl_container_of(listener, output, frame); +static void render(struct sample_output *output, struct wlr_output_state *state) { + struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->output, state, NULL); struct sample_state *sample = output->sample; - struct wlr_output *wlr_output = output->output; - - struct wlr_output_state output_state; - wlr_output_state_init(&output_state); - struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL); wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ - .box = { .width = wlr_output->width, .height = wlr_output->height }, .color = { 0.25, 0.25, 0.25, 1 }, }); @@ -141,7 +135,15 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } wlr_render_pass_submit(pass); - wlr_output_commit_state(wlr_output, &output_state); +} + +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *output = wl_container_of(listener, output, frame); + + struct wlr_output_state output_state; + wlr_output_state_init(&output_state); + render(output, &output_state); + wlr_output_commit_state(output->output, &output_state); wlr_output_state_finish(&output_state); } @@ -182,6 +184,7 @@ static void new_output_notify(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } + render(sample_output, &state); wlr_output_commit_state(output, &state); wlr_output_state_finish(&state); } diff --git a/examples/pointer.c b/examples/pointer.c index f3ef5435e..64853f1e6 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -92,28 +92,29 @@ static void warp_to_touch(struct sample_state *state, wlr_cursor_warp_absolute(state->cursor, dev, x, y); } -static void output_frame_notify(struct wl_listener *listener, void *data) { - struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); - struct sample_state *state = sample_output->state; - struct wlr_output *wlr_output = sample_output->output; - struct wlr_renderer *renderer = state->renderer; - assert(renderer); - - struct wlr_output_state output_state; - wlr_output_state_init(&output_state); - struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL); +static void render(struct sample_output *output, struct wlr_output_state *state) { + struct wlr_output *wlr_output = output->output; + struct sample_state *sample_state = output->state; + struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, state, NULL); wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ - .box = { .width = wlr_output->width, .height = wlr_output->height }, .color = { - state->clear_color[0], - state->clear_color[1], - state->clear_color[2], - state->clear_color[3], + sample_state->clear_color[0], + sample_state->clear_color[1], + sample_state->clear_color[2], + sample_state->clear_color[3], }, }); wlr_output_add_software_cursors_to_render_pass(wlr_output, pass, NULL); wlr_render_pass_submit(pass); - wlr_output_commit_state(wlr_output, &output_state); +} + +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); + + struct wlr_output_state output_state; + wlr_output_state_init(&output_state); + render(sample_output, &output_state); + wlr_output_commit_state(sample_output->output, &output_state); wlr_output_state_finish(&output_state); } @@ -280,6 +281,7 @@ static void new_output_notify(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } + render(sample_output, &state); wlr_output_commit_state(output, &state); wlr_output_state_finish(&state); } diff --git a/examples/rotation.c b/examples/rotation.c index a50297f70..82f517ea0 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -47,27 +47,25 @@ struct sample_keyboard { struct wl_listener destroy; }; -static void output_frame_notify(struct wl_listener *listener, void *data) { - struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); - struct sample_state *sample = sample_output->sample; - struct wlr_output *wlr_output = sample_output->output; +static void render (struct sample_output *output, struct wlr_output_state *state) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - int32_t width, height; - wlr_output_effective_resolution(wlr_output, NULL, &width, &height); - struct wlr_output_state output_state; - wlr_output_state_init(&output_state); - struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL); + struct sample_state *sample = output->sample; + struct wlr_output *wlr_output = output->output; + struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, state, NULL); + + int32_t width, height; + wlr_output_effective_resolution(wlr_output, state, &width, &height); + wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ - .box = { .width = wlr_output->width, .height = wlr_output->height }, .color = { 0.25, 0.25, 0.25, 1 }, }); - for (int y = -128 + (int)sample_output->y_offs; y < height; y += 128) { - for (int x = -128 + (int)sample_output->x_offs; x < width; x += 128) { + for (int y = -128 + (int)output->y_offs; y < height; y += 128) { + for (int x = -128 + (int)output->x_offs; x < width; x += 128) { wlr_render_pass_add_texture(pass, &(struct wlr_render_texture_options){ .texture = sample->cat_texture, .dst_box = { .x = x, .y = y }, @@ -77,24 +75,32 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } wlr_render_pass_submit(pass); - wlr_output_commit_state(wlr_output, &output_state); - wlr_output_state_finish(&output_state); long ms = (now.tv_sec - sample->last_frame.tv_sec) * 1000 + (now.tv_nsec - sample->last_frame.tv_nsec) / 1000000; float seconds = ms / 1000.0f; + output->x_offs += output->x_vel * seconds; + output->y_offs += output->y_vel * seconds; + if (output->x_offs > 128) { + output->x_offs = 0; + } + if (output->y_offs > 128) { + output->y_offs = 0; + } - sample_output->x_offs += sample_output->x_vel * seconds; - sample_output->y_offs += sample_output->y_vel * seconds; - if (sample_output->x_offs > 128) { - sample_output->x_offs = 0; - } - if (sample_output->y_offs > 128) { - sample_output->y_offs = 0; - } sample->last_frame = now; } +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); + + struct wlr_output_state output_state; + wlr_output_state_init(&output_state); + render(sample_output, &output_state); + wlr_output_commit_state(sample_output->output, &output_state); + wlr_output_state_finish(&output_state); +} + static void update_velocities(struct sample_state *sample, float x_diff, float y_diff) { struct sample_output *sample_output; @@ -137,6 +143,7 @@ static void new_output_notify(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } + render(sample_output, &state); wlr_output_commit_state(output, &state); wlr_output_state_finish(&state); } diff --git a/examples/scene-graph.c b/examples/scene-graph.c index 421986534..e57ce9c90 100644 --- a/examples/scene-graph.c +++ b/examples/scene-graph.c @@ -86,6 +86,7 @@ static void server_handle_new_output(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } + wlr_scene_output_build_state(output->scene_output, &state, NULL); wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); diff --git a/examples/simple.c b/examples/simple.c index d16708654..dd0690ce7 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -39,11 +39,25 @@ struct sample_keyboard { struct wl_listener destroy; }; +static void render(struct sample_output *output, struct wlr_output_state *state) { + struct wlr_output *wlr_output = output->output; + struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, state, NULL); + wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ + .box = { .width = wlr_output->width, .height = wlr_output->height }, + .color = { + .r = output->sample->color[0], + .g = output->sample->color[1], + .b = output->sample->color[2], + .a = output->sample->color[3], + }, + }); + wlr_render_pass_submit(pass); +} + static void output_frame_notify(struct wl_listener *listener, void *data) { struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); struct sample_state *sample = sample_output->sample; - struct wlr_output *wlr_output = sample_output->output; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -63,19 +77,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct wlr_output_state state; wlr_output_state_init(&state); - struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &state, NULL); - wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ - .box = { .width = wlr_output->width, .height = wlr_output->height }, - .color = { - .r = sample->color[0], - .g = sample->color[1], - .b = sample->color[2], - .a = sample->color[3], - }, - }); - wlr_render_pass_submit(pass); - - wlr_output_commit_state(wlr_output, &state); + render(sample_output, &state); + wlr_output_commit_state(sample_output->output, &state); wlr_output_state_finish(&state); sample->last_frame = now; } @@ -111,6 +114,7 @@ static void new_output_notify(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } + render(sample_output, &state); wlr_output_commit_state(output, &state); wlr_output_state_finish(&state); } diff --git a/examples/tablet.c b/examples/tablet.c index 658895a1d..32adf5f44 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -77,22 +77,18 @@ struct sample_keyboard { struct wl_listener destroy; }; -static void output_frame_notify(struct wl_listener *listener, void *data) { - struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); - struct sample_state *sample = sample_output->sample; - struct wlr_output *wlr_output = sample_output->output; +static void render(struct sample_output *output, struct wlr_output_state *state) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); + struct wlr_output *wlr_output = output->output; + struct sample_state *sample = output->sample; + int32_t width, height; - wlr_output_effective_resolution(wlr_output, NULL, &width, &height); - - struct wlr_output_state output_state; - wlr_output_state_init(&output_state); - struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL); + wlr_output_effective_resolution(wlr_output, state, &width, &height); + struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, state, NULL); wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ - .box = { .width = wlr_output->width, .height = wlr_output->height }, .color = { 0.25, 0.25, 0.25, 1 }, }); @@ -157,11 +153,19 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } wlr_render_pass_submit(pass); - wlr_output_commit_state(wlr_output, &output_state); - wlr_output_state_finish(&output_state); sample->last_frame = now; } +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); + + struct wlr_output_state output_state; + wlr_output_state_init(&output_state); + render(sample_output, &output_state); + wlr_output_commit_state(sample_output->output, &output_state); + wlr_output_state_finish(&output_state); +} + static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) { struct tablet_tool_state *tstate = wl_container_of(listener, tstate, axis); struct wlr_tablet_tool_axis_event *event = data; @@ -285,6 +289,7 @@ static void new_output_notify(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } + render(sample_output, &state); wlr_output_commit_state(output, &state); wlr_output_state_finish(&state); } diff --git a/examples/touch.c b/examples/touch.c index 03ce2dee0..23bba2c28 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -63,22 +63,16 @@ struct sample_keyboard { struct wl_listener destroy; }; -static void output_frame_notify(struct wl_listener *listener, void *data) { - struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); - struct sample_state *sample = sample_output->sample; +static void render(struct sample_output *output, struct wlr_output_state *state) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - struct wlr_output *wlr_output = sample_output->output; - int32_t width, height; - wlr_output_effective_resolution(wlr_output, NULL, &width, &height); + wlr_output_effective_resolution(output->output, state, &width, &height); + struct sample_state *sample = output->sample; - struct wlr_output_state output_state; - wlr_output_state_init(&output_state); - struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL); + struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->output, state, NULL); wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ - .box = { .width = width, .height = height }, .color = { 0.25, 0.25, 0.25, 1 }, }); @@ -93,11 +87,19 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } wlr_render_pass_submit(pass); - wlr_output_commit_state(wlr_output, &output_state); - wlr_output_state_finish(&output_state); sample->last_frame = now; } +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); + + struct wlr_output_state output_state; + wlr_output_state_init(&output_state); + render(sample_output, &output_state); + wlr_output_commit_state(sample_output->output, &output_state); + wlr_output_state_finish(&output_state); +} + static void touch_down_notify(struct wl_listener *listener, void *data) { struct wlr_touch_down_event *event = data; struct touch_state *tstate = wl_container_of(listener, tstate, down); @@ -188,6 +190,7 @@ static void new_output_notify(struct wl_listener *listener, void *data) { if (mode != NULL) { wlr_output_state_set_mode(&state, mode); } + render(sample_output, &state); wlr_output_commit_state(output, &state); wlr_output_state_finish(&state); } From 3f0a10bad03796dd8bee8b35c25cb4e19b2bd901 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 11 Sep 2023 03:28:46 -0400 Subject: [PATCH 5/7] wlr_output: Don't allow commits enabling an output with no buffer --- types/output/output.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/types/output/output.c b/types/output/output.c index c388e8a9b..e73cc1b69 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -636,8 +636,13 @@ static bool output_basic_test(struct wlr_output *output, wlr_drm_format_finish(&format); } - bool enabled = output_pending_enabled(output, state); + if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled && + (state->committed & WLR_OUTPUT_STATE_BUFFER) == 0) { + wlr_log(WLR_DEBUG, "Tried to enable an output without a buffer"); + return false; + } + bool enabled = output_pending_enabled(output, state); if (enabled && (state->committed & (WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_MODE))) { int pending_width, pending_height; From 3ae9c80ddf4a723b0ee5262314ff95c0992f9539 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 6 Dec 2023 02:22:35 -0500 Subject: [PATCH 6/7] wlr_output: Don't allow commits changing render format without a buffer --- types/output/output.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/types/output/output.c b/types/output/output.c index e73cc1b69..83e9653cc 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -621,6 +621,12 @@ static bool output_basic_test(struct wlr_output *output, } } + if ((state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) && + (state->committed & WLR_OUTPUT_STATE_BUFFER) == 0) { + wlr_log(WLR_DEBUG, "Tried to change the render format without a buffer."); + return false; + } + if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { struct wlr_allocator *allocator = output->allocator; assert(allocator != NULL); From b3ccec61486934aa1fa04bebb192752bf0df2f5a Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 5 Dec 2023 20:06:52 -0500 Subject: [PATCH 7/7] output: Remove output_ensure_buffer Compositors are now required to commit a buffer themselves when they modeset. --- include/types/wlr_output.h | 2 - types/output/output.c | 23 +--------- types/output/render.c | 94 -------------------------------------- 3 files changed, 1 insertion(+), 118 deletions(-) diff --git a/include/types/wlr_output.h b/include/types/wlr_output.h index 2dc979c66..5784efdec 100644 --- a/include/types/wlr_output.h +++ b/include/types/wlr_output.h @@ -12,8 +12,6 @@ bool output_pending_enabled(struct wlr_output *output, bool output_pick_format(struct wlr_output *output, const struct wlr_drm_format_set *display_formats, struct wlr_drm_format *format, uint32_t fmt); -bool output_ensure_buffer(struct wlr_output *output, - struct wlr_output_state *state, bool *new_back_buffer); bool output_cursor_set_texture(struct wlr_output_cursor *cursor, struct wlr_texture *texture, bool own_texture, const struct wlr_fbox *src_box, diff --git a/types/output/output.c b/types/output/output.c index 83e9653cc..9407895bb 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -721,16 +721,7 @@ bool wlr_output_test_state(struct wlr_output *output, return true; } - bool new_back_buffer = false; - if (!output_ensure_buffer(output, ©, &new_back_buffer)) { - return false; - } - - bool success = output->impl->test(output, ©); - if (new_back_buffer) { - wlr_buffer_unlock(copy.buffer); - } - return success; + return output->impl->test(output, ©); } bool output_prepare_commit(struct wlr_output *output, const struct wlr_output_state *state) { @@ -792,28 +783,16 @@ bool wlr_output_commit_state(struct wlr_output *output, return false; } - bool new_back_buffer = false; - if (!output_ensure_buffer(output, &pending, &new_back_buffer)) { - return false; - } - if (!output_prepare_commit(output, &pending)) { return false; } if (!output->impl->commit(output, &pending)) { - if (new_back_buffer) { - wlr_buffer_unlock(pending.buffer); - } return false; } output_apply_commit(output, &pending); - if (new_back_buffer) { - wlr_buffer_unlock(pending.buffer); - } - return true; } diff --git a/types/output/render.c b/types/output/render.c index 155da5cf8..f841fe87c 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -38,100 +38,6 @@ bool wlr_output_init_render(struct wlr_output *output, return true; } -static struct wlr_buffer *output_acquire_empty_buffer(struct wlr_output *output, - const struct wlr_output_state *state) { - assert(!(state->committed & WLR_OUTPUT_STATE_BUFFER)); - - // wlr_output_configure_primary_swapchain() function will call - // wlr_output_test_state(), which can call us again. This is dangerous: we - // risk infinite recursion. However, a buffer will always be supplied in - // wlr_output_test_state(), which will prevent us from being called. - if (!wlr_output_configure_primary_swapchain(output, state, - &output->swapchain)) { - return NULL; - } - - struct wlr_buffer *buffer = wlr_swapchain_acquire(output->swapchain); - if (buffer == NULL) { - return NULL; - } - - struct wlr_render_pass *pass = - wlr_renderer_begin_buffer_pass(output->renderer, buffer, NULL); - if (pass == NULL) { - wlr_buffer_unlock(buffer); - return NULL; - } - - wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){ - .color = { 0, 0, 0, 0 }, - .blend_mode = WLR_RENDER_BLEND_MODE_NONE, - }); - - if (!wlr_render_pass_submit(pass)) { - wlr_buffer_unlock(buffer); - return NULL; - } - - return buffer; -} - -// This function may attach a new, empty buffer if necessary. -// If so, the new_back_buffer out parameter will be set to true. -bool output_ensure_buffer(struct wlr_output *output, - struct wlr_output_state *state, bool *new_buffer) { - assert(*new_buffer == false); - - // If we already have a buffer, we don't need to allocate a new one - if (state->committed & WLR_OUTPUT_STATE_BUFFER) { - return true; - } - - // If the compositor hasn't called wlr_output_init_render(), they will use - // their own logic to attach buffers - if (output->renderer == NULL) { - return true; - } - - bool enabled = output->enabled; - if (state->committed & WLR_OUTPUT_STATE_ENABLED) { - enabled = state->enabled; - } - - // If we're lighting up an output or changing its mode, make sure to - // provide a new buffer - bool needs_new_buffer = false; - if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) { - needs_new_buffer = true; - } - if (state->committed & WLR_OUTPUT_STATE_MODE) { - needs_new_buffer = true; - } - if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { - needs_new_buffer = true; - } - if (state->allow_reconfiguration && output->commit_seq == 0 && enabled) { - // On first commit, require a new buffer if the compositor called a - // mode-setting function, even if the mode won't change. This makes it - // so the swapchain is created now. - needs_new_buffer = true; - } - if (!needs_new_buffer) { - return true; - } - - wlr_log(WLR_DEBUG, "Attaching empty buffer to output for modeset"); - struct wlr_buffer *buffer = output_acquire_empty_buffer(output, state); - if (buffer == NULL) { - return false; - } - - *new_buffer = true; - wlr_output_state_set_buffer(state, buffer); - wlr_buffer_unlock(buffer); - return true; -} - void wlr_output_lock_attach_render(struct wlr_output *output, bool lock) { if (lock) { ++output->attach_render_locks;