blob: 872fcfa5ad7272356b2557db33c94dc9ce1e6a3b [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033
Benjamin Franzkec649a922011-03-02 11:56:04 +010034#include <xf86drm.h>
35#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050036#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010037
Benjamin Franzke060cf802011-04-30 09:32:11 +020038#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020039#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040040#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010043#include "gl-renderer.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020044#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010045#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040046
Kristian Høgsberg061c4252012-06-28 11:28:15 -040047static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060048static char *output_name;
49static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060050static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060051static struct wl_list configured_output_list;
52
53enum output_config {
54 OUTPUT_CONFIG_INVALID = 0,
55 OUTPUT_CONFIG_OFF,
56 OUTPUT_CONFIG_PREFERRED,
57 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060058 OUTPUT_CONFIG_MODE,
59 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060060};
61
62struct drm_configured_output {
63 char *name;
64 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060065 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060066 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060067 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060068 enum output_config config;
69 struct wl_list link;
70};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040071
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040072struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050073 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
75 struct udev *udev;
76 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040077
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010078 struct udev_monitor *udev_monitor;
79 struct wl_event_source *udev_drm_source;
80
Benjamin Franzke2af7f102011-03-02 11:14:59 +010081 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010082 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010083 int fd;
84 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020085 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050086 uint32_t *crtcs;
87 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050088 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010089 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050090 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020091
Rob Clark4339add2012-08-09 14:18:28 -050092 /* we need these parameters in order to not fail drmModeAddFB2()
93 * due to out of bounds dimensions, and then mistakenly set
94 * sprites_are_broken:
95 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020096 uint32_t min_width, max_width;
97 uint32_t min_height, max_height;
98 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050099
Jesse Barnes58ef3792012-02-23 09:45:49 -0500100 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500101 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200102 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500103
Rob Clarkab5b1e32012-08-09 13:24:45 -0500104 int cursors_are_broken;
105
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400107};
108
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500110 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400111 drmModeModeInfo mode_info;
112};
113
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300114struct drm_output;
115
116struct drm_fb {
117 struct gbm_bo *bo;
118 struct drm_output *output;
119 uint32_t fb_id;
120 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200121 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300122};
123
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400124struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500125 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400127 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400128 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500129 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400130 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700131 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200132
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300133 int vblank_pending;
134 int page_flip_pending;
135
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400136 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400137 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400138 struct weston_plane cursor_plane;
139 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400140 struct weston_surface *cursor_surface;
141 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300142 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200143 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144};
145
Jesse Barnes58ef3792012-02-23 09:45:49 -0500146/*
147 * An output has a primary display plane plus zero or more sprites for
148 * blending display contents.
149 */
150struct drm_sprite {
151 struct wl_list link;
152
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400153 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500154
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200155 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300156 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500157 struct drm_compositor *compositor;
158
Jesse Barnes58ef3792012-02-23 09:45:49 -0500159 uint32_t possible_crtcs;
160 uint32_t plane_id;
161 uint32_t count_formats;
162
163 int32_t src_x, src_y;
164 uint32_t src_w, src_h;
165 uint32_t dest_x, dest_y;
166 uint32_t dest_w, dest_h;
167
168 uint32_t formats[];
169};
170
Pekka Paalanen33156972012-08-03 13:30:30 -0400171struct drm_seat {
172 struct weston_seat base;
173 struct wl_list devices_list;
174 struct udev_monitor *udev_monitor;
175 struct wl_event_source *udev_monitor_source;
176 char *seat_id;
177};
178
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400179static void
180drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400181
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
184{
185 struct weston_compositor *ec = output_base->compositor;
186 struct drm_compositor *c =(struct drm_compositor *) ec;
187 struct drm_output *output = (struct drm_output *) output_base;
188 int crtc;
189
190 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
191 if (c->crtcs[crtc] != output->crtc_id)
192 continue;
193
194 if (supported & (1 << crtc))
195 return -1;
196 }
197
198 return 0;
199}
200
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300201static void
202drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
203{
204 struct drm_fb *fb = data;
205 struct gbm_device *gbm = gbm_bo_get_device(bo);
206
207 if (fb->fb_id)
208 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
209
Pekka Paalanende685b82012-12-04 15:58:12 +0200210 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300211
212 free(data);
213}
214
215static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500216drm_fb_get_from_bo(struct gbm_bo *bo,
217 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300218{
219 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500220 uint32_t width, height, stride, handle;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200221 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300222 int ret;
223
224 if (fb)
225 return fb;
226
227 fb = malloc(sizeof *fb);
228
229 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300230 fb->is_client_buffer = 0;
Pekka Paalanende685b82012-12-04 15:58:12 +0200231 fb->buffer_ref.buffer = NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300232
233 width = gbm_bo_get_width(bo);
234 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400235 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300236 handle = gbm_bo_get_handle(bo).u32;
237
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200238 if (compositor->min_width > width || width > compositor->max_width ||
239 compositor->min_height > height ||
240 height > compositor->max_height) {
241 weston_log("bo geometry out of bounds\n");
242 goto err_free;
243 }
244
245 ret = -1;
246
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200247 if (format && !compositor->no_addfb2) {
248 handles[0] = handle;
249 pitches[0] = stride;
250 offsets[0] = 0;
251
252 ret = drmModeAddFB2(compositor->drm.fd, width, height,
253 format, handles, pitches, offsets,
254 &fb->fb_id, 0);
255 if (ret) {
256 weston_log("addfb2 failed: %m\n");
257 compositor->no_addfb2 = 1;
258 compositor->sprites_are_broken = 1;
259 }
260 }
261
262 if (ret)
263 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
264 stride, handle, &fb->fb_id);
265
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300266 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200267 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200268 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300269 }
270
271 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
272
273 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200274
275err_free:
276 free(fb);
277 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300278}
279
280static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200281drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
282{
Pekka Paalanende685b82012-12-04 15:58:12 +0200283 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200284
285 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200286
Pekka Paalanende685b82012-12-04 15:58:12 +0200287 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200288}
289
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200290static void
291drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
292{
293 if (!fb)
294 return;
295
296 if (fb->bo) {
297 if (fb->is_client_buffer)
298 gbm_bo_destroy(fb->bo);
299 else
300 gbm_surface_release_buffer(output->surface,
301 output->current->bo);
302 }
303}
304
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500305static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200306drm_output_check_scanout_format(struct drm_output *output,
307 struct weston_surface *es, struct gbm_bo *bo)
308{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200309 uint32_t format;
310 pixman_region32_t r;
311
312 format = gbm_bo_get_format(bo);
313
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500314 switch (format) {
315 case GBM_FORMAT_XRGB8888:
316 return format;
317 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200318 /* We can only scanout an ARGB buffer if the surface's
319 * opaque region covers the whole output */
320 pixman_region32_init(&r);
321 pixman_region32_subtract(&r, &output->base.region,
322 &es->opaque);
323
324 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500325 format = GBM_FORMAT_XRGB8888;
326 else
327 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200328
329 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200330
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500331 return format;
332 default:
333 return 0;
334 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200335}
336
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400337static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400338drm_output_prepare_scanout_surface(struct weston_output *_output,
339 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500340{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400341 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500342 struct drm_compositor *c =
343 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200344 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300345 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500346 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500347
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500348 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200349 es->geometry.y != output->base.y ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200350 buffer == NULL ||
351 buffer->width != output->base.current->width ||
352 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200353 output->base.transform != es->buffer_transform ||
354 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400355 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500356
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400357 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200358 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500359
Rob Bradford9b101872012-09-14 23:25:41 +0100360 /* Unable to use the buffer for scanout */
361 if (!bo)
362 return NULL;
363
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500364 format = drm_output_check_scanout_format(output, es, bo);
365 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300366 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400367 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300368 }
369
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500370 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300371 if (!output->next) {
372 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400373 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300374 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500375
Pekka Paalanende685b82012-12-04 15:58:12 +0200376 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500377
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400378 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500379}
380
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500381static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400382drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400383{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200384 struct drm_compositor *c =
385 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300386 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400387
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200388 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400389
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200390 pixman_region32_subtract(&c->base.primary_plane.damage,
391 &c->base.primary_plane.damage, damage);
392
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300393 bo = gbm_surface_lock_front_buffer(output->surface);
394 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200395 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400396 return;
397 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300398
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500399 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300400 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200401 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300402 gbm_surface_release_buffer(output->surface, bo);
403 return;
404 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400405}
406
407static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500408drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400409 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100410{
411 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500412 struct drm_compositor *compositor =
413 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500414 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400415 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500416 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100417
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300418 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400419 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300420 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400421 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100422
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400423 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300424 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400425 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300426 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400427 &output->connector_id, 1,
428 &mode->mode_info);
429 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200430 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400431 return;
432 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200433 }
434
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500435 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300436 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500437 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200438 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500439 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500440 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100441
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300442 output->page_flip_pending = 1;
443
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400444 drm_output_set_cursor(output);
445
Jesse Barnes58ef3792012-02-23 09:45:49 -0500446 /*
447 * Now, update all the sprite surfaces
448 */
449 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200450 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500451 drmVBlank vbl = {
452 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
453 .request.sequence = 1,
454 };
455
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200456 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200457 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500458 continue;
459
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200460 if (s->next && !compositor->sprites_hidden)
461 fb_id = s->next->fb_id;
462
Jesse Barnes58ef3792012-02-23 09:45:49 -0500463 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200464 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500465 s->dest_x, s->dest_y,
466 s->dest_w, s->dest_h,
467 s->src_x, s->src_y,
468 s->src_w, s->src_h);
469 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200470 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500471 ret, strerror(errno));
472
Rob Clark5ca1a472012-08-08 20:27:37 -0500473 if (output->pipe > 0)
474 vbl.request.type |= DRM_VBLANK_SECONDARY;
475
Jesse Barnes58ef3792012-02-23 09:45:49 -0500476 /*
477 * Queue a vblank signal so we know when the surface
478 * becomes active on the display or has been replaced.
479 */
480 vbl.request.signal = (unsigned long)s;
481 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
482 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200483 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500484 ret, strerror(errno));
485 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300486
487 s->output = output;
488 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500489 }
490
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500491 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400492}
493
494static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500495vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
496 void *data)
497{
498 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300499 struct drm_output *output = s->output;
500 uint32_t msecs;
501
502 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500503
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200504 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200505 s->current = s->next;
506 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300507
508 if (!output->page_flip_pending) {
509 msecs = sec * 1000 + usec / 1000;
510 weston_output_finish_frame(&output->base, msecs);
511 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500512}
513
514static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400515page_flip_handler(int fd, unsigned int frame,
516 unsigned int sec, unsigned int usec, void *data)
517{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200518 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400519 uint32_t msecs;
520
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300521 output->page_flip_pending = 0;
522
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200523 drm_output_release_fb(output, output->current);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300524 output->current = output->next;
525 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400526
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300527 if (!output->vblank_pending) {
528 msecs = sec * 1000 + usec / 1000;
529 weston_output_finish_frame(&output->base, msecs);
530 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200531}
532
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500533static uint32_t
534drm_output_check_sprite_format(struct drm_sprite *s,
535 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500536{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500537 uint32_t i, format;
538
539 format = gbm_bo_get_format(bo);
540
541 if (format == GBM_FORMAT_ARGB8888) {
542 pixman_region32_t r;
543
544 pixman_region32_init(&r);
545 pixman_region32_subtract(&r, &es->transform.boundingbox,
546 &es->transform.opaque);
547
548 if (!pixman_region32_not_empty(&r))
549 format = GBM_FORMAT_XRGB8888;
550
551 pixman_region32_fini(&r);
552 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500553
554 for (i = 0; i < s->count_formats; i++)
555 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500556 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500557
558 return 0;
559}
560
561static int
562drm_surface_transform_supported(struct weston_surface *es)
563{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400564 struct weston_matrix *matrix = &es->transform.matrix;
565 int i;
566
567 if (!es->transform.enabled)
568 return 1;
569
570 for (i = 0; i < 16; i++) {
571 switch (i) {
572 case 10:
573 case 15:
574 if (matrix->d[i] != 1.0)
575 return 0;
576 break;
577 case 0:
578 case 5:
579 case 12:
580 case 13:
581 break;
582 default:
583 if (matrix->d[i] != 0.0)
584 return 0;
585 break;
586 }
587 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588
589 return 1;
590}
591
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400592static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500593drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400594 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500595{
596 struct weston_compositor *ec = output_base->compositor;
597 struct drm_compositor *c =(struct drm_compositor *) ec;
598 struct drm_sprite *s;
599 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200602 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400604 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200606 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200607 return NULL;
608
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500609 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400610 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500611
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300612 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400613 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300614
Pekka Paalanende685b82012-12-04 15:58:12 +0200615 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400616 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500617
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200618 if (es->alpha != 1.0f)
619 return NULL;
620
Pekka Paalanende685b82012-12-04 15:58:12 +0200621 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500622 return NULL;
623
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400625 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 wl_list_for_each(s, &c->sprite_list, link) {
628 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
629 continue;
630
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200631 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 found = 1;
633 break;
634 }
635 }
636
637 /* No sprites available */
638 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400639 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400641 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200642 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400643 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400644 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400645
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500646 format = drm_output_check_sprite_format(s, es, bo);
647 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200648 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400649 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650 }
651
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200652 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200653 if (!s->next) {
654 gbm_bo_destroy(bo);
655 return NULL;
656 }
657
Pekka Paalanende685b82012-12-04 15:58:12 +0200658 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500659
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400660 box = pixman_region32_extents(&es->transform.boundingbox);
661 s->plane.x = box->x1;
662 s->plane.y = box->y1;
663
Jesse Barnes58ef3792012-02-23 09:45:49 -0500664 /*
665 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200666 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500667 * for us already).
668 */
669 pixman_region32_init(&dest_rect);
670 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
671 &output_base->region);
672 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
673 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200674 tbox = weston_transformed_rect(output_base->width,
675 output_base->height,
676 output_base->transform, *box);
677 s->dest_x = tbox.x1;
678 s->dest_y = tbox.y1;
679 s->dest_w = tbox.x2 - tbox.x1;
680 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681 pixman_region32_fini(&dest_rect);
682
683 pixman_region32_init(&src_rect);
684 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
685 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500686 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400687
688 weston_surface_from_global_fixed(es,
689 wl_fixed_from_int(box->x1),
690 wl_fixed_from_int(box->y1),
691 &sx1, &sy1);
692 weston_surface_from_global_fixed(es,
693 wl_fixed_from_int(box->x2),
694 wl_fixed_from_int(box->y2),
695 &sx2, &sy2);
696
697 if (sx1 < 0)
698 sx1 = 0;
699 if (sy1 < 0)
700 sy1 = 0;
701 if (sx2 > wl_fixed_from_int(es->geometry.width))
702 sx2 = wl_fixed_from_int(es->geometry.width);
703 if (sy2 > wl_fixed_from_int(es->geometry.height))
704 sy2 = wl_fixed_from_int(es->geometry.height);
705
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200706 tbox.x1 = sx1;
707 tbox.y1 = sy1;
708 tbox.x2 = sx2;
709 tbox.y2 = sy2;
710
711 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
712 wl_fixed_from_int(es->geometry.height),
713 es->buffer_transform, tbox);
714
715 s->src_x = tbox.x1 << 8;
716 s->src_y = tbox.y1 << 8;
717 s->src_w = (tbox.x2 - tbox.x1) << 8;
718 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500719 pixman_region32_fini(&src_rect);
720
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400721 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500722}
723
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400724static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400725drm_output_prepare_cursor_surface(struct weston_output *output_base,
726 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500727{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400728 struct drm_compositor *c =
729 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400730 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400731
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200732 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
733 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400734 if (output->cursor_surface)
735 return NULL;
736 if (es->output_mask != (1u << output_base->id))
737 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500738 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400739 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200740 if (es->buffer_ref.buffer == NULL ||
741 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400742 es->geometry.width > 64 || es->geometry.height > 64)
743 return NULL;
744
745 output->cursor_surface = es;
746
747 return &output->cursor_plane;
748}
749
750static void
751drm_output_set_cursor(struct drm_output *output)
752{
753 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400754 struct drm_compositor *c =
755 (struct drm_compositor *) output->base.compositor;
756 EGLint handle, stride;
757 struct gbm_bo *bo;
758 uint32_t buf[64 * 64];
759 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400760 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500761
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400762 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400763 if (es == NULL) {
764 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
765 return;
766 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500767
Pekka Paalanende685b82012-12-04 15:58:12 +0200768 if (es->buffer_ref.buffer &&
769 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400770 pixman_region32_fini(&output->cursor_plane.damage);
771 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400772 output->current_cursor ^= 1;
773 bo = output->cursor_bo[output->current_cursor];
774 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200775 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
776 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400777 for (i = 0; i < es->geometry.height; i++)
778 memcpy(buf + i * 64, s + i * stride,
779 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500780
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400781 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300782 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400783
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400784 handle = gbm_bo_get_handle(bo).s32;
785 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500786 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300787 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500788 c->cursors_are_broken = 1;
789 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400790 }
791
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400792 x = es->geometry.x - output->base.x;
793 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400794 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500795 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400796 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500797 c->cursors_are_broken = 1;
798 }
799
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400800 output->cursor_plane.x = x;
801 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400802 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500803}
804
Jesse Barnes58ef3792012-02-23 09:45:49 -0500805static void
806drm_assign_planes(struct weston_output *output)
807{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400808 struct drm_compositor *c =
809 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200810 struct drm_output *drm_output = (struct drm_output *) output;
811 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400812 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500813 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400814 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200816 /* Reset the opaque region of the planes */
817 pixman_region32_fini(&drm_output->cursor_plane.opaque);
818 pixman_region32_init(&drm_output->cursor_plane.opaque);
819 pixman_region32_fini(&drm_output->fb_plane.opaque);
820 pixman_region32_init(&drm_output->fb_plane.opaque);
821
822 wl_list_for_each (s, &c->sprite_list, link) {
823 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
824 continue;
825
826 pixman_region32_fini(&s->plane.opaque);
827 pixman_region32_init(&s->plane.opaque);
828 }
829
Jesse Barnes58ef3792012-02-23 09:45:49 -0500830 /*
831 * Find a surface for each sprite in the output using some heuristics:
832 * 1) size
833 * 2) frequency of update
834 * 3) opacity (though some hw might support alpha blending)
835 * 4) clipping (this can be fixed with color keys)
836 *
837 * The idea is to save on blitting since this should save power.
838 * If we can get a large video surface on the sprite for example,
839 * the main display surface may not need to update at all, and
840 * the client buffer can be used directly for the sprite surface
841 * as we do for flipping full screen surfaces.
842 */
843 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400844 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400845 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200846 /* test whether this buffer can ever go into a plane:
847 * non-shm, or small enough to be a cursor
848 */
849 if ((es->buffer_ref.buffer &&
850 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
851 (es->geometry.width <= 64 && es->geometry.height <= 64))
852 es->keep_buffer = 1;
853 else
854 es->keep_buffer = 0;
855
Jesse Barnes58ef3792012-02-23 09:45:49 -0500856 pixman_region32_init(&surface_overlap);
857 pixman_region32_intersect(&surface_overlap, &overlap,
858 &es->transform.boundingbox);
859
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400860 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400861 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400862 next_plane = primary;
863 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400864 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400865 if (next_plane == NULL)
866 next_plane = drm_output_prepare_scanout_surface(output, es);
867 if (next_plane == NULL)
868 next_plane = drm_output_prepare_overlay_surface(output, es);
869 if (next_plane == NULL)
870 next_plane = primary;
871 weston_surface_move_to_plane(es, next_plane);
872 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500873 pixman_region32_union(&overlap, &overlap,
874 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400875
Jesse Barnes58ef3792012-02-23 09:45:49 -0500876 pixman_region32_fini(&surface_overlap);
877 }
878 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500879}
880
Matt Roper361d2ad2011-08-29 13:52:23 -0700881static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500882drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700883{
884 struct drm_output *output = (struct drm_output *) output_base;
885 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200886 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700887 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700888
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200889 if (output->backlight)
890 backlight_destroy(output->backlight);
891
Matt Roper361d2ad2011-08-29 13:52:23 -0700892 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400893 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700894
895 /* Restore original CRTC state */
896 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200897 origcrtc->x, origcrtc->y,
898 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700899 drmModeFreeCrtc(origcrtc);
900
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200901 c->crtc_allocator &= ~(1 << output->crtc_id);
902 c->connector_allocator &= ~(1 << output->connector_id);
903
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100904 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100905
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400906 gbm_surface_destroy(output->surface);
907
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400908 weston_plane_release(&output->fb_plane);
909 weston_plane_release(&output->cursor_plane);
910
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500911 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200912 wl_list_remove(&output->base.link);
913
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400914 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700915 free(output);
916}
917
Alex Wub7b8bda2012-04-17 17:20:48 +0800918static struct drm_mode *
919choose_mode (struct drm_output *output, struct weston_mode *target_mode)
920{
921 struct drm_mode *tmp_mode = NULL, *mode;
922
923 if (output->base.current->width == target_mode->width &&
924 output->base.current->height == target_mode->height &&
925 (output->base.current->refresh == target_mode->refresh ||
926 target_mode->refresh == 0))
927 return (struct drm_mode *)output->base.current;
928
929 wl_list_for_each(mode, &output->base.mode_list, base.link) {
930 if (mode->mode_info.hdisplay == target_mode->width &&
931 mode->mode_info.vdisplay == target_mode->height) {
932 if (mode->mode_info.vrefresh == target_mode->refresh ||
933 target_mode->refresh == 0) {
934 return mode;
935 } else if (!tmp_mode)
936 tmp_mode = mode;
937 }
938 }
939
940 return tmp_mode;
941}
942
943static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200944drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
945
946static int
Alex Wub7b8bda2012-04-17 17:20:48 +0800947drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
948{
949 struct drm_output *output;
950 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +0800951 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +0800952
953 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200954 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800955 return -1;
956 }
957
958 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200959 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800960 return -1;
961 }
962
963 ec = (struct drm_compositor *)output_base->compositor;
964 output = (struct drm_output *)output_base;
965 drm_mode = choose_mode (output, mode);
966
967 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200968 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800969 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200970 }
971
972 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +0800973 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800974
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200975 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800976
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200977 output->base.current = &drm_mode->base;
978 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +0800979 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
980
Alex Wub7b8bda2012-04-17 17:20:48 +0800981 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200982 drm_output_release_fb(output, output->current);
983 drm_output_release_fb(output, output->next);
984 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800985
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200986 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800987 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800988
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200989 if (drm_output_init_egl(output, ec) < 0) {
990 weston_log("failed to init output egl state with new mode");
991 return -1;
992 }
993
Alex Wub7b8bda2012-04-17 17:20:48 +0800994 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800995}
996
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400997static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400998on_drm_input(int fd, uint32_t mask, void *data)
999{
1000 drmEventContext evctx;
1001
1002 memset(&evctx, 0, sizeof evctx);
1003 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1004 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001005 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001006 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001007
1008 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001009}
1010
1011static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001012init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001013{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001014 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001015 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001016
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001017 sysnum = udev_device_get_sysnum(device);
1018 if (sysnum)
1019 ec->drm.id = atoi(sysnum);
1020 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001021 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001022 return -1;
1023 }
1024
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001025 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001026 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001027 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001028 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001029 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001030 udev_device_get_devnode(device));
1031 return -1;
1032 }
1033
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001034 weston_log("using %s\n", filename);
1035
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001036 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001037
1038 return 0;
1039}
1040
1041static int
1042init_egl(struct drm_compositor *ec)
1043{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001044 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001045
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001046 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001047 NULL) < 0) {
1048 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001049 return -1;
1050 }
1051
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001052 return 0;
1053}
1054
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001055static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001056drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1057{
1058 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001059 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001060
1061 mode = malloc(sizeof *mode);
1062 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001063 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001064
1065 mode->base.flags = 0;
1066 mode->base.width = info->hdisplay;
1067 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001068
1069 /* Calculate higher precision (mHz) refresh rate */
1070 refresh = (info->clock * 1000000LL / info->htotal +
1071 info->vtotal / 2) / info->vtotal;
1072
1073 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1074 refresh *= 2;
1075 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1076 refresh /= 2;
1077 if (info->vscan > 1)
1078 refresh /= info->vscan;
1079
1080 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001081 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001082
1083 if (info->type & DRM_MODE_TYPE_PREFERRED)
1084 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1085
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001086 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1087
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001088 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001089}
1090
1091static int
1092drm_subpixel_to_wayland(int drm_value)
1093{
1094 switch (drm_value) {
1095 default:
1096 case DRM_MODE_SUBPIXEL_UNKNOWN:
1097 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1098 case DRM_MODE_SUBPIXEL_NONE:
1099 return WL_OUTPUT_SUBPIXEL_NONE;
1100 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1101 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1102 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1103 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1104 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1105 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1106 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1107 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1108 }
1109}
1110
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001111/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001112static uint32_t
1113drm_get_backlight(struct drm_output *output)
1114{
1115 long brightness, max_brightness, norm;
1116
1117 brightness = backlight_get_brightness(output->backlight);
1118 max_brightness = backlight_get_max_brightness(output->backlight);
1119
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001120 /* convert it on a scale of 0 to 255 */
1121 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001122
1123 return (uint32_t) norm;
1124}
1125
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001126/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001127static void
1128drm_set_backlight(struct weston_output *output_base, uint32_t value)
1129{
1130 struct drm_output *output = (struct drm_output *) output_base;
1131 long max_brightness, new_brightness;
1132
1133 if (!output->backlight)
1134 return;
1135
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001136 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001137 return;
1138
1139 max_brightness = backlight_get_max_brightness(output->backlight);
1140
1141 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001142 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001143
1144 backlight_set_brightness(output->backlight, new_brightness);
1145}
1146
1147static drmModePropertyPtr
1148drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1149{
1150 drmModePropertyPtr props;
1151 int i;
1152
1153 for (i = 0; i < connector->count_props; i++) {
1154 props = drmModeGetProperty(fd, connector->props[i]);
1155 if (!props)
1156 continue;
1157
1158 if (!strcmp(props->name, name))
1159 return props;
1160
1161 drmModeFreeProperty(props);
1162 }
1163
1164 return NULL;
1165}
1166
1167static void
1168drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1169{
1170 struct drm_output *output = (struct drm_output *) output_base;
1171 struct weston_compositor *ec = output_base->compositor;
1172 struct drm_compositor *c = (struct drm_compositor *) ec;
1173 drmModeConnectorPtr connector;
1174 drmModePropertyPtr prop;
1175
1176 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1177 if (!connector)
1178 return;
1179
1180 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1181 if (!prop) {
1182 drmModeFreeConnector(connector);
1183 return;
1184 }
1185
1186 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1187 prop->prop_id, level);
1188 drmModeFreeProperty(prop);
1189 drmModeFreeConnector(connector);
1190}
1191
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001192static const char *connector_type_names[] = {
1193 "None",
1194 "VGA",
1195 "DVI",
1196 "DVI",
1197 "DVI",
1198 "Composite",
1199 "TV",
1200 "LVDS",
1201 "CTV",
1202 "DIN",
1203 "DP",
1204 "HDMI",
1205 "HDMI",
1206 "TV",
1207 "eDP",
1208};
1209
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001210static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001211find_crtc_for_connector(struct drm_compositor *ec,
1212 drmModeRes *resources, drmModeConnector *connector)
1213{
1214 drmModeEncoder *encoder;
1215 uint32_t possible_crtcs;
1216 int i, j;
1217
1218 for (j = 0; j < connector->count_encoders; j++) {
1219 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1220 if (encoder == NULL) {
1221 weston_log("Failed to get encoder.\n");
1222 return -1;
1223 }
1224 possible_crtcs = encoder->possible_crtcs;
1225 drmModeFreeEncoder(encoder);
1226
1227 for (i = 0; i < resources->count_crtcs; i++) {
1228 if (possible_crtcs & (1 << i) &&
1229 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1230 return i;
1231 }
1232 }
1233
1234 return -1;
1235}
1236
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001237/* Init output state that depends on gl or gbm */
1238static int
1239drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1240{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001241 int i, flags;
1242
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001243 output->surface = gbm_surface_create(ec->gbm,
1244 output->base.current->width,
1245 output->base.current->height,
1246 GBM_FORMAT_XRGB8888,
1247 GBM_BO_USE_SCANOUT |
1248 GBM_BO_USE_RENDERING);
1249 if (!output->surface) {
1250 weston_log("failed to create gbm surface\n");
1251 return -1;
1252 }
1253
1254 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001255 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001256 gbm_surface_destroy(output->surface);
1257 return -1;
1258 }
1259
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001260 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1261
1262 for (i = 0; i < 2; i++) {
1263 if (output->cursor_bo[i])
1264 continue;
1265
1266 output->cursor_bo[i] =
1267 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1268 flags);
1269 }
1270
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001271 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1272 weston_log("cursor buffers unavailable, using gl cursors\n");
1273 ec->cursors_are_broken = 1;
1274 }
1275
1276 return 0;
1277}
1278
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001279static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001280create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001281 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001282 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001283 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001284{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001285 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001286 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1287 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001288 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001289 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001290 drmModeModeInfo crtc_mode;
1291 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001292 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001293 char name[32];
1294 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001295
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001296 i = find_crtc_for_connector(ec, resources, connector);
1297 if (i < 0) {
1298 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001299 return -1;
1300 }
1301
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001302 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001303 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001304 return -1;
1305
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001306 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001307 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1308 output->base.make = "unknown";
1309 output->base.model = "unknown";
1310 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001311
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001312 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1313 type_name = connector_type_names[connector->connector_type];
1314 else
1315 type_name = "UNKNOWN";
1316 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1317 output->name = strdup(name);
1318
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001319 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001320 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001321 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001322 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001323 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001324
Matt Roper361d2ad2011-08-29 13:52:23 -07001325 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1326
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001327 /* Get the current mode on the crtc that's currently driving
1328 * this connector. */
1329 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001330 memset(&crtc_mode, 0, sizeof crtc_mode);
1331 if (encoder != NULL) {
1332 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1333 drmModeFreeEncoder(encoder);
1334 if (crtc == NULL)
1335 goto err_free;
1336 if (crtc->mode_valid)
1337 crtc_mode = crtc->mode;
1338 drmModeFreeCrtc(crtc);
1339 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001340
David Herrmann0f0d54e2011-12-08 17:05:45 +01001341 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001342 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1343 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001344 goto err_free;
1345 }
1346
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001347 preferred = NULL;
1348 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001349 configured = NULL;
1350
1351 wl_list_for_each(temp, &configured_output_list, link) {
1352 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001353 if (temp->mode)
1354 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001355 temp->name, temp->mode);
1356 o = temp;
1357 break;
1358 }
1359 }
1360
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001361 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001362 weston_log("Disabling output %s\n", o->name);
1363
1364 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1365 0, 0, 0, 0, 0, NULL);
1366 goto err_free;
1367 }
1368
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001369 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001370 if (o && o->config == OUTPUT_CONFIG_MODE &&
1371 o->width == drm_mode->base.width &&
1372 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001373 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001374 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001375 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001376 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001377 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001378 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001379
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001380 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001381 configured = drm_output_add_mode(output, &o->crtc_mode);
1382 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001383 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001384 current = configured;
1385 }
1386
Wang Quanxianacb805a2012-07-30 18:09:46 -04001387 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001388 current = drm_output_add_mode(output, &crtc_mode);
1389 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001390 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001391 }
1392
Scott Moreau8ab5d452012-07-30 19:51:08 -06001393 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1394 configured = current;
1395
Wang Quanxianacb805a2012-07-30 18:09:46 -04001396 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001397 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001398 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001399 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001400 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001401 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001402 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001403 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001404
1405 if (output->base.current == NULL) {
1406 weston_log("no available modes for %s\n", output->name);
1407 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001408 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001409
Wang Quanxianacb805a2012-07-30 18:09:46 -04001410 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1411
John Kåre Alsaker94659272012-11-13 19:10:18 +01001412 weston_output_init(&output->base, &ec->base, x, y,
1413 connector->mmWidth, connector->mmHeight,
1414 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1415
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001416 if (drm_output_init_egl(output, ec) < 0) {
1417 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001418 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001419 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001420
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001421 output->backlight = backlight_init(drm_device,
1422 connector->connector_type);
1423 if (output->backlight) {
1424 output->base.set_backlight = drm_set_backlight;
1425 output->base.backlight_current = drm_get_backlight(output);
1426 }
1427
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001428 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1429
Alex Wubd3354b2012-04-17 17:20:49 +08001430 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001431 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001432 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001433 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001434 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001435 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001436
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001437 weston_plane_init(&output->cursor_plane, 0, 0);
1438 weston_plane_init(&output->fb_plane, 0, 0);
1439
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001440 weston_log("Output %s, (connector %d, crtc %d)\n",
1441 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001442 wl_list_for_each(m, &output->base.mode_list, link)
1443 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1444 m->width, m->height, m->refresh / 1000.0,
1445 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1446 ", preferred" : "",
1447 m->flags & WL_OUTPUT_MODE_CURRENT ?
1448 ", current" : "",
1449 connector->count_modes == 0 ?
1450 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001451
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001452 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001453
John Kåre Alsaker94659272012-11-13 19:10:18 +01001454err_output:
1455 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001456err_free:
1457 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1458 base.link) {
1459 wl_list_remove(&drm_mode->base.link);
1460 free(drm_mode);
1461 }
1462
1463 drmModeFreeCrtc(output->original_crtc);
1464 ec->crtc_allocator &= ~(1 << output->crtc_id);
1465 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001466 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001467 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001468
David Herrmann0f0d54e2011-12-08 17:05:45 +01001469 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001470}
1471
Jesse Barnes58ef3792012-02-23 09:45:49 -05001472static void
1473create_sprites(struct drm_compositor *ec)
1474{
1475 struct drm_sprite *sprite;
1476 drmModePlaneRes *plane_res;
1477 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001478 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001479
1480 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1481 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001482 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001483 strerror(errno));
1484 return;
1485 }
1486
1487 for (i = 0; i < plane_res->count_planes; i++) {
1488 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1489 if (!plane)
1490 continue;
1491
1492 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1493 plane->count_formats));
1494 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001495 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001496 __func__);
1497 free(plane);
1498 continue;
1499 }
1500
1501 memset(sprite, 0, sizeof *sprite);
1502
1503 sprite->possible_crtcs = plane->possible_crtcs;
1504 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001505 sprite->current = NULL;
1506 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001507 sprite->compositor = ec;
1508 sprite->count_formats = plane->count_formats;
1509 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001510 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001511 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001512 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001513
1514 wl_list_insert(&ec->sprite_list, &sprite->link);
1515 }
1516
1517 free(plane_res->planes);
1518 free(plane_res);
1519}
1520
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001521static void
1522destroy_sprites(struct drm_compositor *compositor)
1523{
1524 struct drm_sprite *sprite, *next;
1525 struct drm_output *output;
1526
1527 output = container_of(compositor->base.output_list.next,
1528 struct drm_output, base.link);
1529
1530 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1531 drmModeSetPlane(compositor->drm.fd,
1532 sprite->plane_id,
1533 output->crtc_id, 0, 0,
1534 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001535 drm_output_release_fb(output, sprite->current);
1536 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001537 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001538 free(sprite);
1539 }
1540}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001541
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001542static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001543create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001544 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001545{
1546 drmModeConnector *connector;
1547 drmModeRes *resources;
1548 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001549 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001550
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001551 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001552 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001553 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001554 return -1;
1555 }
1556
Jesse Barnes58ef3792012-02-23 09:45:49 -05001557 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001558 if (!ec->crtcs) {
1559 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001560 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001561 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001562
Rob Clark4339add2012-08-09 14:18:28 -05001563 ec->min_width = resources->min_width;
1564 ec->max_width = resources->max_width;
1565 ec->min_height = resources->min_height;
1566 ec->max_height = resources->max_height;
1567
Jesse Barnes58ef3792012-02-23 09:45:49 -05001568 ec->num_crtcs = resources->count_crtcs;
1569 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1570
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001571 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001572 connector = drmModeGetConnector(ec->drm.fd,
1573 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001574 if (connector == NULL)
1575 continue;
1576
1577 if (connector->connection == DRM_MODE_CONNECTED &&
1578 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001579 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001580 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001581 connector, x, y,
1582 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001583 drmModeFreeConnector(connector);
1584 continue;
1585 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001586
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001587 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001588 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001589 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001590 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001591
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001592 drmModeFreeConnector(connector);
1593 }
1594
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001595 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001596 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001597 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001598 return -1;
1599 }
1600
1601 drmModeFreeResources(resources);
1602
1603 return 0;
1604}
1605
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001606static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001607update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001608{
1609 drmModeConnector *connector;
1610 drmModeRes *resources;
1611 struct drm_output *output, *next;
1612 int x = 0, y = 0;
1613 int x_offset = 0, y_offset = 0;
1614 uint32_t connected = 0, disconnects = 0;
1615 int i;
1616
1617 resources = drmModeGetResources(ec->drm.fd);
1618 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001619 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001620 return;
1621 }
1622
1623 /* collect new connects */
1624 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001625 int connector_id = resources->connectors[i];
1626
1627 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001628 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001629 continue;
1630
David Herrmann7551cff2011-12-08 17:05:43 +01001631 if (connector->connection != DRM_MODE_CONNECTED) {
1632 drmModeFreeConnector(connector);
1633 continue;
1634 }
1635
Benjamin Franzke117483d2011-08-30 11:38:26 +02001636 connected |= (1 << connector_id);
1637
1638 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001639 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001640 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001641 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001642
1643 /* XXX: not yet needed, we die with 0 outputs */
1644 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001645 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001646 else
1647 x = 0;
1648 y = 0;
1649 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001650 connector, x, y,
1651 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001652 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001653
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001654 }
1655 drmModeFreeConnector(connector);
1656 }
1657 drmModeFreeResources(resources);
1658
1659 disconnects = ec->connector_allocator & ~connected;
1660 if (disconnects) {
1661 wl_list_for_each_safe(output, next, &ec->base.output_list,
1662 base.link) {
1663 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001664 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001665 output->base.x - x_offset,
1666 output->base.y - y_offset);
1667 }
1668
1669 if (disconnects & (1 << output->connector_id)) {
1670 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001671 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001672 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001673 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001674 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001675 }
1676 }
1677 }
1678
1679 /* FIXME: handle zero outputs, without terminating */
1680 if (ec->connector_allocator == 0)
1681 wl_display_terminate(ec->base.wl_display);
1682}
1683
1684static int
David Herrmannd7488c22012-03-11 20:05:21 +01001685udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001686{
David Herrmannd7488c22012-03-11 20:05:21 +01001687 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001688 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001689
1690 sysnum = udev_device_get_sysnum(device);
1691 if (!sysnum || atoi(sysnum) != ec->drm.id)
1692 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001693
David Herrmann6ac52db2012-03-11 20:05:22 +01001694 val = udev_device_get_property_value(device, "HOTPLUG");
1695 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001696 return 0;
1697
David Herrmann6ac52db2012-03-11 20:05:22 +01001698 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001699}
1700
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001701static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001702udev_drm_event(int fd, uint32_t mask, void *data)
1703{
1704 struct drm_compositor *ec = data;
1705 struct udev_device *event;
1706
1707 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001708
David Herrmannd7488c22012-03-11 20:05:21 +01001709 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001710 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001711
1712 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001713
1714 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001715}
1716
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001717static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001718drm_restore(struct weston_compositor *ec)
1719{
1720 struct drm_compositor *d = (struct drm_compositor *) ec;
1721
1722 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1723 weston_log("failed to drop master: %m\n");
1724 tty_reset(d->tty);
1725}
1726
Pekka Paalanen33156972012-08-03 13:30:30 -04001727static const char default_seat[] = "seat0";
1728
1729static void
1730device_added(struct udev_device *udev_device, struct drm_seat *master)
1731{
1732 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001733 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001734 const char *devnode;
1735 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001736 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001737 int fd;
1738
1739 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1740 if (!device_seat)
1741 device_seat = default_seat;
1742
1743 if (strcmp(device_seat, master->seat_id))
1744 return;
1745
1746 c = master->base.compositor;
1747 devnode = udev_device_get_devnode(udev_device);
1748
1749 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001750 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001751 * read. mtdev_get() also expects this. */
1752 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1753 if (fd < 0) {
1754 weston_log("opening input device '%s' failed.\n", devnode);
1755 return;
1756 }
1757
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001758 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001759 if (!device) {
1760 close(fd);
1761 weston_log("not using input device '%s'.\n", devnode);
1762 return;
1763 }
1764
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001765 calibration_values =
1766 udev_device_get_property_value(udev_device,
1767 "WL_CALIBRATION");
1768
1769 if (calibration_values && sscanf(calibration_values,
1770 "%f %f %f %f %f %f",
1771 &device->abs.calibration[0],
1772 &device->abs.calibration[1],
1773 &device->abs.calibration[2],
1774 &device->abs.calibration[3],
1775 &device->abs.calibration[4],
1776 &device->abs.calibration[5]) == 6) {
1777 device->abs.apply_calibration = 1;
1778 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1779 device->abs.calibration[0],
1780 device->abs.calibration[1],
1781 device->abs.calibration[2],
1782 device->abs.calibration[3],
1783 device->abs.calibration[4],
1784 device->abs.calibration[5]);
1785 }
1786
Pekka Paalanen33156972012-08-03 13:30:30 -04001787 wl_list_insert(master->devices_list.prev, &device->link);
1788}
1789
1790static void
1791evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1792{
1793 struct drm_seat *seat = (struct drm_seat *) seat_base;
1794 struct udev_enumerate *e;
1795 struct udev_list_entry *entry;
1796 struct udev_device *device;
1797 const char *path, *sysname;
1798
1799 e = udev_enumerate_new(udev);
1800 udev_enumerate_add_match_subsystem(e, "input");
1801 udev_enumerate_scan_devices(e);
1802 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1803 path = udev_list_entry_get_name(entry);
1804 device = udev_device_new_from_syspath(udev, path);
1805
1806 sysname = udev_device_get_sysname(device);
1807 if (strncmp("event", sysname, 5) != 0) {
1808 udev_device_unref(device);
1809 continue;
1810 }
1811
1812 device_added(device, seat);
1813
1814 udev_device_unref(device);
1815 }
1816 udev_enumerate_unref(e);
1817
1818 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1819
1820 if (wl_list_empty(&seat->devices_list)) {
1821 weston_log(
1822 "warning: no input devices on entering Weston. "
1823 "Possible causes:\n"
1824 "\t- no permissions to read /dev/input/event*\n"
1825 "\t- seats misconfigured "
1826 "(Weston backend option 'seat', "
1827 "udev device property ID_SEAT)\n");
1828 }
1829}
1830
1831static int
1832evdev_udev_handler(int fd, uint32_t mask, void *data)
1833{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001834 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001835 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001836 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001837 const char *action;
1838 const char *devnode;
1839
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001840 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001841 if (!udev_device)
1842 return 1;
1843
1844 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001845 if (!action)
1846 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001847
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001848 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1849 goto out;
1850
1851 if (!strcmp(action, "add")) {
1852 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001853 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001854 else if (!strcmp(action, "remove")) {
1855 devnode = udev_device_get_devnode(udev_device);
1856 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1857 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001858 weston_log("input device %s, %s removed\n",
1859 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001860 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001861 break;
1862 }
1863 }
1864
1865out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001866 udev_device_unref(udev_device);
1867
1868 return 0;
1869}
1870
1871static int
1872evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1873{
1874 struct drm_seat *master = (struct drm_seat *) seat_base;
1875 struct wl_event_loop *loop;
1876 struct weston_compositor *c = master->base.compositor;
1877 int fd;
1878
1879 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1880 if (!master->udev_monitor) {
1881 weston_log("udev: failed to create the udev monitor\n");
1882 return 0;
1883 }
1884
1885 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1886 "input", NULL);
1887
1888 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1889 weston_log("udev: failed to bind the udev monitor\n");
1890 udev_monitor_unref(master->udev_monitor);
1891 return 0;
1892 }
1893
1894 loop = wl_display_get_event_loop(c->wl_display);
1895 fd = udev_monitor_get_fd(master->udev_monitor);
1896 master->udev_monitor_source =
1897 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1898 evdev_udev_handler, master);
1899 if (!master->udev_monitor_source) {
1900 udev_monitor_unref(master->udev_monitor);
1901 return 0;
1902 }
1903
1904 return 1;
1905}
1906
1907static void
1908evdev_disable_udev_monitor(struct weston_seat *seat_base)
1909{
1910 struct drm_seat *seat = (struct drm_seat *) seat_base;
1911
1912 if (!seat->udev_monitor)
1913 return;
1914
1915 udev_monitor_unref(seat->udev_monitor);
1916 seat->udev_monitor = NULL;
1917 wl_event_source_remove(seat->udev_monitor_source);
1918 seat->udev_monitor_source = NULL;
1919}
1920
1921static void
1922drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1923{
1924 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001925 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001926
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001927 wl_list_for_each(device, &seat->devices_list, link)
1928 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001929}
1930
1931static void
1932evdev_input_create(struct weston_compositor *c, struct udev *udev,
1933 const char *seat_id)
1934{
1935 struct drm_seat *seat;
1936
1937 seat = malloc(sizeof *seat);
1938 if (seat == NULL)
1939 return;
1940
1941 memset(seat, 0, sizeof *seat);
1942 weston_seat_init(&seat->base, c);
1943 seat->base.led_update = drm_led_update;
1944
1945 wl_list_init(&seat->devices_list);
1946 seat->seat_id = strdup(seat_id);
1947 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1948 free(seat->seat_id);
1949 free(seat);
1950 return;
1951 }
1952
1953 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001954}
1955
1956static void
1957evdev_remove_devices(struct weston_seat *seat_base)
1958{
1959 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001960 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001961
1962 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001963 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001964
Pekka Paalanend8583512012-08-03 14:39:11 +03001965 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001966 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001967}
1968
1969static void
1970evdev_input_destroy(struct weston_seat *seat_base)
1971{
1972 struct drm_seat *seat = (struct drm_seat *) seat_base;
1973
1974 evdev_remove_devices(seat_base);
1975 evdev_disable_udev_monitor(&seat->base);
1976
1977 weston_seat_release(seat_base);
1978 free(seat->seat_id);
1979 free(seat);
1980}
1981
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001982static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001983drm_free_configured_output(struct drm_configured_output *output)
1984{
1985 free(output->name);
1986 free(output->mode);
1987 free(output);
1988}
1989
1990static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001991drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001992{
1993 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001994 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001995 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001996
Daniel Stone37816df2012-05-16 18:45:18 +01001997 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1998 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001999 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002000 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002001
2002 wl_event_source_remove(d->udev_drm_source);
2003 wl_event_source_remove(d->drm_source);
2004
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002005 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002006
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002007 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002008
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002009 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002010 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002011 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002012 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002013 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002014
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002015 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002016}
2017
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002018static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002019drm_compositor_set_modes(struct drm_compositor *compositor)
2020{
2021 struct drm_output *output;
2022 struct drm_mode *drm_mode;
2023 int ret;
2024
2025 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2026 drm_mode = (struct drm_mode *) output->base.current;
2027 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002028 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002029 &output->connector_id, 1,
2030 &drm_mode->mode_info);
2031 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002032 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002033 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002034 drm_mode->base.width, drm_mode->base.height,
2035 output->base.x, output->base.y);
2036 }
2037 }
2038}
2039
2040static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002041vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002042{
2043 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002044 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002045 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002046 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002047
2048 switch (event) {
2049 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002050 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002051 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002052 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002053 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002054 wl_display_terminate(compositor->wl_display);
2055 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002056 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002057 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002058 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002059 wl_list_for_each(seat, &compositor->seat_list, link) {
2060 evdev_add_devices(ec->udev, seat);
2061 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002062 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002063 break;
2064 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002065 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002066 wl_list_for_each(seat, &compositor->seat_list, link) {
2067 evdev_disable_udev_monitor(seat);
2068 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002069 }
2070
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002071 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002072 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002073 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002074
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002075 /* If we have a repaint scheduled (either from a
2076 * pending pageflip or the idle handler), make sure we
2077 * cancel that so we don't try to pageflip when we're
2078 * vt switched away. The SLEEPING state will prevent
2079 * further attemps at repainting. When we switch
2080 * back, we schedule a repaint, which will process
2081 * pending frame callbacks. */
2082
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002083 wl_list_for_each(output, &ec->base.output_list, base.link) {
2084 output->base.repaint_needed = 0;
2085 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002086 }
2087
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002088 output = container_of(ec->base.output_list.next,
2089 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002090
2091 wl_list_for_each(sprite, &ec->sprite_list, link)
2092 drmModeSetPlane(ec->drm.fd,
2093 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002094 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002095 0, 0, 0, 0, 0, 0, 0, 0);
2096
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002097 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002098 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002099
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002100 break;
2101 };
2102}
2103
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002104static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002105switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002106{
2107 struct drm_compositor *ec = data;
2108
Daniel Stone325fc2d2012-05-30 16:31:58 +01002109 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002110}
2111
David Herrmann0af066f2012-10-29 19:21:16 +01002112/*
2113 * Find primary GPU
2114 * Some systems may have multiple DRM devices attached to a single seat. This
2115 * function loops over all devices and tries to find a PCI device with the
2116 * boot_vga sysfs attribute set to 1.
2117 * If no such device is found, the first DRM device reported by udev is used.
2118 */
2119static struct udev_device*
2120find_primary_gpu(struct drm_compositor *ec, const char *seat)
2121{
2122 struct udev_enumerate *e;
2123 struct udev_list_entry *entry;
2124 const char *path, *device_seat, *id;
2125 struct udev_device *device, *drm_device, *pci;
2126
2127 e = udev_enumerate_new(ec->udev);
2128 udev_enumerate_add_match_subsystem(e, "drm");
2129 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2130
2131 udev_enumerate_scan_devices(e);
2132 drm_device = NULL;
2133 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2134 path = udev_list_entry_get_name(entry);
2135 device = udev_device_new_from_syspath(ec->udev, path);
2136 if (!device)
2137 continue;
2138 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2139 if (!device_seat)
2140 device_seat = default_seat;
2141 if (strcmp(device_seat, seat)) {
2142 udev_device_unref(device);
2143 continue;
2144 }
2145
2146 pci = udev_device_get_parent_with_subsystem_devtype(device,
2147 "pci", NULL);
2148 if (pci) {
2149 id = udev_device_get_sysattr_value(pci, "boot_vga");
2150 if (id && !strcmp(id, "1")) {
2151 if (drm_device)
2152 udev_device_unref(drm_device);
2153 drm_device = device;
2154 break;
2155 }
2156 }
2157
2158 if (!drm_device)
2159 drm_device = device;
2160 else
2161 udev_device_unref(device);
2162 }
2163
2164 udev_enumerate_unref(e);
2165 return drm_device;
2166}
2167
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002168static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002169planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002170{
2171 struct drm_compositor *c = data;
2172
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002173 switch (key) {
2174 case KEY_C:
2175 c->cursors_are_broken ^= 1;
2176 break;
2177 case KEY_V:
2178 c->sprites_are_broken ^= 1;
2179 break;
2180 case KEY_O:
2181 c->sprites_hidden ^= 1;
2182 break;
2183 default:
2184 break;
2185 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002186}
2187
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002188static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002189drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002190 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002191 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002192{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002193 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002194 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002195 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002196 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002197 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002198 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002199
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002200 weston_log("initializing drm backend\n");
2201
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002202 ec = malloc(sizeof *ec);
2203 if (ec == NULL)
2204 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002205 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002206
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002207 /* KMS support for sprites is not complete yet, so disable the
2208 * functionality for now. */
2209 ec->sprites_are_broken = 1;
2210
Daniel Stone725c2c32012-06-22 14:04:36 +01002211 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002212 config_file) < 0) {
2213 weston_log("weston_compositor_init failed\n");
2214 goto err_base;
2215 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002216
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002217 ec->udev = udev_new();
2218 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002219 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002220 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002221 }
2222
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002223 ec->base.wl_display = display;
2224 ec->tty = tty_create(&ec->base, vt_func, tty);
2225 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002226 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002227 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002228 }
2229
David Herrmann0af066f2012-10-29 19:21:16 +01002230 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002231 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002232 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002233 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002234 }
David Herrmann0af066f2012-10-29 19:21:16 +01002235 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002236
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002237 if (init_drm(ec, drm_device) < 0) {
2238 weston_log("failed to initialize kms\n");
2239 goto err_udev_dev;
2240 }
2241
2242 if (init_egl(ec) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002243 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002244 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002245 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002246
2247 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002248 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002249
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002250 ec->base.focus = 1;
2251
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002252 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002253
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002254 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002255 weston_compositor_add_key_binding(&ec->base, key,
2256 MODIFIER_CTRL | MODIFIER_ALT,
2257 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002258
Jesse Barnes58ef3792012-02-23 09:45:49 -05002259 wl_list_init(&ec->sprite_list);
2260 create_sprites(ec);
2261
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002262 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002263 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002264 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002265 }
2266
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002267 path = NULL;
2268
Tiago Vignattice03ec32011-12-19 01:14:03 +02002269 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002270
2271 loop = wl_display_get_event_loop(ec->base.wl_display);
2272 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002273 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002274 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002275
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002276 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2277 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002278 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002279 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002280 }
2281 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2282 "drm", NULL);
2283 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002284 wl_event_loop_add_fd(loop,
2285 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002286 WL_EVENT_READABLE, udev_drm_event, ec);
2287
2288 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002289 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002290 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002291 }
2292
Daniel Stonea96b93c2012-06-22 14:04:37 +01002293 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002294
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002295 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002296 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002297 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002298 planes_binding, ec);
2299 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2300 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002301
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002302 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002303
2304err_udev_monitor:
2305 wl_event_source_remove(ec->udev_drm_source);
2306 udev_monitor_unref(ec->udev_monitor);
2307err_drm_source:
2308 wl_event_source_remove(ec->drm_source);
2309 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2310 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002311err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002312 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002313 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002314 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002315err_udev_dev:
2316 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002317err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002318 tty_destroy(ec->tty);
2319err_udev:
2320 udev_unref(ec->udev);
2321err_compositor:
2322 weston_compositor_shutdown(&ec->base);
2323err_base:
2324 free(ec);
2325 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002326}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002327
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002328static int
2329set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2330{
2331 mode->flags = 0;
2332
2333 if (strcmp(hsync, "+hsync") == 0)
2334 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2335 else if (strcmp(hsync, "-hsync") == 0)
2336 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2337 else
2338 return -1;
2339
2340 if (strcmp(vsync, "+vsync") == 0)
2341 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2342 else if (strcmp(vsync, "-vsync") == 0)
2343 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2344 else
2345 return -1;
2346
2347 return 0;
2348}
2349
2350static int
2351check_for_modeline(struct drm_configured_output *output)
2352{
2353 drmModeModeInfo mode;
2354 char hsync[16];
2355 char vsync[16];
2356 char mode_name[16];
2357 float fclock;
2358
2359 mode.type = DRM_MODE_TYPE_USERDEF;
2360 mode.hskew = 0;
2361 mode.vscan = 0;
2362 mode.vrefresh = 0;
2363
2364 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2365 &fclock, &mode.hdisplay,
2366 &mode.hsync_start,
2367 &mode.hsync_end, &mode.htotal,
2368 &mode.vdisplay,
2369 &mode.vsync_start,
2370 &mode.vsync_end, &mode.vtotal,
2371 hsync, vsync) == 11) {
2372 if (set_sync_flags(&mode, hsync, vsync))
2373 return -1;
2374
2375 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2376 strcpy(mode.name, mode_name);
2377
2378 mode.clock = fclock * 1000;
2379 } else
2380 return -1;
2381
2382 output->crtc_mode = mode;
2383
2384 return 0;
2385}
2386
Scott Moreau8ab5d452012-07-30 19:51:08 -06002387static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002388drm_output_set_transform(struct drm_configured_output *output)
2389{
2390 if (!output_transform) {
2391 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2392 return;
2393 }
2394
2395 if (!strcmp(output_transform, "normal"))
2396 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2397 else if (!strcmp(output_transform, "90"))
2398 output->transform = WL_OUTPUT_TRANSFORM_90;
2399 else if (!strcmp(output_transform, "180"))
2400 output->transform = WL_OUTPUT_TRANSFORM_180;
2401 else if (!strcmp(output_transform, "270"))
2402 output->transform = WL_OUTPUT_TRANSFORM_270;
2403 else if (!strcmp(output_transform, "flipped"))
2404 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2405 else if (!strcmp(output_transform, "flipped-90"))
2406 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2407 else if (!strcmp(output_transform, "flipped-180"))
2408 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2409 else if (!strcmp(output_transform, "flipped-270"))
2410 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2411 else {
2412 weston_log("Invalid transform \"%s\" for output %s\n",
2413 output_transform, output_name);
2414 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2415 }
2416
2417 free(output_transform);
2418 output_transform = NULL;
2419}
2420
2421static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002422output_section_done(void *data)
2423{
2424 struct drm_configured_output *output;
2425
2426 output = malloc(sizeof *output);
2427
Scott Moreau1bad5db2012-08-18 01:04:05 -06002428 if (!output || !output_name || (output_name[0] == 'X') ||
2429 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002430 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002431 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002432 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002433 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002434 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002435 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002436 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002437 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002438 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002439
2440 output->config = OUTPUT_CONFIG_INVALID;
2441 output->name = output_name;
2442 output->mode = output_mode;
2443
Scott Moreau1bad5db2012-08-18 01:04:05 -06002444 if (output_mode) {
2445 if (strcmp(output_mode, "off") == 0)
2446 output->config = OUTPUT_CONFIG_OFF;
2447 else if (strcmp(output_mode, "preferred") == 0)
2448 output->config = OUTPUT_CONFIG_PREFERRED;
2449 else if (strcmp(output_mode, "current") == 0)
2450 output->config = OUTPUT_CONFIG_CURRENT;
2451 else if (sscanf(output_mode, "%dx%d",
2452 &output->width, &output->height) == 2)
2453 output->config = OUTPUT_CONFIG_MODE;
2454 else if (check_for_modeline(output) == 0)
2455 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002456
Scott Moreau1bad5db2012-08-18 01:04:05 -06002457 if (output->config == OUTPUT_CONFIG_INVALID)
2458 weston_log("Invalid mode \"%s\" for output %s\n",
2459 output_mode, output_name);
2460 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002461 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002462
2463 drm_output_set_transform(output);
2464
2465 wl_list_insert(&configured_output_list, &output->link);
2466
2467 if (output_transform)
2468 free(output_transform);
2469 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002470}
2471
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002472WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002473backend_init(struct wl_display *display, int argc, char *argv[],
2474 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002475{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002476 int connector = 0, tty = 0;
2477 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002478
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002479 const struct weston_option drm_options[] = {
2480 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2481 { WESTON_OPTION_STRING, "seat", 0, &seat },
2482 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002483 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002484 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002485
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002486 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002487
Scott Moreau8ab5d452012-07-30 19:51:08 -06002488 wl_list_init(&configured_output_list);
2489
2490 const struct config_key drm_config_keys[] = {
2491 { "name", CONFIG_KEY_STRING, &output_name },
2492 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002493 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002494 };
2495
2496 const struct config_section config_section[] = {
2497 { "output", drm_config_keys,
2498 ARRAY_LENGTH(drm_config_keys), output_section_done },
2499 };
2500
2501 parse_config_file(config_file, config_section,
2502 ARRAY_LENGTH(config_section), NULL);
2503
Daniel Stonec1be8e52012-06-01 11:14:02 -04002504 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2505 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002506}