xref: /aosp_15_r20/external/crosvm/gpu_display/src/display_wl.c (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <assert.h>
6 #include <memory.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <poll.h>
15 #include <sys/ioctl.h>
16 #include <sys/mman.h>
17 #include <sys/socket.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 
22 #include "aura-shell.h"
23 #include "linux-dmabuf-unstable-v1.h"
24 #include "viewporter.h"
25 #include "xdg-shell.h"
26 #include "virtio-gpu-metadata-v1.h"
27 #include <wayland-client-core.h>
28 #include <wayland-client-protocol.h>
29 #include <wayland-client.h>
30 
31 // BTN_LEFT is copied from linux/input-event-codes.h because the kernel headers
32 // aren't readily available in some downstream projects.
33 #define BTN_LEFT 0x110
34 
35 #define DEFAULT_SCALE 2
36 #define MAX_BUFFER_COUNT 64
37 #define EVENT_BUF_SIZE 256
38 
39 const int32_t DWL_KEYBOARD_KEY_STATE_RELEASED = WL_KEYBOARD_KEY_STATE_RELEASED;
40 const int32_t DWL_KEYBOARD_KEY_STATE_PRESSED  = WL_KEYBOARD_KEY_STATE_PRESSED;
41 
42 const uint32_t DWL_EVENT_TYPE_KEYBOARD_ENTER = 0x00;
43 const uint32_t DWL_EVENT_TYPE_KEYBOARD_LEAVE = 0x01;
44 const uint32_t DWL_EVENT_TYPE_KEYBOARD_KEY   = 0x02;
45 const uint32_t DWL_EVENT_TYPE_POINTER_ENTER  = 0x10;
46 const uint32_t DWL_EVENT_TYPE_POINTER_LEAVE  = 0x11;
47 const uint32_t DWL_EVENT_TYPE_POINTER_MOVE   = 0x12;
48 const uint32_t DWL_EVENT_TYPE_POINTER_BUTTON = 0x13;
49 const uint32_t DWL_EVENT_TYPE_TOUCH_DOWN     = 0x20;
50 const uint32_t DWL_EVENT_TYPE_TOUCH_UP       = 0x21;
51 const uint32_t DWL_EVENT_TYPE_TOUCH_MOTION   = 0x22;
52 
53 const uint32_t DWL_SURFACE_FLAG_RECEIVE_INPUT = 1 << 0;
54 const uint32_t DWL_SURFACE_FLAG_HAS_ALPHA     = 1 << 1;
55 
56 struct dwl_event {
57 	const void *surface_descriptor;
58 	uint32_t event_type;
59 	int32_t params[3];
60 };
61 
62 struct dwl_context;
63 
64 struct interfaces {
65 	struct dwl_context *context;
66 	struct wl_compositor *compositor;
67 	struct wl_subcompositor *subcompositor;
68 	struct wl_shm *shm;
69 	struct wl_seat *seat;
70 	struct zaura_shell *aura; // optional
71 	struct zwp_linux_dmabuf_v1 *linux_dmabuf;
72 	struct xdg_wm_base *xdg_wm_base;
73 	struct wp_viewporter *viewporter; // optional
74 	struct wp_virtio_gpu_metadata_v1 *virtio_gpu_metadata; // optional
75 };
76 
77 struct output {
78 	struct wl_output *output;
79 	struct zaura_output *aura_output;
80 	struct dwl_context *context;
81 	uint32_t id;
82 	uint32_t current_scale;
83 	uint32_t device_scale_factor;
84 	bool internal;
85 };
86 
87 struct input {
88 	struct wl_keyboard *wl_keyboard;
89 	struct wl_pointer *wl_pointer;
90 	struct wl_surface *keyboard_input_surface;
91 	struct wl_surface *pointer_input_surface;
92 	int32_t pointer_x;
93 	int32_t pointer_y;
94 	bool pointer_lbutton_state;
95 };
96 
97 typedef void (*dwl_error_callback_type)(const char *message);
98 
99 struct dwl_context {
100 	struct wl_display *display;
101 	struct dwl_surface *surfaces[MAX_BUFFER_COUNT];
102 	struct dwl_dmabuf *dmabufs[MAX_BUFFER_COUNT];
103 	struct interfaces ifaces;
104 	struct input input;
105 	bool output_added;
106 	struct output outputs[8];
107 
108 	struct dwl_event event_cbuf[EVENT_BUF_SIZE];
109 	size_t event_read_pos;
110 	size_t event_write_pos;
111 
112 	dwl_error_callback_type error_callback;
113 };
114 
115 #define outputs_for_each(context, pos, output)                                 \
116 	for (pos = 0, output = &context->outputs[pos];                         \
117 	     pos < (sizeof(context->outputs) / sizeof(context->outputs[0]));   \
118 	     pos++, output = &context->outputs[pos])
119 
120 struct dwl_dmabuf {
121 	uint32_t width;
122 	uint32_t height;
123 	uint32_t import_id;
124 	bool in_use;
125 	struct wl_buffer *buffer;
126 	struct dwl_context *context;
127 };
128 
129 struct dwl_surface {
130 	struct dwl_context *context;
131 	struct wl_surface *wl_surface;
132 	struct zaura_surface *aura;
133 	struct xdg_surface *xdg_surface;
134 	struct xdg_toplevel *xdg_toplevel;
135 	struct wp_viewport *viewport;
136 	struct wp_virtio_gpu_surface_metadata_v1 *virtio_gpu_surface_metadata;
137 	struct wl_subsurface *subsurface;
138 	uint32_t width;
139 	uint32_t height;
140 	uint32_t surface_id;
141 	double scale;
142 	bool close_requested;
143 	size_t buffer_count;
144 	uint64_t buffer_use_bit_mask;
145 	struct wl_buffer *buffers[0];
146 };
147 
148 static_assert(sizeof(((struct dwl_surface *)0)->buffer_use_bit_mask) * 8 >=
149 		  MAX_BUFFER_COUNT,
150 	      "not enough bits in buffer_use_bit_mask");
151 
output_geometry(void * data,struct wl_output * output,int x,int y,int physical_width,int physical_height,int subpixel,const char * make,const char * model,int transform)152 static void output_geometry(void *data, struct wl_output *output, int x, int y,
153 			    int physical_width, int physical_height,
154 			    int subpixel, const char *make, const char *model,
155 			    int transform)
156 {
157 	(void)data;
158 	(void)output;
159 	(void)x;
160 	(void)y;
161 	(void)physical_width;
162 	(void)physical_height;
163 	(void)subpixel;
164 	(void)make;
165 	(void)model;
166 	(void)transform;
167 }
168 
output_mode(void * data,struct wl_output * output,uint32_t flags,int width,int height,int refresh)169 static void output_mode(void *data, struct wl_output *output, uint32_t flags,
170 			int width, int height, int refresh)
171 {
172 	(void)data;
173 	(void)output;
174 	(void)flags;
175 	(void)width;
176 	(void)height;
177 	(void)refresh;
178 }
179 
output_done(void * data,struct wl_output * output)180 static void output_done(void *data, struct wl_output *output)
181 {
182 	(void)data;
183 	(void)output;
184 }
185 
output_scale(void * data,struct wl_output * wl_output,int32_t scale_factor)186 static void output_scale(void *data, struct wl_output *wl_output,
187 			 int32_t scale_factor)
188 {
189 	(void)wl_output;
190 	struct output *output = (struct output *)data;
191 	struct dwl_context *context = output->context;
192 
193 	// If the aura interface is available, we prefer the scale factor
194 	// reported by that.
195 	if (context->ifaces.aura)
196 		return;
197 
198 	output->current_scale = 1000 * scale_factor;
199 }
200 
201 static const struct wl_output_listener output_listener = {
202     .geometry = output_geometry,
203     .mode = output_mode,
204     .done = output_done,
205     .scale = output_scale};
206 
aura_output_scale(void * data,struct zaura_output * aura_output,uint32_t flags,uint32_t scale)207 static void aura_output_scale(void *data, struct zaura_output *aura_output,
208 			      uint32_t flags, uint32_t scale)
209 {
210 	(void)aura_output;
211 	struct output *output = (struct output *)data;
212 	if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT) {
213 		output->current_scale = scale;
214 	}
215 }
216 
aura_output_connection(void * data,struct zaura_output * aura_output,uint32_t connection)217 static void aura_output_connection(void *data, struct zaura_output *aura_output,
218 				   uint32_t connection)
219 {
220 	(void)aura_output;
221 	struct output *output = (struct output *)data;
222 	output->internal = connection == ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL;
223 }
224 
aura_output_device_scale_factor(void * data,struct zaura_output * aura_output,uint32_t device_scale_factor)225 static void aura_output_device_scale_factor(void *data,
226 					    struct zaura_output *aura_output,
227 					    uint32_t device_scale_factor)
228 {
229 	(void)aura_output;
230 	struct output *output = (struct output *)data;
231 	output->device_scale_factor = device_scale_factor;
232 }
233 
234 static const struct zaura_output_listener aura_output_listener = {
235     .scale = aura_output_scale,
236     .connection = aura_output_connection,
237     .device_scale_factor = aura_output_device_scale_factor};
238 
xdg_wm_base_ping(void * data,struct xdg_wm_base * xdg_wm_base,uint32_t serial)239 static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base,
240 			     uint32_t serial)
241 {
242 	(void)data;
243 	xdg_wm_base_pong(xdg_wm_base, serial);
244 }
245 
246 static const struct xdg_wm_base_listener xdg_wm_base_listener = {
247 	.ping = xdg_wm_base_ping,
248 };
249 
250 
wl_keyboard_keymap(void * data,struct wl_keyboard * wl_keyboard,uint32_t format,int32_t fd,uint32_t size)251 static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
252 			       uint32_t format, int32_t fd, uint32_t size)
253 {
254 	struct dwl_context *context = (struct dwl_context*)data;
255 	(void)wl_keyboard;
256 	(void)fd;
257 	(void)size;
258 	if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
259 		context->error_callback("wl_keyboard: invalid keymap format");
260 	}
261 }
262 
dwl_context_push_event(struct dwl_context * self,struct dwl_event * event)263 static void dwl_context_push_event(struct dwl_context *self,
264 				   struct dwl_event *event)
265 {
266 	if (!self)
267 		return;
268 
269 	memcpy(self->event_cbuf + self->event_write_pos, event,
270 	       sizeof(struct dwl_event));
271 
272 	if (++self->event_write_pos == EVENT_BUF_SIZE)
273 		self->event_write_pos = 0;
274 }
275 
wl_keyboard_enter(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,struct wl_surface * surface,struct wl_array * keys)276 static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard,
277 			      uint32_t serial, struct wl_surface *surface,
278 			      struct wl_array *keys)
279 {
280 	(void)wl_keyboard;
281 	(void)serial;
282 	(void)surface;
283 	struct dwl_context *context = (struct dwl_context*)data;
284 	struct input *input = &context->input;
285 	uint32_t *key;
286 	struct dwl_event event = {0};
287 	input->keyboard_input_surface = surface;
288 	wl_array_for_each(key, keys) {
289 		event.surface_descriptor = input->keyboard_input_surface;
290 		event.event_type = DWL_EVENT_TYPE_KEYBOARD_KEY;
291 		event.params[0] = (int32_t)*key;
292 		event.params[1] = DWL_KEYBOARD_KEY_STATE_PRESSED;
293 		dwl_context_push_event(context, &event);
294 	}
295 }
296 
wl_keyboard_key(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,uint32_t time,uint32_t key,uint32_t state)297 static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
298 			    uint32_t serial, uint32_t time, uint32_t key,
299 			    uint32_t state)
300 {
301 	struct dwl_context *context = (struct dwl_context*)data;
302 	struct input *input = &context->input;
303 	(void)wl_keyboard;
304 	(void)serial;
305 	(void)time;
306 	struct dwl_event event = {0};
307 	event.surface_descriptor = input->keyboard_input_surface;
308 	event.event_type = DWL_EVENT_TYPE_KEYBOARD_KEY;
309 	event.params[0] = (int32_t)key;
310 	event.params[1] = state;
311 	dwl_context_push_event(context, &event);
312 }
313 
wl_keyboard_leave(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,struct wl_surface * surface)314 static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard,
315 			      uint32_t serial, struct wl_surface *surface)
316 {
317 	struct dwl_context *context = (struct dwl_context*)data;
318 	struct input *input = &context->input;
319 	struct dwl_event event = {0};
320 	(void)wl_keyboard;
321 	(void)serial;
322 	(void)surface;
323 
324 	event.surface_descriptor = input->keyboard_input_surface;
325 	event.event_type = DWL_EVENT_TYPE_KEYBOARD_LEAVE;
326 	dwl_context_push_event(context, &event);
327 
328 	input->keyboard_input_surface = NULL;
329 }
330 
wl_keyboard_modifiers(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)331 static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,
332 				  uint32_t serial, uint32_t mods_depressed,
333 				  uint32_t mods_latched, uint32_t mods_locked,
334 				  uint32_t group)
335 {
336 	(void)data;
337 	(void)wl_keyboard;
338 	(void)serial;
339 	(void)mods_depressed;
340 	(void)mods_latched;
341 	(void)mods_locked;
342 	(void)group;
343 }
344 
wl_keyboard_repeat_info(void * data,struct wl_keyboard * wl_keyboard,int32_t rate,int32_t delay)345 static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
346 				    int32_t rate, int32_t delay)
347 {
348 	(void)data;
349 	(void)wl_keyboard;
350 	(void)rate;
351 	(void)delay;
352 }
353 
354 static const struct wl_keyboard_listener wl_keyboard_listener = {
355 	.keymap = wl_keyboard_keymap,
356 	.enter = wl_keyboard_enter,
357 	.leave = wl_keyboard_leave,
358 	.key = wl_keyboard_key,
359 	.modifiers = wl_keyboard_modifiers,
360 	.repeat_info = wl_keyboard_repeat_info,
361 };
362 
pointer_enter_handler(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surface,wl_fixed_t x,wl_fixed_t y)363 static void pointer_enter_handler(void *data, struct wl_pointer *wl_pointer,
364 				  uint32_t serial, struct wl_surface *surface,
365 				  wl_fixed_t x, wl_fixed_t y)
366 {
367 	struct dwl_context *context = (struct dwl_context*)data;
368 	struct input *input = &context->input;
369 	(void)wl_pointer;
370 	(void)serial;
371 
372 	input->pointer_input_surface = surface;
373 	input->pointer_x = wl_fixed_to_int(x);
374 	input->pointer_y = wl_fixed_to_int(y);
375 }
376 
pointer_leave_handler(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surface)377 static void pointer_leave_handler(void *data, struct wl_pointer *wl_pointer,
378 				  uint32_t serial, struct wl_surface *surface)
379 {
380 	struct dwl_context *context = (struct dwl_context*)data;
381 	struct input *input = &context->input;
382 	(void)wl_pointer;
383 	(void)serial;
384 	(void)surface;
385 
386 	input->pointer_input_surface = NULL;
387 }
388 
pointer_motion_handler(void * data,struct wl_pointer * wl_pointer,uint32_t time,wl_fixed_t x,wl_fixed_t y)389 static void pointer_motion_handler(void *data, struct wl_pointer *wl_pointer,
390 				   uint32_t time, wl_fixed_t x, wl_fixed_t y)
391 {
392 	struct dwl_context *context = (struct dwl_context*)data;
393 	struct input *input = &context->input;
394 	struct dwl_event event = {0};
395 	(void)wl_pointer;
396 	(void)time;
397 
398 	input->pointer_x = wl_fixed_to_int(x);
399 	input->pointer_y = wl_fixed_to_int(y);
400 	if (input->pointer_lbutton_state) {
401 		event.surface_descriptor = input->pointer_input_surface;
402 		event.event_type = DWL_EVENT_TYPE_TOUCH_MOTION;
403 		event.params[0] = input->pointer_x;
404 		event.params[1] = input->pointer_y;
405 		dwl_context_push_event(context, &event);
406 	}
407 }
408 
pointer_button_handler(void * data,struct wl_pointer * wl_pointer,uint32_t serial,uint32_t time,uint32_t button,uint32_t state)409 static void pointer_button_handler(void *data, struct wl_pointer *wl_pointer,
410 				   uint32_t serial, uint32_t time, uint32_t button,
411 				   uint32_t state)
412 {
413 	struct dwl_context *context = (struct dwl_context*)data;
414 	struct input *input = &context->input;
415 	(void)wl_pointer;
416 	(void)time;
417 	(void)serial;
418 
419 	// we track only the left mouse button since we emulate a single touch device
420 	if (button == BTN_LEFT) {
421 		input->pointer_lbutton_state = state != 0;
422 		struct dwl_event event = {0};
423 		event.surface_descriptor = input->pointer_input_surface;
424 		event.event_type = (state != 0)?
425 			DWL_EVENT_TYPE_TOUCH_DOWN:DWL_EVENT_TYPE_TOUCH_UP;
426 		event.params[0] = input->pointer_x;
427 		event.params[1] = input->pointer_y;
428 		dwl_context_push_event(context, &event);
429 	}
430 }
431 
wl_pointer_frame(void * data,struct wl_pointer * wl_pointer)432 static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
433 {
434 	(void)data;
435 	(void)wl_pointer;
436 }
437 
pointer_axis_handler(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis,wl_fixed_t value)438 static void pointer_axis_handler(void *data, struct wl_pointer *wl_pointer,
439 				 uint32_t time, uint32_t axis, wl_fixed_t value)
440 {
441 	(void)data;
442 	(void)wl_pointer;
443 	(void)time;
444 	(void)axis;
445 	(void)value;
446 }
447 
wl_pointer_axis_source(void * data,struct wl_pointer * wl_pointer,uint32_t axis_source)448 static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer,
449 				   uint32_t axis_source)
450 {
451 	(void)data;
452 	(void)wl_pointer;
453 	(void)axis_source;
454 }
455 
wl_pointer_axis_stop(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis)456 static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
457 					uint32_t time, uint32_t axis)
458 {
459 	(void)data;
460 	(void)wl_pointer;
461 	(void)time;
462 	(void)axis;
463 }
464 
wl_pointer_axis_discrete(void * data,struct wl_pointer * wl_pointer,uint32_t axis,int32_t discrete)465 static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
466 				     uint32_t axis, int32_t discrete)
467 {
468 	(void)data;
469 	(void)wl_pointer;
470 	(void)axis;
471 	(void)discrete;
472 }
473 
474 const struct wl_pointer_listener wl_pointer_listener = {
475 	.enter = pointer_enter_handler,
476 	.leave = pointer_leave_handler,
477 	.motion = pointer_motion_handler,
478 	.button = pointer_button_handler,
479 	.axis = pointer_axis_handler,
480 	.frame = wl_pointer_frame,
481 	.axis_source = wl_pointer_axis_source,
482 	.axis_stop = wl_pointer_axis_stop,
483 	.axis_discrete = wl_pointer_axis_discrete,
484 };
485 
wl_seat_capabilities(void * data,struct wl_seat * wl_seat,uint32_t capabilities)486 static void wl_seat_capabilities(void *data, struct wl_seat *wl_seat,
487 				 uint32_t capabilities)
488 {
489 	struct dwl_context *context = (struct dwl_context*)data;
490 	struct input *input = &context->input;
491 	bool have_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD;
492 	bool have_pointer = capabilities & WL_SEAT_CAPABILITY_POINTER;
493 
494 	if (have_keyboard && input->wl_keyboard == NULL) {
495 		input->wl_keyboard = wl_seat_get_keyboard(wl_seat);
496 		wl_keyboard_add_listener(input->wl_keyboard, &wl_keyboard_listener, context);
497 	} else if (!have_keyboard && input->wl_keyboard != NULL) {
498 		wl_keyboard_release(input->wl_keyboard);
499 		input->wl_keyboard = NULL;
500 	}
501 
502 	if (have_pointer && input->wl_pointer == NULL) {
503 		input->wl_pointer = wl_seat_get_pointer(wl_seat);
504 		wl_pointer_add_listener(input->wl_pointer, &wl_pointer_listener, context);
505 	} else if (!have_pointer && input->wl_pointer != NULL) {
506 		wl_pointer_release(input->wl_pointer);
507 		input->wl_pointer = NULL;
508 	}
509 }
510 
wl_seat_name(void * data,struct wl_seat * wl_seat,const char * name)511 static void wl_seat_name(void *data, struct wl_seat *wl_seat, const char *name)
512 {
513 	(void)data;
514 	(void)wl_seat;
515 	(void)name;
516 }
517 
518 static const struct wl_seat_listener wl_seat_listener = {
519 	.capabilities = wl_seat_capabilities,
520 	.name = wl_seat_name,
521 };
522 
dwl_context_output_add(struct dwl_context * context,struct wl_output * wl_output,uint32_t id)523 static void dwl_context_output_add(struct dwl_context *context,
524 				   struct wl_output *wl_output, uint32_t id)
525 {
526 	size_t i;
527 	struct output *output;
528 	outputs_for_each(context, i, output)
529 	{
530 		if (output->output == NULL) {
531 			context->output_added = true;
532 			output->id = id;
533 			output->output = wl_output;
534 			output->context = context;
535 			output->current_scale = 1000;
536 			output->device_scale_factor = 1000;
537 			// This is a fun little hack from reveman. The idea is
538 			// that the first display will be internal and never get
539 			// removed.
540 			output->internal = i == 0;
541 			wl_output_add_listener(output->output, &output_listener,
542 					       output);
543 			return;
544 		}
545 	}
546 }
547 
dwl_context_output_remove_destroy(struct dwl_context * context,uint32_t id)548 static void dwl_context_output_remove_destroy(struct dwl_context *context,
549 					      uint32_t id)
550 {
551 	size_t i;
552 	struct output *output;
553 	outputs_for_each(context, i, output)
554 	{
555 		if (output->id == id) {
556 			if (output->aura_output)
557 				zaura_output_destroy(output->aura_output);
558 			wl_output_destroy(output->output);
559 			memset(output, 0, sizeof(struct output));
560 			return;
561 		}
562 	}
563 }
564 
dwl_context_output_get_aura(struct dwl_context * context)565 static void dwl_context_output_get_aura(struct dwl_context *context)
566 {
567 	if (!context->ifaces.aura)
568 		return;
569 
570 	size_t i;
571 	struct output *output;
572 	outputs_for_each(context, i, output)
573 	{
574 		if (output->output != NULL && output->aura_output == NULL) {
575 			output->aura_output = zaura_shell_get_aura_output(
576 			    context->ifaces.aura, output->output);
577 			zaura_output_add_listener(
578 			    output->aura_output, &aura_output_listener, output);
579 		}
580 	}
581 }
582 
registry_global(void * data,struct wl_registry * registry,uint32_t id,const char * interface,uint32_t version)583 static void registry_global(void *data, struct wl_registry *registry,
584 			    uint32_t id, const char *interface,
585 			    uint32_t version)
586 {
587 	(void)version;
588 	struct interfaces *ifaces = (struct interfaces *)data;
589 	if (strcmp(interface, wl_compositor_interface.name) == 0) {
590 		ifaces->compositor = (struct wl_compositor *)wl_registry_bind(
591 		    registry, id, &wl_compositor_interface, 3);
592 	} else if (strcmp(interface, wl_subcompositor_interface.name) == 0) {
593 		ifaces->subcompositor =
594 		    (struct wl_subcompositor *)wl_registry_bind(
595 			registry, id, &wl_subcompositor_interface, 1);
596 	} else if (strcmp(interface, wl_shm_interface.name) == 0) {
597 		ifaces->shm = (struct wl_shm *)wl_registry_bind(
598 		    registry, id, &wl_shm_interface, 1);
599 	} else if (strcmp(interface, wl_seat_interface.name) == 0) {
600 		ifaces->seat = (struct wl_seat *)wl_registry_bind(
601 		    registry, id, &wl_seat_interface, 5);
602 		wl_seat_add_listener(ifaces->seat, &wl_seat_listener, ifaces->context);
603 	} else if (strcmp(interface, wl_output_interface.name) == 0) {
604 		struct wl_output *output = (struct wl_output *)wl_registry_bind(
605 		    registry, id, &wl_output_interface, 2);
606 		dwl_context_output_add(ifaces->context, output, id);
607 	} else if (strcmp(interface, "zaura_shell") == 0 && version >= 6) {
608 		ifaces->aura = (struct zaura_shell *)wl_registry_bind(
609 		    registry, id, &zaura_shell_interface, 6);
610 	} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
611 		ifaces->linux_dmabuf =
612 		    (struct zwp_linux_dmabuf_v1 *)wl_registry_bind(
613 			registry, id, &zwp_linux_dmabuf_v1_interface, 1);
614 	} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
615 		ifaces->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(
616 		    registry, id, &xdg_wm_base_interface, 1);
617 		xdg_wm_base_add_listener(ifaces->xdg_wm_base, &xdg_wm_base_listener,
618 			NULL);
619 	} else if (strcmp(interface, "wp_viewporter") == 0) {
620 		ifaces->viewporter = (struct wp_viewporter *)wl_registry_bind(
621 		    registry, id, &wp_viewporter_interface, 1);
622 	} else if (strcmp(interface, "wp_virtio_gpu_metadata_v1") == 0) {
623 		ifaces->virtio_gpu_metadata =
624 			(struct wp_virtio_gpu_metadata_v1 *)wl_registry_bind(
625 			registry, id, &wp_virtio_gpu_metadata_v1_interface, 1);
626 	}
627 }
628 
global_remove(void * data,struct wl_registry * registry,uint32_t id)629 static void global_remove(void *data, struct wl_registry *registry, uint32_t id)
630 {
631 	(void)registry;
632 
633 	struct interfaces *ifaces = (struct interfaces *)data;
634 	// If the ID matches any output, this will remove it. Otherwise, this is
635 	// a no-op.
636 	dwl_context_output_remove_destroy(ifaces->context, id);
637 
638 	if (ifaces->aura &&
639 	    wl_proxy_get_id((struct wl_proxy *)ifaces->aura) == id) {
640 		zaura_shell_destroy(ifaces->aura);
641 		ifaces->aura = NULL;
642 	}
643 
644 	// TODO(zachr): deal with the removal of some of the required
645 	// interfaces.
646 }
647 
648 static const struct wl_registry_listener registry_listener = {
649     .global = registry_global, .global_remove = global_remove};
650 
toplevel_configure(void * data,struct xdg_toplevel * xdg_toplevel,int32_t width,int32_t height,struct wl_array * states)651 static void toplevel_configure(void *data,
652 			       struct xdg_toplevel *xdg_toplevel,
653 			       int32_t width, int32_t height,
654 			       struct wl_array *states)
655 {
656 	(void)data;
657 	(void)xdg_toplevel;
658 	(void)width;
659 	(void)height;
660 	(void)states;
661 }
662 
toplevel_close(void * data,struct xdg_toplevel * xdg_toplevel)663 static void toplevel_close(void *data,
664 			   struct xdg_toplevel *xdg_toplevel)
665 {
666 	(void)xdg_toplevel;
667 	struct dwl_surface *surface = (struct dwl_surface *)data;
668 	surface->close_requested = true;
669 }
670 
671 static const struct xdg_toplevel_listener toplevel_listener = {
672     .configure = toplevel_configure, .close = toplevel_close};
673 
xdg_surface_configure_handler(void * data,struct xdg_surface * xdg_surface,uint32_t serial)674 static void xdg_surface_configure_handler(void *data,
675 					  struct xdg_surface *xdg_surface,
676 					  uint32_t serial)
677 {
678 	(void)data;
679 	xdg_surface_ack_configure(xdg_surface, serial);
680 }
681 
682 static const struct xdg_surface_listener xdg_surface_listener = {
683 	.configure = xdg_surface_configure_handler
684 };
685 
surface_enter(void * data,struct wl_surface * wl_surface,struct wl_output * wl_output)686 static void surface_enter(void *data, struct wl_surface *wl_surface,
687 			  struct wl_output *wl_output)
688 {
689 	struct dwl_surface *surface = (struct dwl_surface *)data;
690 
691 	struct output *output =
692 	    (struct output *)wl_output_get_user_data(wl_output);
693 
694 	surface->scale = (output->device_scale_factor / 1000.0) *
695 			 (output->current_scale / 1000.0);
696 
697 	if (surface->viewport) {
698 		wp_viewport_set_destination(
699 		    surface->viewport, ceil(surface->width / surface->scale),
700 		    ceil(surface->height / surface->scale));
701 	} else {
702 		wl_surface_set_buffer_scale(wl_surface, surface->scale);
703 	}
704 
705 	wl_surface_commit(wl_surface);
706 }
707 
surface_leave(void * data,struct wl_surface * wl_surface,struct wl_output * output)708 static void surface_leave(void *data, struct wl_surface *wl_surface,
709 			  struct wl_output *output)
710 {
711 	(void)data;
712 	(void)wl_surface;
713 	(void)output;
714 }
715 
716 static const struct wl_surface_listener surface_listener = {
717     .enter = surface_enter, .leave = surface_leave};
718 
error_callback_stub(const char * message)719 static void error_callback_stub(const char *message) {
720 	(void)message;
721 }
722 
dwl_context_new(dwl_error_callback_type error_callback)723 struct dwl_context *dwl_context_new(dwl_error_callback_type error_callback)
724 {
725 	struct dwl_context *ctx = calloc(1, sizeof(struct dwl_context));
726 	if (!ctx)
727 		return NULL;
728 	ctx->ifaces.context = ctx;
729 	ctx->error_callback = error_callback ? error_callback : error_callback_stub;
730 	return ctx;
731 }
732 
dwl_context_destroy(struct dwl_context ** self)733 void dwl_context_destroy(struct dwl_context **self)
734 {
735 	if ((*self)->display)
736 		wl_display_disconnect((*self)->display);
737 	free(*self);
738 	*self = NULL;
739 }
740 
dwl_context_setup(struct dwl_context * self,const char * socket_path)741 bool dwl_context_setup(struct dwl_context *self, const char *socket_path)
742 {
743 	struct wl_display *display = wl_display_connect(socket_path);
744 	if (!display) {
745 		self->error_callback("failed to connect to display");
746 		return false;
747 	}
748 	self->display = display;
749 	wl_display_set_user_data(display, self);
750 
751 	struct wl_registry *registry = wl_display_get_registry(display);
752 	if (!registry) {
753 		self->error_callback("failed to get registry");
754 		goto fail;
755 	}
756 
757 	struct interfaces *ifaces = &self->ifaces;
758 	wl_registry_add_listener(registry, &registry_listener, ifaces);
759 	wl_display_roundtrip(display);
760 	dwl_context_output_get_aura(self);
761 
762 	if (!ifaces->shm) {
763 		self->error_callback("missing interface shm");
764 		goto fail;
765 	}
766 	if (!ifaces->compositor) {
767 		self->error_callback("missing interface compositor");
768 		goto fail;
769 	}
770 	if (!ifaces->subcompositor) {
771 		self->error_callback("missing interface subcompositor");
772 		goto fail;
773 	}
774 	if (!ifaces->seat) {
775 		self->error_callback("missing interface seat");
776 		goto fail;
777 	}
778 	if (!ifaces->linux_dmabuf) {
779 		self->error_callback("missing interface linux_dmabuf");
780 		goto fail;
781 	}
782 	if (!ifaces->xdg_wm_base) {
783 		self->error_callback("missing interface xdg_wm_base");
784 		goto fail;
785 	}
786 
787 	return true;
788 
789 fail:
790 	wl_display_disconnect(display);
791 	self->display = NULL;
792 	return false;
793 }
794 
dwl_context_fd(struct dwl_context * self)795 int dwl_context_fd(struct dwl_context *self)
796 {
797 	return wl_display_get_fd(self->display);
798 }
799 
dwl_context_dispatch(struct dwl_context * self)800 void dwl_context_dispatch(struct dwl_context *self)
801 {
802 	wl_display_dispatch(self->display);
803 	if (self->output_added) {
804 		self->output_added = false;
805 		dwl_context_output_get_aura(self);
806 		wl_display_roundtrip(self->display);
807 	}
808 }
809 
linux_buffer_created(void * data,struct zwp_linux_buffer_params_v1 * zwp_linux_buffer_params_v1,struct wl_buffer * buffer)810 static void linux_buffer_created(
811     void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1,
812     struct wl_buffer *buffer)
813 {
814 	(void)zwp_linux_buffer_params_v1;
815 	struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
816 	dmabuf->buffer = buffer;
817 }
818 
linux_buffer_failed(void * data,struct zwp_linux_buffer_params_v1 * zwp_linux_buffer_params_v1)819 static void linux_buffer_failed(
820     void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1)
821 {
822 	(void)data;
823 	(void)zwp_linux_buffer_params_v1;
824 }
825 
826 static const struct zwp_linux_buffer_params_v1_listener linux_buffer_listener =
827     {.created = linux_buffer_created, .failed = linux_buffer_failed};
828 
dmabuf_buffer_release(void * data,struct wl_buffer * buffer)829 static void dmabuf_buffer_release(void *data, struct wl_buffer *buffer)
830 {
831 	struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
832 	(void)buffer;
833 
834 	dmabuf->in_use = false;
835 }
836 
837 static const struct wl_buffer_listener dmabuf_buffer_listener = {
838     .release = dmabuf_buffer_release};
839 
dwl_context_add_dmabuf(struct dwl_context * self,struct dwl_dmabuf * dmabuf)840 static bool dwl_context_add_dmabuf(struct dwl_context *self,
841 				   struct dwl_dmabuf *dmabuf)
842 {
843 	size_t i;
844 	for (i = 0; i < MAX_BUFFER_COUNT; i++) {
845 		if (!self->dmabufs[i]) {
846 			self->dmabufs[i] = dmabuf;
847 			return true;
848 		}
849 	}
850 
851 	return false;
852 }
853 
dwl_context_remove_dmabuf(struct dwl_context * self,uint32_t import_id)854 static void dwl_context_remove_dmabuf(struct dwl_context *self,
855 				      uint32_t import_id)
856 {
857 	size_t i;
858 	for (i = 0; i < MAX_BUFFER_COUNT; i++) {
859 		if (self->dmabufs[i] &&
860 		    self->dmabufs[i]->import_id == import_id) {
861 			self->dmabufs[i] = NULL;
862 		}
863 	}
864 }
865 
dwl_context_get_dmabuf(struct dwl_context * self,uint32_t import_id)866 static struct dwl_dmabuf *dwl_context_get_dmabuf(struct dwl_context *self,
867 					         uint32_t import_id)
868 {
869 	size_t i;
870 	for (i = 0; i < MAX_BUFFER_COUNT; i++) {
871 		if (self->dmabufs[i] &&
872 		    self->dmabufs[i]->import_id == import_id) {
873 			return self->dmabufs[i];
874 		}
875 	}
876 
877 	return NULL;
878 }
879 
dwl_context_dmabuf_new(struct dwl_context * self,uint32_t import_id,int fd,uint32_t offset,uint32_t stride,uint64_t modifier,uint32_t width,uint32_t height,uint32_t fourcc)880 struct dwl_dmabuf *dwl_context_dmabuf_new(struct dwl_context *self,
881 					  uint32_t import_id,
882 					  int fd, uint32_t offset,
883 					  uint32_t stride, uint64_t modifier,
884 					  uint32_t width, uint32_t height,
885 					  uint32_t fourcc)
886 {
887 	struct dwl_dmabuf *dmabuf = calloc(1, sizeof(struct dwl_dmabuf));
888 	if (!dmabuf) {
889 		self->error_callback("failed to allocate dwl_dmabuf");
890 		return NULL;
891 	}
892 	dmabuf->width = width;
893 	dmabuf->height = height;
894 
895 	struct zwp_linux_buffer_params_v1 *params =
896 	    zwp_linux_dmabuf_v1_create_params(self->ifaces.linux_dmabuf);
897 	if (!params) {
898 		self->error_callback("failed to allocate zwp_linux_buffer_params_v1");
899 		free(dmabuf);
900 		return NULL;
901 	}
902 
903 	zwp_linux_buffer_params_v1_add_listener(params, &linux_buffer_listener,
904 						dmabuf);
905 	zwp_linux_buffer_params_v1_add(params, fd, 0 /* plane_idx */, offset,
906 				       stride, modifier >> 32,
907 				       (uint32_t)modifier);
908 	zwp_linux_buffer_params_v1_create(params, width, height, fourcc, 0);
909 	wl_display_roundtrip(self->display);
910 	zwp_linux_buffer_params_v1_destroy(params);
911 
912 	if (!dmabuf->buffer) {
913 		self->error_callback("failed to get wl_buffer for dmabuf");
914 		free(dmabuf);
915 		return NULL;
916 	}
917 
918 	wl_buffer_add_listener(dmabuf->buffer, &dmabuf_buffer_listener, dmabuf);
919 
920 	dmabuf->import_id = import_id;
921 	dmabuf->context = self;
922 	if (!dwl_context_add_dmabuf(self, dmabuf)) {
923 		self->error_callback("failed to add dmabuf to context");
924 		free(dmabuf);
925 		return NULL;
926 	}
927 
928 	return dmabuf;
929 }
930 
dwl_dmabuf_destroy(struct dwl_dmabuf ** self)931 void dwl_dmabuf_destroy(struct dwl_dmabuf **self)
932 {
933 	dwl_context_remove_dmabuf((*self)->context, (*self)->import_id);
934 	wl_buffer_destroy((*self)->buffer);
935 	free(*self);
936 	*self = NULL;
937 }
938 
surface_buffer_release(void * data,struct wl_buffer * buffer)939 static void surface_buffer_release(void *data, struct wl_buffer *buffer)
940 {
941 	struct dwl_surface *surface = (struct dwl_surface *)data;
942 	(void)buffer;
943 
944 	size_t i;
945 	for (i = 0; i < surface->buffer_count; i++) {
946 		if (buffer == surface->buffers[i]) {
947 			surface->buffer_use_bit_mask &= ~(1 << i);
948 			break;
949 		}
950 	}
951 }
952 
953 static const struct wl_buffer_listener surface_buffer_listener = {
954     .release = surface_buffer_release};
955 
dwl_context_get_surface(struct dwl_context * self,uint32_t surface_id)956 static struct dwl_surface *dwl_context_get_surface(struct dwl_context *self,
957 					           uint32_t surface_id)
958 {
959 	size_t i;
960 	for (i = 0; i < MAX_BUFFER_COUNT; i++) {
961 		if (self->surfaces[i] &&
962 		    self->surfaces[i]->surface_id == surface_id) {
963 			return self->surfaces[i];
964 		}
965 	}
966 
967 	return NULL;
968 }
969 
dwl_context_add_surface(struct dwl_context * self,struct dwl_surface * surface)970 static bool dwl_context_add_surface(struct dwl_context *self,
971 				    struct dwl_surface *surface)
972 {
973 	size_t i;
974 	for (i = 0; i < MAX_BUFFER_COUNT; i++) {
975 		if (!self->surfaces[i]) {
976 			self->surfaces[i] = surface;
977 			return true;
978 		}
979 	}
980 
981 	return false;
982 }
983 
dwl_context_remove_surface(struct dwl_context * self,uint32_t surface_id)984 static void dwl_context_remove_surface(struct dwl_context *self,
985 				       uint32_t surface_id)
986 {
987 	size_t i;
988 	for (i = 0; i < MAX_BUFFER_COUNT; i++) {
989 		if (self->surfaces[i] &&
990 		    self->surfaces[i]->surface_id == surface_id) {
991 			self->surfaces[i] = NULL;
992 		}
993 	}
994 }
995 
dwl_context_surface_new(struct dwl_context * self,uint32_t parent_id,uint32_t surface_id,int shm_fd,size_t shm_size,size_t buffer_size,uint32_t width,uint32_t height,uint32_t stride,uint32_t flags)996 struct dwl_surface *dwl_context_surface_new(struct dwl_context *self,
997 					    uint32_t parent_id,
998 					    uint32_t  surface_id,
999 					    int shm_fd, size_t shm_size,
1000 					    size_t buffer_size, uint32_t width,
1001 					    uint32_t height, uint32_t stride,
1002 					    uint32_t flags)
1003 {
1004 	if (buffer_size == 0)
1005 		return NULL;
1006 
1007 	size_t buffer_count = shm_size / buffer_size;
1008 	if (buffer_count == 0)
1009 		return NULL;
1010 	if (buffer_count > MAX_BUFFER_COUNT)
1011 		return NULL;
1012 
1013 	struct dwl_surface *disp_surface =
1014 	    calloc(1, sizeof(struct dwl_surface) +
1015 			  sizeof(struct wl_buffer *) * buffer_count);
1016 	if (!disp_surface)
1017 		return NULL;
1018 
1019 	disp_surface->context = self;
1020 	disp_surface->width = width;
1021 	disp_surface->height = height;
1022 	disp_surface->scale = DEFAULT_SCALE;
1023 	disp_surface->buffer_count = buffer_count;
1024 
1025 	struct wl_shm_pool *shm_pool =
1026 	    wl_shm_create_pool(self->ifaces.shm, shm_fd, shm_size);
1027 	if (!shm_pool) {
1028 		self->error_callback("failed to make shm pool");
1029 		goto fail;
1030 	}
1031 
1032 	size_t i;
1033 	uint32_t format = (flags & DWL_SURFACE_FLAG_HAS_ALPHA)?
1034 		WL_SHM_FORMAT_ARGB8888:WL_SHM_FORMAT_XRGB8888;
1035 
1036 	for (i = 0; i < buffer_count; i++) {
1037 		struct wl_buffer *buffer = wl_shm_pool_create_buffer(
1038 		    shm_pool, buffer_size * i, width, height, stride, format);
1039 		if (!buffer) {
1040 			self->error_callback("failed to create buffer");
1041 			goto fail;
1042 		}
1043 		disp_surface->buffers[i] = buffer;
1044 	}
1045 
1046 	for (i = 0; i < buffer_count; i++)
1047 		wl_buffer_add_listener(disp_surface->buffers[i],
1048 				       &surface_buffer_listener, disp_surface);
1049 
1050 	disp_surface->wl_surface =
1051 	    wl_compositor_create_surface(self->ifaces.compositor);
1052 	if (!disp_surface->wl_surface) {
1053 		self->error_callback("failed to make surface");
1054 		goto fail;
1055 	}
1056 
1057 	wl_surface_add_listener(disp_surface->wl_surface, &surface_listener,
1058 				disp_surface);
1059 
1060 	struct wl_region *region = wl_compositor_create_region(self->ifaces.compositor);
1061 	if (!region) {
1062 		self->error_callback("failed to make region");
1063 		goto fail;
1064 	}
1065 
1066 	bool receive_input = (flags & DWL_SURFACE_FLAG_RECEIVE_INPUT);
1067 	if (receive_input) {
1068 		wl_region_add(region, 0, 0, width, height);
1069 	} else {
1070 		// We have to add an empty region because NULL doesn't work
1071 		wl_region_add(region, 0, 0, 0, 0);
1072 	}
1073 	wl_surface_set_input_region(disp_surface->wl_surface, region);
1074 	wl_surface_set_opaque_region(disp_surface->wl_surface, region);
1075 	wl_region_destroy(region);
1076 
1077 	if (!parent_id) {
1078 		disp_surface->xdg_surface = xdg_wm_base_get_xdg_surface(
1079 		    self->ifaces.xdg_wm_base, disp_surface->wl_surface);
1080 		if (!disp_surface->xdg_surface) {
1081 			self->error_callback("failed to make xdg shell surface");
1082 			goto fail;
1083 		}
1084 
1085 		disp_surface->xdg_toplevel =
1086 		    xdg_surface_get_toplevel(disp_surface->xdg_surface);
1087 		if (!disp_surface->xdg_toplevel) {
1088 			self->error_callback("failed to make toplevel xdg shell surface");
1089 			goto fail;
1090 		}
1091 		xdg_toplevel_set_title(disp_surface->xdg_toplevel, "crosvm");
1092 		xdg_toplevel_add_listener(disp_surface->xdg_toplevel,
1093 					      &toplevel_listener, disp_surface);
1094 
1095 		xdg_surface_add_listener(disp_surface->xdg_surface,
1096 					     &xdg_surface_listener,
1097 					     NULL);
1098 		if (self->ifaces.aura) {
1099 			disp_surface->aura = zaura_shell_get_aura_surface(
1100 			    self->ifaces.aura, disp_surface->wl_surface);
1101 			if (!disp_surface->aura) {
1102 				self->error_callback("failed to make aura surface");
1103 				goto fail;
1104 			}
1105 			zaura_surface_set_frame(
1106 			    disp_surface->aura,
1107 			    ZAURA_SURFACE_FRAME_TYPE_NORMAL);
1108 		}
1109 
1110 		// signal that the surface is ready to be configured
1111 		wl_surface_commit(disp_surface->wl_surface);
1112 
1113 		// wait for the surface to be configured
1114 		wl_display_roundtrip(self->display);
1115 	} else {
1116 		struct dwl_surface *parent_surface =
1117 			dwl_context_get_surface(self, parent_id);
1118 
1119 		if (!parent_surface) {
1120 			self->error_callback("failed to find parent_surface");
1121 			goto fail;
1122 		}
1123 
1124 		disp_surface->subsurface = wl_subcompositor_get_subsurface(
1125 		    self->ifaces.subcompositor, disp_surface->wl_surface,
1126 		    parent_surface->wl_surface);
1127 		if (!disp_surface->subsurface) {
1128 			self->error_callback("failed to make subsurface");
1129 			goto fail;
1130 		}
1131 		wl_subsurface_set_desync(disp_surface->subsurface);
1132 	}
1133 
1134 	if (self->ifaces.viewporter) {
1135 		disp_surface->viewport = wp_viewporter_get_viewport(
1136 		    self->ifaces.viewporter, disp_surface->wl_surface);
1137 		if (!disp_surface->viewport) {
1138 			self->error_callback("failed to make surface viewport");
1139 			goto fail;
1140 		}
1141 	}
1142 
1143 	if (self->ifaces.virtio_gpu_metadata) {
1144 		disp_surface->virtio_gpu_surface_metadata =
1145 			wp_virtio_gpu_metadata_v1_get_surface_metadata(
1146 				self->ifaces.virtio_gpu_metadata, disp_surface->wl_surface);
1147 		if (!disp_surface->virtio_gpu_surface_metadata) {
1148 			self->error_callback("failed to make surface virtio surface metadata");
1149 			goto fail;
1150 		}
1151 	}
1152 
1153 	wl_surface_attach(disp_surface->wl_surface, disp_surface->buffers[0], 0,
1154 			  0);
1155 	wl_surface_damage(disp_surface->wl_surface, 0, 0, width, height);
1156 	wl_shm_pool_destroy(shm_pool);
1157 
1158 	// Needed to get outputs before iterating them.
1159 	wl_display_roundtrip(self->display);
1160 
1161 	// Assuming that this surface will enter the internal output initially,
1162 	// trigger a surface enter for that output before doing the first
1163 	// surface commit. THis is to avoid unpleasant artifacts when the
1164 	// surface first appears.
1165 	struct output *output;
1166 	outputs_for_each(self, i, output)
1167 	{
1168 		if (output->internal) {
1169 			surface_enter(disp_surface, disp_surface->wl_surface,
1170 				      output->output);
1171 		}
1172 	}
1173 
1174 	wl_surface_commit(disp_surface->wl_surface);
1175 	wl_display_flush(self->display);
1176 
1177 	disp_surface->surface_id = surface_id;
1178 	if (!dwl_context_add_surface(self, disp_surface)) {
1179 		self->error_callback("failed to add surface to context");
1180 		goto fail;
1181 	}
1182 
1183 	return disp_surface;
1184 fail:
1185 	if (disp_surface->virtio_gpu_surface_metadata)
1186 		wp_virtio_gpu_surface_metadata_v1_destroy(
1187 			disp_surface->virtio_gpu_surface_metadata);
1188 	if (disp_surface->viewport)
1189 		wp_viewport_destroy(disp_surface->viewport);
1190 	if (disp_surface->subsurface)
1191 		wl_subsurface_destroy(disp_surface->subsurface);
1192 	if (disp_surface->xdg_toplevel)
1193 		xdg_toplevel_destroy(disp_surface->xdg_toplevel);
1194 	if (disp_surface->xdg_surface)
1195 		xdg_surface_destroy(disp_surface->xdg_surface);
1196 	if (disp_surface->aura)
1197 		zaura_surface_destroy(disp_surface->aura);
1198 	if (disp_surface->wl_surface)
1199 		wl_surface_destroy(disp_surface->wl_surface);
1200 	for (i = 0; i < buffer_count; i++)
1201 		if (disp_surface->buffers[i])
1202 			wl_buffer_destroy(disp_surface->buffers[i]);
1203 	if (shm_pool)
1204 		wl_shm_pool_destroy(shm_pool);
1205 	free(disp_surface);
1206 	return NULL;
1207 }
1208 
dwl_surface_destroy(struct dwl_surface ** self)1209 void dwl_surface_destroy(struct dwl_surface **self)
1210 {
1211 	size_t i;
1212 
1213 	dwl_context_remove_surface((*self)->context, (*self)->surface_id);
1214 	if ((*self)->virtio_gpu_surface_metadata)
1215 		wp_virtio_gpu_surface_metadata_v1_destroy(
1216 			(*self)->virtio_gpu_surface_metadata);
1217 	if ((*self)->viewport)
1218 		wp_viewport_destroy((*self)->viewport);
1219 	if ((*self)->subsurface)
1220 		wl_subsurface_destroy((*self)->subsurface);
1221 	if ((*self)->xdg_toplevel)
1222 		xdg_toplevel_destroy((*self)->xdg_toplevel);
1223 	if ((*self)->xdg_surface)
1224 		xdg_surface_destroy((*self)->xdg_surface);
1225 	if ((*self)->aura)
1226 		zaura_surface_destroy((*self)->aura);
1227 	if ((*self)->wl_surface)
1228 		wl_surface_destroy((*self)->wl_surface);
1229 	for (i = 0; i < (*self)->buffer_count; i++)
1230 		wl_buffer_destroy((*self)->buffers[i]);
1231 	wl_display_flush((*self)->context->display);
1232 	free(*self);
1233 	*self = NULL;
1234 }
1235 
dwl_surface_commit(struct dwl_surface * self)1236 void dwl_surface_commit(struct dwl_surface *self)
1237 {
1238 	// It is possible that we are committing frames faster than the
1239 	// compositor can put them on the screen. This may result in dropped
1240 	// frames, but this is acceptable considering there is no good way to
1241 	// apply back pressure to the guest gpu driver right now. The intention
1242 	// of this module is to help bootstrap gpu support, so it does not have
1243 	// to have artifact free rendering.
1244 	wl_surface_commit(self->wl_surface);
1245 	wl_display_flush(self->context->display);
1246 }
1247 
dwl_surface_buffer_in_use(struct dwl_surface * self,size_t buffer_index)1248 bool dwl_surface_buffer_in_use(struct dwl_surface *self, size_t buffer_index)
1249 {
1250 	return (self->buffer_use_bit_mask & (1 << buffer_index)) != 0;
1251 }
1252 
dwl_surface_flip(struct dwl_surface * self,size_t buffer_index)1253 void dwl_surface_flip(struct dwl_surface *self, size_t buffer_index)
1254 {
1255 	if (buffer_index >= self->buffer_count)
1256 		return;
1257 	wl_surface_attach(self->wl_surface, self->buffers[buffer_index], 0, 0);
1258 	wl_surface_damage(self->wl_surface, 0, 0, self->width, self->height);
1259 	dwl_surface_commit(self);
1260 	self->buffer_use_bit_mask |= 1 << buffer_index;
1261 }
1262 
dwl_surface_flip_to(struct dwl_surface * self,uint32_t import_id)1263 void dwl_surface_flip_to(struct dwl_surface *self, uint32_t import_id)
1264 {
1265 	// Surface and dmabuf have to exist in same context.
1266 	struct dwl_dmabuf *dmabuf = dwl_context_get_dmabuf(self->context,
1267 							   import_id);
1268 	if (!dmabuf)
1269 		return;
1270 
1271 	if (self->width != dmabuf->width || self->height != dmabuf->height)
1272 		return;
1273 	wl_surface_attach(self->wl_surface, dmabuf->buffer, 0, 0);
1274 	wl_surface_damage(self->wl_surface, 0, 0, self->width, self->height);
1275 	dwl_surface_commit(self);
1276 	dmabuf->in_use = true;
1277 }
1278 
dwl_surface_close_requested(const struct dwl_surface * self)1279 bool dwl_surface_close_requested(const struct dwl_surface *self)
1280 {
1281 	return self->close_requested;
1282 }
1283 
dwl_surface_set_position(struct dwl_surface * self,uint32_t x,uint32_t y)1284 void dwl_surface_set_position(struct dwl_surface *self, uint32_t x, uint32_t y)
1285 {
1286 	if (self->subsurface) {
1287 		wl_subsurface_set_position(self->subsurface, x / self->scale,
1288 					   y / self->scale);
1289 		wl_surface_commit(self->wl_surface);
1290 		wl_display_flush(self->context->display);
1291 	}
1292 }
1293 
dwl_surface_descriptor(const struct dwl_surface * self)1294 const void* dwl_surface_descriptor(const struct dwl_surface *self)
1295 {
1296 	return self->wl_surface;
1297 }
1298 
dwl_context_pending_events(const struct dwl_context * self)1299 bool dwl_context_pending_events(const struct dwl_context *self)
1300 {
1301 	if (self->event_write_pos == self->event_read_pos)
1302 		return false;
1303 
1304 	return true;
1305 }
1306 
dwl_context_next_event(struct dwl_context * self,struct dwl_event * event)1307 void dwl_context_next_event(struct dwl_context *self, struct dwl_event *event)
1308 {
1309 	memcpy(event, self->event_cbuf + self->event_read_pos,
1310 	       sizeof(struct dwl_event));
1311 
1312 	if (++self->event_read_pos == EVENT_BUF_SIZE)
1313 		self->event_read_pos = 0;
1314 }
1315 
dwl_surface_set_scanout_id(struct dwl_surface * self,uint32_t scanout_id)1316 void dwl_surface_set_scanout_id(struct dwl_surface *self, uint32_t scanout_id)
1317 {
1318 	if (self->virtio_gpu_surface_metadata) {
1319 		wp_virtio_gpu_surface_metadata_v1_set_scanout_id(
1320 			self->virtio_gpu_surface_metadata, scanout_id);
1321 	}
1322 }
1323