• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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