Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 4205845

Browse files
committed
examples/explicit-sync: new example
1 parent 05b36e2 commit 4205845

2 files changed

Lines changed: 258 additions & 0 deletions

File tree

examples/explicit-sync.c

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
#define _POSIX_C_SOURCE 200112L
2+
#include <assert.h>
3+
#include <getopt.h>
4+
#include <stdbool.h>
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#include <time.h>
8+
#include <unistd.h>
9+
#include <wayland-server-core.h>
10+
#include <wlr/backend.h>
11+
#include <wlr/render/timeline.h>
12+
#include <wlr/render/wlr_renderer.h>
13+
#include <wlr/types/wlr_compositor.h>
14+
#include <wlr/types/wlr_linux_explicit_synchronization_v1.h>
15+
#include <wlr/types/wlr_output.h>
16+
#include <wlr/types/wlr_surface.h>
17+
#include <wlr/types/wlr_xdg_shell.h>
18+
#include <wlr/util/log.h>
19+
20+
/* Simple compositor with explicit synchronization support. Input is
21+
* unimplemented.
22+
*
23+
* New surfaces are stacked on top of the existing ones as they appear. */
24+
25+
struct server {
26+
struct wl_display *display;
27+
struct wlr_backend *backend;
28+
struct wlr_renderer *renderer;
29+
struct wlr_linux_explicit_synchronization_v1 *explicit_sync_v1;
30+
31+
struct wl_list outputs;
32+
struct wl_list surfaces;
33+
34+
struct wl_listener new_output;
35+
struct wl_listener new_surface;
36+
};
37+
38+
struct surface {
39+
struct wlr_surface *wlr;
40+
struct wl_list link;
41+
42+
struct wlr_render_timeline *timeline;
43+
44+
struct wl_listener destroy;
45+
};
46+
47+
struct output {
48+
struct wl_list link;
49+
struct server *server;
50+
struct wlr_output *wlr;
51+
52+
struct wlr_render_timeline *in_timeline, *out_timeline;
53+
54+
struct wl_listener frame;
55+
};
56+
57+
static void output_handle_frame(struct wl_listener *listener, void *data) {
58+
struct output *output = wl_container_of(listener, output, frame);
59+
struct wlr_renderer *renderer = output->server->renderer;
60+
61+
if (!wlr_output_attach_render(output->wlr, NULL)) {
62+
return;
63+
}
64+
65+
wlr_renderer_begin(renderer, output->wlr->width, output->wlr->height);
66+
wlr_renderer_clear(renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
67+
68+
struct timespec now;
69+
clock_gettime(CLOCK_MONOTONIC, &now);
70+
71+
int pos = 0;
72+
struct surface *surface;
73+
wl_list_for_each(surface, &output->server->surfaces, link) {
74+
pos += 50;
75+
76+
struct wlr_texture *texture = wlr_surface_get_texture(surface->wlr);
77+
if (texture == NULL) {
78+
continue;
79+
}
80+
81+
uint64_t surface_point = surface->wlr->current.seq;
82+
if (!wlr_linux_explicit_synchronization_v1_signal_surface_timeline(
83+
output->server->explicit_sync_v1, surface->wlr,
84+
surface->timeline, surface_point)) {
85+
wlr_log(WLR_ERROR, "Failed to signal surface timeline");
86+
continue;
87+
}
88+
if (!wlr_renderer_wait_timeline(renderer,
89+
surface->timeline, surface_point)) {
90+
wlr_log(WLR_ERROR, "Failed to wait for surface timeline");
91+
continue;
92+
}
93+
94+
wlr_render_texture(renderer, texture, output->wlr->transform_matrix,
95+
pos, pos, 1.0);
96+
97+
wlr_surface_send_frame_done(surface->wlr, &now);
98+
}
99+
100+
uint64_t output_point = output->wlr->commit_seq;
101+
if (!wlr_renderer_signal_timeline(renderer, output->in_timeline,
102+
output_point)) {
103+
wlr_log(WLR_ERROR, "Failed to signal renderer timeline");
104+
return;
105+
}
106+
107+
wlr_renderer_end(renderer);
108+
109+
wlr_output_set_wait_timeline(output->wlr,
110+
output->in_timeline, output_point);
111+
wlr_output_set_signal_timeline(output->wlr,
112+
output->out_timeline, output_point);
113+
114+
if (!wlr_output_commit(output->wlr)) {
115+
wlr_log(WLR_ERROR, "Failed to commit output");
116+
return;
117+
}
118+
119+
wl_list_for_each(surface, &output->server->surfaces, link) {
120+
if (!wlr_linux_explicit_synchronization_v1_wait_surface_timeline(
121+
output->server->explicit_sync_v1, surface->wlr,
122+
output->out_timeline, output_point)) {
123+
wlr_log(WLR_ERROR, "Failed to wait for surface timeline");
124+
}
125+
}
126+
}
127+
128+
static void server_handle_new_output(struct wl_listener *listener, void *data) {
129+
struct server *server = wl_container_of(listener, server, new_output);
130+
struct wlr_output *wlr_output = data;
131+
132+
int drm_fd = wlr_renderer_get_drm_fd(server->renderer);
133+
struct wlr_render_timeline *in_timeline = wlr_render_timeline_create(drm_fd);
134+
struct wlr_render_timeline *out_timeline = wlr_render_timeline_create(drm_fd);
135+
if (in_timeline == NULL || out_timeline == NULL) {
136+
return;
137+
}
138+
139+
struct output *output =
140+
calloc(1, sizeof(struct output));
141+
output->wlr = wlr_output;
142+
output->server = server;
143+
output->in_timeline = in_timeline;
144+
output->out_timeline = out_timeline;
145+
output->frame.notify = output_handle_frame;
146+
wl_signal_add(&wlr_output->events.frame, &output->frame);
147+
wl_list_insert(&server->outputs, &output->link);
148+
149+
if (!wl_list_empty(&wlr_output->modes)) {
150+
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
151+
wlr_output_set_mode(wlr_output, mode);
152+
wlr_output_commit(wlr_output);
153+
}
154+
155+
wlr_output_create_global(wlr_output);
156+
}
157+
158+
static void surface_handle_destroy(struct wl_listener *listener, void *data) {
159+
struct surface *surface = wl_container_of(listener, surface, destroy);
160+
wlr_render_timeline_destroy(surface->timeline);
161+
wl_list_remove(&surface->destroy.link);
162+
wl_list_remove(&surface->link);
163+
free(surface);
164+
}
165+
166+
static void server_handle_new_surface(struct wl_listener *listener,
167+
void *data) {
168+
struct server *server = wl_container_of(listener, server, new_surface);
169+
struct wlr_surface *wlr_surface = data;
170+
171+
int drm_fd = wlr_renderer_get_drm_fd(server->renderer);
172+
struct wlr_render_timeline *timeline = wlr_render_timeline_create(drm_fd);
173+
if (timeline == NULL) {
174+
return;
175+
}
176+
177+
struct surface *surface = calloc(1, sizeof(struct surface));
178+
surface->wlr = wlr_surface;
179+
surface->timeline = timeline;
180+
surface->destroy.notify = surface_handle_destroy;
181+
wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);
182+
183+
wl_list_insert(&server->surfaces, &surface->link);
184+
}
185+
186+
int main(int argc, char *argv[]) {
187+
wlr_log_init(WLR_DEBUG, NULL);
188+
189+
const char *startup_cmd = NULL;
190+
int c;
191+
while ((c = getopt(argc, argv, "s:")) != -1) {
192+
switch (c) {
193+
case 's':
194+
startup_cmd = optarg;
195+
break;
196+
default:
197+
printf("usage: %s [-s startup-command]\n", argv[0]);
198+
return EXIT_FAILURE;
199+
}
200+
}
201+
if (optind < argc) {
202+
printf("usage: %s [-s startup-command]\n", argv[0]);
203+
return EXIT_FAILURE;
204+
}
205+
206+
struct server server = {0};
207+
server.display = wl_display_create();
208+
server.backend = wlr_backend_autocreate(server.display);
209+
server.renderer = wlr_backend_get_renderer(server.backend);
210+
wlr_renderer_init_wl_display(server.renderer, server.display);
211+
212+
struct wlr_compositor *compositor =
213+
wlr_compositor_create(server.display, server.renderer);
214+
215+
wlr_xdg_shell_create(server.display);
216+
217+
server.explicit_sync_v1 =
218+
wlr_linux_explicit_synchronization_v1_create(server.display);
219+
220+
wl_list_init(&server.outputs);
221+
wl_list_init(&server.surfaces);
222+
223+
server.new_output.notify = server_handle_new_output;
224+
wl_signal_add(&server.backend->events.new_output, &server.new_output);
225+
226+
server.new_surface.notify = server_handle_new_surface;
227+
wl_signal_add(&compositor->events.new_surface, &server.new_surface);
228+
229+
const char *socket = wl_display_add_socket_auto(server.display);
230+
if (!socket) {
231+
wl_display_destroy(server.display);
232+
return EXIT_FAILURE;
233+
}
234+
235+
if (!wlr_backend_start(server.backend)) {
236+
wl_display_destroy(server.display);
237+
return EXIT_FAILURE;
238+
}
239+
240+
setenv("WAYLAND_DISPLAY", socket, true);
241+
if (startup_cmd != NULL) {
242+
if (fork() == 0) {
243+
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, (void *)NULL);
244+
}
245+
}
246+
247+
wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s",
248+
socket);
249+
wl_display_run(server.display);
250+
251+
wl_display_destroy_clients(server.display);
252+
wl_display_destroy(server.display);
253+
return EXIT_SUCCESS;
254+
}

examples/meson.build

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ compositors = {
5555
'src': 'scene-graph.c',
5656
'proto': ['xdg-shell'],
5757
},
58+
'explicit-sync': {
59+
'src': 'explicit-sync.c',
60+
'proto': ['xdg-shell'],
61+
},
5862
}
5963

6064
clients = {

0 commit comments

Comments
 (0)