1 /*
2 * Copyright © 2010-2011 Benjamin Franzke
3 * Copyright © 2012 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27 #include "config.h"
28
29 #include <assert.h>
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/time.h>
34 #include <stdbool.h>
35 #include <drm_fourcc.h>
36
37 #include <libweston/libweston.h>
38 #include <libweston/backend-headless.h>
39 #include "shared/helpers.h"
40 #include "linux-explicit-synchronization.h"
41 #include "pixman-renderer.h"
42 #include "renderer-gl/gl-renderer.h"
43 #include "shared/weston-egl-ext.h"
44 #include "linux-dmabuf.h"
45 #include "presentation-time-server-protocol.h"
46 #include <libweston/windowed-output-api.h>
47
48 enum headless_renderer_type {
49 HEADLESS_NOOP,
50 HEADLESS_PIXMAN,
51 HEADLESS_GL,
52 };
53
54 struct headless_backend {
55 struct weston_backend base;
56 struct weston_compositor *compositor;
57
58 struct weston_seat fake_seat;
59 enum headless_renderer_type renderer_type;
60
61 struct gl_renderer_interface *glri;
62 };
63
64 struct headless_head {
65 struct weston_head base;
66 };
67
68 struct headless_output {
69 struct weston_output base;
70
71 struct weston_mode mode;
72 struct wl_event_source *finish_frame_timer;
73 uint32_t *image_buf;
74 pixman_image_t *image;
75 };
76
77 static const uint32_t headless_formats[] = {
78 DRM_FORMAT_XRGB8888,
79 DRM_FORMAT_ARGB8888,
80 };
81
82 static inline struct headless_head *
to_headless_head(struct weston_head * base)83 to_headless_head(struct weston_head *base)
84 {
85 return container_of(base, struct headless_head, base);
86 }
87
88 static inline struct headless_output *
to_headless_output(struct weston_output * base)89 to_headless_output(struct weston_output *base)
90 {
91 return container_of(base, struct headless_output, base);
92 }
93
94 static inline struct headless_backend *
to_headless_backend(struct weston_compositor * base)95 to_headless_backend(struct weston_compositor *base)
96 {
97 return container_of(base->backend, struct headless_backend, base);
98 }
99
100 static int
headless_output_start_repaint_loop(struct weston_output * output)101 headless_output_start_repaint_loop(struct weston_output *output)
102 {
103 struct timespec ts;
104
105 weston_compositor_read_presentation_clock(output->compositor, &ts);
106 weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
107
108 return 0;
109 }
110
111 static int
finish_frame_handler(void * data)112 finish_frame_handler(void *data)
113 {
114 struct headless_output *output = data;
115 struct timespec ts;
116
117 weston_compositor_read_presentation_clock(output->base.compositor, &ts);
118 weston_output_finish_frame(&output->base, &ts, 0);
119
120 return 1;
121 }
122
123 static int
headless_output_repaint(struct weston_output * output_base,pixman_region32_t * damage,void * repaint_data)124 headless_output_repaint(struct weston_output *output_base,
125 pixman_region32_t *damage,
126 void *repaint_data)
127 {
128 struct headless_output *output = to_headless_output(output_base);
129 struct weston_compositor *ec = output->base.compositor;
130
131 ec->renderer->repaint_output(&output->base, damage);
132
133 pixman_region32_subtract(&ec->primary_plane.damage,
134 &ec->primary_plane.damage, damage);
135
136 wl_event_source_timer_update(output->finish_frame_timer, 16);
137
138 return 0;
139 }
140
141 static void
headless_output_disable_gl(struct headless_output * output)142 headless_output_disable_gl(struct headless_output *output)
143 {
144 struct weston_compositor *compositor = output->base.compositor;
145 struct headless_backend *b = to_headless_backend(compositor);
146
147 b->glri->output_destroy(&output->base);
148 }
149
150 static void
headless_output_disable_pixman(struct headless_output * output)151 headless_output_disable_pixman(struct headless_output *output)
152 {
153 pixman_renderer_output_destroy(&output->base);
154 pixman_image_unref(output->image);
155 free(output->image_buf);
156 }
157
158 static int
headless_output_disable(struct weston_output * base)159 headless_output_disable(struct weston_output *base)
160 {
161 struct headless_output *output = to_headless_output(base);
162 struct headless_backend *b = to_headless_backend(base->compositor);
163
164 if (!output->base.enabled)
165 return 0;
166
167 wl_event_source_remove(output->finish_frame_timer);
168
169 switch (b->renderer_type) {
170 case HEADLESS_GL:
171 headless_output_disable_gl(output);
172 break;
173 case HEADLESS_PIXMAN:
174 headless_output_disable_pixman(output);
175 break;
176 case HEADLESS_NOOP:
177 break;
178 }
179
180 return 0;
181 }
182
183 static void
headless_output_destroy(struct weston_output * base)184 headless_output_destroy(struct weston_output *base)
185 {
186 struct headless_output *output = to_headless_output(base);
187
188 headless_output_disable(&output->base);
189 weston_output_release(&output->base);
190
191 free(output);
192 }
193
194 static int
headless_output_enable_gl(struct headless_output * output)195 headless_output_enable_gl(struct headless_output *output)
196 {
197 struct weston_compositor *compositor = output->base.compositor;
198 struct headless_backend *b = to_headless_backend(compositor);
199 const struct gl_renderer_pbuffer_options options = {
200 .width = output->base.current_mode->width,
201 .height = output->base.current_mode->height,
202 .drm_formats = headless_formats,
203 .drm_formats_count = ARRAY_LENGTH(headless_formats),
204 };
205
206 if (b->glri->output_pbuffer_create(&output->base, &options) < 0) {
207 weston_log("failed to create gl renderer output state\n");
208 return -1;
209 }
210
211 return 0;
212 }
213
214 static int
headless_output_enable_pixman(struct headless_output * output)215 headless_output_enable_pixman(struct headless_output *output)
216 {
217 const struct pixman_renderer_output_options options = {
218 .use_shadow = true,
219 };
220
221 output->image_buf = malloc(output->base.current_mode->width *
222 output->base.current_mode->height * 4);
223 if (!output->image_buf)
224 return -1;
225
226 output->image = pixman_image_create_bits(PIXMAN_x8r8g8b8,
227 output->base.current_mode->width,
228 output->base.current_mode->height,
229 output->image_buf,
230 output->base.current_mode->width * 4);
231
232 if (pixman_renderer_output_create(&output->base, &options) < 0)
233 goto err_renderer;
234
235 pixman_renderer_output_set_buffer(&output->base, output->image);
236
237 return 0;
238
239 err_renderer:
240 pixman_image_unref(output->image);
241 free(output->image_buf);
242
243 return -1;
244 }
245
246 static int
headless_output_enable(struct weston_output * base)247 headless_output_enable(struct weston_output *base)
248 {
249 struct headless_output *output = to_headless_output(base);
250 struct headless_backend *b = to_headless_backend(base->compositor);
251 struct wl_event_loop *loop;
252 int ret = 0;
253
254 loop = wl_display_get_event_loop(b->compositor->wl_display);
255 output->finish_frame_timer =
256 wl_event_loop_add_timer(loop, finish_frame_handler, output);
257
258 switch (b->renderer_type) {
259 case HEADLESS_GL:
260 ret = headless_output_enable_gl(output);
261 break;
262 case HEADLESS_PIXMAN:
263 ret = headless_output_enable_pixman(output);
264 break;
265 case HEADLESS_NOOP:
266 break;
267 }
268
269 if (ret < 0) {
270 wl_event_source_remove(output->finish_frame_timer);
271 return -1;
272 }
273
274 return 0;
275 }
276
277 static int
headless_output_set_size(struct weston_output * base,int width,int height)278 headless_output_set_size(struct weston_output *base,
279 int width, int height)
280 {
281 struct headless_output *output = to_headless_output(base);
282 struct weston_head *head;
283 int output_width, output_height;
284
285 /* We can only be called once. */
286 assert(!output->base.current_mode);
287
288 /* Make sure we have scale set. */
289 assert(output->base.scale);
290
291 wl_list_for_each(head, &output->base.head_list, output_link) {
292 weston_head_set_monitor_strings(head, "weston", "headless",
293 NULL);
294
295 /* XXX: Calculate proper size. */
296 weston_head_set_physical_size(head, width, height);
297 }
298
299 output_width = width * output->base.scale;
300 output_height = height * output->base.scale;
301
302 output->mode.flags =
303 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
304 output->mode.width = output_width;
305 output->mode.height = output_height;
306 output->mode.refresh = 60000;
307 wl_list_insert(&output->base.mode_list, &output->mode.link);
308
309 output->base.current_mode = &output->mode;
310
311 output->base.start_repaint_loop = headless_output_start_repaint_loop;
312 output->base.repaint = headless_output_repaint;
313 output->base.assign_planes = NULL;
314 output->base.set_backlight = NULL;
315 output->base.set_dpms = NULL;
316 output->base.switch_mode = NULL;
317
318 return 0;
319 }
320
321 static struct weston_output *
headless_output_create(struct weston_compositor * compositor,const char * name)322 headless_output_create(struct weston_compositor *compositor, const char *name)
323 {
324 struct headless_output *output;
325
326 /* name can't be NULL. */
327 assert(name);
328
329 output = zalloc(sizeof *output);
330 if (!output)
331 return NULL;
332
333 weston_output_init(&output->base, compositor, name);
334
335 output->base.destroy = headless_output_destroy;
336 output->base.disable = headless_output_disable;
337 output->base.enable = headless_output_enable;
338 output->base.attach_head = NULL;
339
340 weston_compositor_add_pending_output(&output->base, compositor);
341
342 return &output->base;
343 }
344
345 static int
headless_head_create(struct weston_compositor * compositor,const char * name)346 headless_head_create(struct weston_compositor *compositor,
347 const char *name)
348 {
349 struct headless_head *head;
350
351 /* name can't be NULL. */
352 assert(name);
353
354 head = zalloc(sizeof *head);
355 if (head == NULL)
356 return -1;
357
358 weston_head_init(&head->base, name);
359 weston_head_set_connection_status(&head->base, true);
360
361 /* Ideally all attributes of the head would be set here, so that the
362 * user has all the information when deciding to create outputs.
363 * We do not have those until set_size() time through.
364 */
365
366 weston_compositor_add_head(compositor, &head->base);
367
368 return 0;
369 }
370
371 static void
headless_head_destroy(struct headless_head * head)372 headless_head_destroy(struct headless_head *head)
373 {
374 weston_head_release(&head->base);
375 free(head);
376 }
377
378 static void
headless_destroy(struct weston_compositor * ec)379 headless_destroy(struct weston_compositor *ec)
380 {
381 struct headless_backend *b = to_headless_backend(ec);
382 struct weston_head *base, *next;
383
384 weston_compositor_shutdown(ec);
385
386 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
387 headless_head_destroy(to_headless_head(base));
388
389 free(b);
390 }
391
392 static int
headless_gl_renderer_init(struct headless_backend * b)393 headless_gl_renderer_init(struct headless_backend *b)
394 {
395 const struct gl_renderer_display_options options = {
396 .egl_platform = EGL_PLATFORM_SURFACELESS_MESA,
397 .egl_native_display = EGL_DEFAULT_DISPLAY,
398 .egl_surface_type = EGL_PBUFFER_BIT,
399 .drm_formats = headless_formats,
400 .drm_formats_count = ARRAY_LENGTH(headless_formats),
401 };
402
403 b->glri = weston_load_module("gl-renderer.so", "gl_renderer_interface");
404 if (!b->glri)
405 return -1;
406
407 return b->glri->display_create(b->compositor, &options);
408 }
409
410 static const struct weston_windowed_output_api api = {
411 headless_output_set_size,
412 headless_head_create,
413 };
414
415 static struct headless_backend *
headless_backend_create(struct weston_compositor * compositor,struct weston_headless_backend_config * config)416 headless_backend_create(struct weston_compositor *compositor,
417 struct weston_headless_backend_config *config)
418 {
419 struct headless_backend *b;
420 int ret;
421
422 b = zalloc(sizeof *b);
423 if (b == NULL)
424 return NULL;
425
426 b->compositor = compositor;
427 compositor->backend = &b->base;
428
429 if (weston_compositor_set_presentation_clock_software(compositor) < 0)
430 goto err_free;
431
432 b->base.destroy = headless_destroy;
433 b->base.create_output = headless_output_create;
434
435 if (config->use_pixman && config->use_gl) {
436 weston_log("Error: cannot use both Pixman *and* GL renderers.\n");
437 goto err_free;
438 }
439
440 if (config->use_gl)
441 b->renderer_type = HEADLESS_GL;
442 else if (config->use_pixman)
443 b->renderer_type = HEADLESS_PIXMAN;
444 else
445 b->renderer_type = HEADLESS_NOOP;
446
447 switch (b->renderer_type) {
448 case HEADLESS_GL:
449 ret = headless_gl_renderer_init(b);
450 break;
451 case HEADLESS_PIXMAN:
452 ret = pixman_renderer_init(compositor);
453 break;
454 case HEADLESS_NOOP:
455 ret = noop_renderer_init(compositor);
456 break;
457 default:
458 assert(0 && "invalid renderer type");
459 ret = -1;
460 }
461
462 if (ret < 0)
463 goto err_input;
464
465 if (compositor->renderer->import_dmabuf) {
466 if (linux_dmabuf_setup(compositor) < 0) {
467 weston_log("Error: dmabuf protocol setup failed.\n");
468 goto err_input;
469 }
470 }
471
472 /* Support zwp_linux_explicit_synchronization_unstable_v1 to enable
473 * testing. */
474 if (linux_explicit_synchronization_setup(compositor) < 0)
475 goto err_input;
476
477 ret = weston_plugin_api_register(compositor, WESTON_WINDOWED_OUTPUT_API_NAME,
478 &api, sizeof(api));
479
480 if (ret < 0) {
481 weston_log("Failed to register output API.\n");
482 goto err_input;
483 }
484
485 return b;
486
487 err_input:
488 weston_compositor_shutdown(compositor);
489 err_free:
490 free(b);
491 return NULL;
492 }
493
494 static void
config_init_to_defaults(struct weston_headless_backend_config * config)495 config_init_to_defaults(struct weston_headless_backend_config *config)
496 {
497 }
498
499 WL_EXPORT int
weston_backend_init(struct weston_compositor * compositor,struct weston_backend_config * config_base)500 weston_backend_init(struct weston_compositor *compositor,
501 struct weston_backend_config *config_base)
502 {
503 struct headless_backend *b;
504 struct weston_headless_backend_config config = {{ 0, }};
505
506 if (config_base == NULL ||
507 config_base->struct_version != WESTON_HEADLESS_BACKEND_CONFIG_VERSION ||
508 config_base->struct_size > sizeof(struct weston_headless_backend_config)) {
509 weston_log("headless backend config structure is invalid\n");
510 return -1;
511 }
512
513 config_init_to_defaults(&config);
514 memcpy(&config, config_base, config_base->struct_size);
515
516 b = headless_backend_create(compositor, &config);
517 if (b == NULL)
518 return -1;
519
520 return 0;
521 }
522