blob: ea23717b6e1b13d942e4e8606371347c2fd12a94 [file] [log] [blame]
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +02001/*
2 * Copyright © 2010-2011 Benjamin Franzke
3 * Copyright © 2012 Intel Corporation
4 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07005 * 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:
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020012 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070013 * 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.
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020025 */
26
Daniel Stonec228e232013-05-22 18:03:19 +030027#include "config.h"
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020028
Armin Krezović7fb17752016-09-30 14:11:07 +020029#include <assert.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030030#include <stdint.h>
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020031#include <stdlib.h>
32#include <string.h>
33#include <sys/time.h>
Derek Foremana04e9132014-11-19 15:06:17 -080034#include <stdbool.h>
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020035
36#include "compositor.h"
Benoit Gschwind3c530942016-04-15 20:28:32 -070037#include "compositor-headless.h"
38#include "shared/helpers.h"
Derek Foremana04e9132014-11-19 15:06:17 -080039#include "pixman-renderer.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020040#include "presentation-time-server-protocol.h"
Armin Krezović7fb17752016-09-30 14:11:07 +020041#include "windowed-output-api.h"
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020042
Giulio Camuffo954f1832014-10-11 18:27:30 +030043struct headless_backend {
44 struct weston_backend base;
45 struct weston_compositor *compositor;
Benoit Gschwind3c530942016-04-15 20:28:32 -070046
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020047 struct weston_seat fake_seat;
Derek Foremana04e9132014-11-19 15:06:17 -080048 bool use_pixman;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020049};
50
51struct headless_output {
52 struct weston_output base;
Benoit Gschwind3c530942016-04-15 20:28:32 -070053
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020054 struct weston_mode mode;
55 struct wl_event_source *finish_frame_timer;
Derek Foremana04e9132014-11-19 15:06:17 -080056 uint32_t *image_buf;
57 pixman_image_t *image;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020058};
59
Armin Krezovića8fb5ea2016-08-01 19:17:55 +020060static inline struct headless_output *
61to_headless_output(struct weston_output *base)
62{
63 return container_of(base, struct headless_output, base);
64}
65
66static inline struct headless_backend *
67to_headless_backend(struct weston_compositor *base)
68{
69 return container_of(base->backend, struct headless_backend, base);
70}
71
Jonas Ådahle5a12252013-04-05 23:07:11 +020072static void
73headless_output_start_repaint_loop(struct weston_output *output)
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020074{
Pekka Paalanenb5eedad2014-09-23 22:08:45 -040075 struct timespec ts;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020076
Pekka Paalanen662f3842015-03-18 12:17:26 +020077 weston_compositor_read_presentation_clock(output->compositor, &ts);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020078 weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +020079}
80
81static int
82finish_frame_handler(void *data)
83{
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020084 struct headless_output *output = data;
85 struct timespec ts;
86
Pekka Paalanen662f3842015-03-18 12:17:26 +020087 weston_compositor_read_presentation_clock(output->base.compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020088 weston_output_finish_frame(&output->base, &ts, 0);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020089
90 return 1;
91}
92
David Herrmann1edf44c2013-10-22 17:11:26 +020093static int
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020094headless_output_repaint(struct weston_output *output_base,
95 pixman_region32_t *damage)
96{
Armin Krezovića8fb5ea2016-08-01 19:17:55 +020097 struct headless_output *output = to_headless_output(output_base);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020098 struct weston_compositor *ec = output->base.compositor;
99
100 ec->renderer->repaint_output(&output->base, damage);
101
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200102 pixman_region32_subtract(&ec->primary_plane.damage,
103 &ec->primary_plane.damage, damage);
104
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200105 wl_event_source_timer_update(output->finish_frame_timer, 16);
106
David Herrmann1edf44c2013-10-22 17:11:26 +0200107 return 0;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200108}
109
Armin Krezović7fb17752016-09-30 14:11:07 +0200110static int
111headless_output_disable(struct weston_output *base)
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200112{
Armin Krezović7fb17752016-09-30 14:11:07 +0200113 struct headless_output *output = to_headless_output(base);
114 struct headless_backend *b = to_headless_backend(base->compositor);
115
116 if (!output->base.enabled)
117 return 0;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200118
119 wl_event_source_remove(output->finish_frame_timer);
Derek Foremana04e9132014-11-19 15:06:17 -0800120
Giulio Camuffo954f1832014-10-11 18:27:30 +0300121 if (b->use_pixman) {
Derek Foremana04e9132014-11-19 15:06:17 -0800122 pixman_renderer_output_destroy(&output->base);
123 pixman_image_unref(output->image);
124 free(output->image_buf);
125 }
126
Armin Krezović7fb17752016-09-30 14:11:07 +0200127 return 0;
128}
129
130static void
131headless_output_destroy(struct weston_output *base)
132{
133 struct headless_output *output = to_headless_output(base);
134
135 headless_output_disable(&output->base);
Derek Foremana04e9132014-11-19 15:06:17 -0800136 weston_output_destroy(&output->base);
137
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200138 free(output);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200139}
140
141static int
Armin Krezović7fb17752016-09-30 14:11:07 +0200142headless_output_enable(struct weston_output *base)
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200143{
Armin Krezović7fb17752016-09-30 14:11:07 +0200144 struct headless_output *output = to_headless_output(base);
145 struct headless_backend *b = to_headless_backend(base->compositor);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200146 struct wl_event_loop *loop;
147
Armin Krezović7fb17752016-09-30 14:11:07 +0200148 loop = wl_display_get_event_loop(b->compositor->wl_display);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200149 output->finish_frame_timer =
150 wl_event_loop_add_timer(loop, finish_frame_handler, output);
151
Giulio Camuffo954f1832014-10-11 18:27:30 +0300152 if (b->use_pixman) {
Armin Krezović7fb17752016-09-30 14:11:07 +0200153 output->image_buf = malloc(output->base.current_mode->width *
154 output->base.current_mode->height * 4);
Derek Foremana04e9132014-11-19 15:06:17 -0800155 if (!output->image_buf)
Armin Krezović7fb17752016-09-30 14:11:07 +0200156 goto err_malloc;
Derek Foremana04e9132014-11-19 15:06:17 -0800157
158 output->image = pixman_image_create_bits(PIXMAN_x8r8g8b8,
Armin Krezović7fb17752016-09-30 14:11:07 +0200159 output->base.current_mode->width,
160 output->base.current_mode->height,
Derek Foremana04e9132014-11-19 15:06:17 -0800161 output->image_buf,
Armin Krezović7fb17752016-09-30 14:11:07 +0200162 output->base.current_mode->width * 4);
Derek Foremana04e9132014-11-19 15:06:17 -0800163
164 if (pixman_renderer_output_create(&output->base) < 0)
Armin Krezović7fb17752016-09-30 14:11:07 +0200165 goto err_renderer;
Derek Foremana04e9132014-11-19 15:06:17 -0800166
167 pixman_renderer_output_set_buffer(&output->base,
168 output->image);
169 }
170
Armin Krezović7fb17752016-09-30 14:11:07 +0200171 return 0;
172
173err_renderer:
174 pixman_image_unref(output->image);
175 free(output->image_buf);
176err_malloc:
177 wl_event_source_remove(output->finish_frame_timer);
178
179 return -1;
180}
181
182static int
183headless_output_set_size(struct weston_output *base,
184 int width, int height)
185{
186 struct headless_output *output = to_headless_output(base);
187 int output_width, output_height;
188
189 /* We can only be called once. */
190 assert(!output->base.current_mode);
191
192 /* Make sure we have scale set. */
193 assert(output->base.scale);
194
195 output_width = width * output->base.scale;
196 output_height = height * output->base.scale;
197
198 output->mode.flags =
199 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
200 output->mode.width = output_width;
201 output->mode.height = output_height;
202 output->mode.refresh = 60000;
203 wl_list_init(&output->base.mode_list);
204 wl_list_insert(&output->base.mode_list, &output->mode.link);
205
206 output->base.current_mode = &output->mode;
207 output->base.make = "weston";
208 output->base.model = "headless";
209
210 /* XXX: Calculate proper size. */
211 output->base.mm_width = width;
212 output->base.mm_height = height;
213
214 output->base.start_repaint_loop = headless_output_start_repaint_loop;
215 output->base.repaint = headless_output_repaint;
216 output->base.assign_planes = NULL;
217 output->base.set_backlight = NULL;
218 output->base.set_dpms = NULL;
219 output->base.switch_mode = NULL;
220
221 return 0;
222}
223
224static int
225headless_output_create(struct weston_compositor *compositor,
226 const char *name)
227{
228 struct headless_output *output;
229
230 /* name can't be NULL. */
231 assert(name);
232
233 output = zalloc(sizeof *output);
234 if (output == NULL)
235 return -1;
236
237 output->base.name = strdup(name);
238 output->base.destroy = headless_output_destroy;
239 output->base.disable = headless_output_disable;
240 output->base.enable = headless_output_enable;
241
242 weston_output_init_pending(&output->base, compositor);
243 weston_compositor_add_pending_output(&output->base, compositor);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200244
245 return 0;
246}
247
248static void
249headless_restore(struct weston_compositor *ec)
250{
251}
252
253static void
254headless_destroy(struct weston_compositor *ec)
255{
Armin Krezovića8fb5ea2016-08-01 19:17:55 +0200256 struct headless_backend *b = to_headless_backend(ec);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200257
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200258 weston_compositor_shutdown(ec);
259
Giulio Camuffo954f1832014-10-11 18:27:30 +0300260 free(b);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200261}
262
Armin Krezović7fb17752016-09-30 14:11:07 +0200263static const struct weston_windowed_output_api api = {
264 headless_output_set_size,
265 headless_output_create,
266};
267
Giulio Camuffo954f1832014-10-11 18:27:30 +0300268static struct headless_backend *
269headless_backend_create(struct weston_compositor *compositor,
Benoit Gschwind3c530942016-04-15 20:28:32 -0700270 struct weston_headless_backend_config *config)
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200271{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300272 struct headless_backend *b;
Armin Krezović7fb17752016-09-30 14:11:07 +0200273 int ret;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200274
Giulio Camuffo954f1832014-10-11 18:27:30 +0300275 b = zalloc(sizeof *b);
276 if (b == NULL)
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200277 return NULL;
278
Giulio Camuffo954f1832014-10-11 18:27:30 +0300279 b->compositor = compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300280 if (weston_compositor_set_presentation_clock_software(compositor) < 0)
281 goto err_free;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400282
Giulio Camuffo954f1832014-10-11 18:27:30 +0300283 b->base.destroy = headless_destroy;
284 b->base.restore = headless_restore;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200285
Benoit Gschwind3c530942016-04-15 20:28:32 -0700286 b->use_pixman = config->use_pixman;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300287 if (b->use_pixman) {
288 pixman_renderer_init(compositor);
Derek Foremana04e9132014-11-19 15:06:17 -0800289 }
Armin Krezovićd84deeb2016-06-23 11:59:29 +0200290
Giulio Camuffo954f1832014-10-11 18:27:30 +0300291 if (!b->use_pixman && noop_renderer_init(compositor) < 0)
Emilio Pozuelo Monfortdd9f6bc2014-02-07 09:34:43 +0100292 goto err_input;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200293
Giulio Camuffo954f1832014-10-11 18:27:30 +0300294 compositor->backend = &b->base;
Armin Krezović7fb17752016-09-30 14:11:07 +0200295
296 ret = weston_plugin_api_register(compositor, WESTON_WINDOWED_OUTPUT_API_NAME,
297 &api, sizeof(api));
298
299 if (ret < 0) {
300 weston_log("Failed to register output API.\n");
301 goto err_input;
302 }
303
Giulio Camuffo954f1832014-10-11 18:27:30 +0300304 return b;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200305
Emilio Pozuelo Monfortdd9f6bc2014-02-07 09:34:43 +0100306err_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300307 weston_compositor_shutdown(compositor);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200308err_free:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300309 free(b);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200310 return NULL;
311}
312
Benoit Gschwind3c530942016-04-15 20:28:32 -0700313static void
314config_init_to_defaults(struct weston_headless_backend_config *config)
315{
316}
317
Giulio Camuffo954f1832014-10-11 18:27:30 +0300318WL_EXPORT int
319backend_init(struct weston_compositor *compositor,
Giulio Camuffo93daabb2015-10-17 19:24:14 +0300320 struct weston_backend_config *config_base)
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200321{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300322 struct headless_backend *b;
Benoit Gschwind3c530942016-04-15 20:28:32 -0700323 struct weston_headless_backend_config config = {{ 0, }};
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200324
Benoit Gschwind3c530942016-04-15 20:28:32 -0700325 if (config_base == NULL ||
326 config_base->struct_version != WESTON_HEADLESS_BACKEND_CONFIG_VERSION ||
327 config_base->struct_size > sizeof(struct weston_headless_backend_config)) {
328 weston_log("headless backend config structure is invalid\n");
329 return -1;
330 }
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200331
Benoit Gschwind3c530942016-04-15 20:28:32 -0700332 config_init_to_defaults(&config);
333 memcpy(&config, config_base, config_base->struct_size);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200334
Benoit Gschwind3c530942016-04-15 20:28:32 -0700335 b = headless_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300336 if (b == NULL)
337 return -1;
Benoit Gschwind3c530942016-04-15 20:28:32 -0700338
Giulio Camuffo954f1832014-10-11 18:27:30 +0300339 return 0;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200340}