blob: ac762c18e04d3cd86a3f5d54d0b1de3a47ec2497 [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,
Daniel Stoneb1f166d2017-03-01 11:34:10 +000095 pixman_region32_t *damage,
96 void *repaint_data)
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020097{
Armin Krezovića8fb5ea2016-08-01 19:17:55 +020098 struct headless_output *output = to_headless_output(output_base);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +020099 struct weston_compositor *ec = output->base.compositor;
100
101 ec->renderer->repaint_output(&output->base, damage);
102
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200103 pixman_region32_subtract(&ec->primary_plane.damage,
104 &ec->primary_plane.damage, damage);
105
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200106 wl_event_source_timer_update(output->finish_frame_timer, 16);
107
David Herrmann1edf44c2013-10-22 17:11:26 +0200108 return 0;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200109}
110
Armin Krezović7fb17752016-09-30 14:11:07 +0200111static int
112headless_output_disable(struct weston_output *base)
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200113{
Armin Krezović7fb17752016-09-30 14:11:07 +0200114 struct headless_output *output = to_headless_output(base);
115 struct headless_backend *b = to_headless_backend(base->compositor);
116
117 if (!output->base.enabled)
118 return 0;
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200119
120 wl_event_source_remove(output->finish_frame_timer);
Derek Foremana04e9132014-11-19 15:06:17 -0800121
Giulio Camuffo954f1832014-10-11 18:27:30 +0300122 if (b->use_pixman) {
Derek Foremana04e9132014-11-19 15:06:17 -0800123 pixman_renderer_output_destroy(&output->base);
124 pixman_image_unref(output->image);
125 free(output->image_buf);
126 }
127
Armin Krezović7fb17752016-09-30 14:11:07 +0200128 return 0;
129}
130
131static void
132headless_output_destroy(struct weston_output *base)
133{
134 struct headless_output *output = to_headless_output(base);
135
136 headless_output_disable(&output->base);
Derek Foremana04e9132014-11-19 15:06:17 -0800137 weston_output_destroy(&output->base);
138
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200139 free(output);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200140}
141
142static int
Armin Krezović7fb17752016-09-30 14:11:07 +0200143headless_output_enable(struct weston_output *base)
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200144{
Armin Krezović7fb17752016-09-30 14:11:07 +0200145 struct headless_output *output = to_headless_output(base);
146 struct headless_backend *b = to_headless_backend(base->compositor);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200147 struct wl_event_loop *loop;
148
Armin Krezović7fb17752016-09-30 14:11:07 +0200149 loop = wl_display_get_event_loop(b->compositor->wl_display);
Ander Conselvan de Oliveira11f8d402012-10-29 18:19:24 +0200150 output->finish_frame_timer =
151 wl_event_loop_add_timer(loop, finish_frame_handler, output);
152
Giulio Camuffo954f1832014-10-11 18:27:30 +0300153 if (b->use_pixman) {
Armin Krezović7fb17752016-09-30 14:11:07 +0200154 output->image_buf = malloc(output->base.current_mode->width *
155 output->base.current_mode->height * 4);
Derek Foremana04e9132014-11-19 15:06:17 -0800156 if (!output->image_buf)
Armin Krezović7fb17752016-09-30 14:11:07 +0200157 goto err_malloc;
Derek Foremana04e9132014-11-19 15:06:17 -0800158
159 output->image = pixman_image_create_bits(PIXMAN_x8r8g8b8,
Armin Krezović7fb17752016-09-30 14:11:07 +0200160 output->base.current_mode->width,
161 output->base.current_mode->height,
Derek Foremana04e9132014-11-19 15:06:17 -0800162 output->image_buf,
Armin Krezović7fb17752016-09-30 14:11:07 +0200163 output->base.current_mode->width * 4);
Derek Foremana04e9132014-11-19 15:06:17 -0800164
165 if (pixman_renderer_output_create(&output->base) < 0)
Armin Krezović7fb17752016-09-30 14:11:07 +0200166 goto err_renderer;
Derek Foremana04e9132014-11-19 15:06:17 -0800167
168 pixman_renderer_output_set_buffer(&output->base,
169 output->image);
170 }
171
Armin Krezović7fb17752016-09-30 14:11:07 +0200172 return 0;
173
174err_renderer:
175 pixman_image_unref(output->image);
176 free(output->image_buf);
177err_malloc:
178 wl_event_source_remove(output->finish_frame_timer);
179
180 return -1;
181}
182
183static int
184headless_output_set_size(struct weston_output *base,
185 int width, int height)
186{
187 struct headless_output *output = to_headless_output(base);
188 int output_width, output_height;
189
190 /* We can only be called once. */
191 assert(!output->base.current_mode);
192
193 /* Make sure we have scale set. */
194 assert(output->base.scale);
195
196 output_width = width * output->base.scale;
197 output_height = height * output->base.scale;
198
199 output->mode.flags =
200 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
201 output->mode.width = output_width;
202 output->mode.height = output_height;
203 output->mode.refresh = 60000;
Armin Krezović7fb17752016-09-30 14:11:07 +0200204 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
Pekka Paalanen26ac2e12017-04-03 13:18:13 +0300237 weston_output_init(&output->base, compositor, name);
238
Armin Krezović7fb17752016-09-30 14:11:07 +0200239 output->base.destroy = headless_output_destroy;
240 output->base.disable = headless_output_disable;
241 output->base.enable = headless_output_enable;
242
Armin Krezović7fb17752016-09-30 14:11:07 +0200243 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
Quentin Glidic23e1d6f2016-12-02 14:08:44 +0100319weston_backend_init(struct weston_compositor *compositor,
320 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}