blob: 449106efa35871282abfbdb3ec3deeed95654344 [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
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500290static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200291drm_output_check_scanout_format(struct drm_output *output,
292 struct weston_surface *es, struct gbm_bo *bo)
293{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200294 uint32_t format;
295 pixman_region32_t r;
296
297 format = gbm_bo_get_format(bo);
298
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500299 switch (format) {
300 case GBM_FORMAT_XRGB8888:
301 return format;
302 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200303 /* We can only scanout an ARGB buffer if the surface's
304 * opaque region covers the whole output */
305 pixman_region32_init(&r);
306 pixman_region32_subtract(&r, &output->base.region,
307 &es->opaque);
308
309 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500310 format = GBM_FORMAT_XRGB8888;
311 else
312 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200313
314 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200315
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500316 return format;
317 default:
318 return 0;
319 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200320}
321
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400322static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400323drm_output_prepare_scanout_surface(struct weston_output *_output,
324 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500325{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400326 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500327 struct drm_compositor *c =
328 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200329 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300330 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500331 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500332
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500333 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200334 es->geometry.y != output->base.y ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200335 buffer == NULL ||
336 buffer->width != output->base.current->width ||
337 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200338 output->base.transform != es->buffer_transform ||
339 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400340 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500341
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400342 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200343 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500344
Rob Bradford9b101872012-09-14 23:25:41 +0100345 /* Unable to use the buffer for scanout */
346 if (!bo)
347 return NULL;
348
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500349 format = drm_output_check_scanout_format(output, es, bo);
350 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300351 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400352 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300353 }
354
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500355 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356 if (!output->next) {
357 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400358 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500360
Pekka Paalanende685b82012-12-04 15:58:12 +0200361 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500362
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400363 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500364}
365
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500366static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400367drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400368{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200369 struct drm_compositor *c =
370 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300371 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400372
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200373 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400374
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200375 pixman_region32_subtract(&c->base.primary_plane.damage,
376 &c->base.primary_plane.damage, damage);
377
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300378 bo = gbm_surface_lock_front_buffer(output->surface);
379 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200380 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400381 return;
382 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300383
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500384 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300385 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200386 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300387 gbm_surface_release_buffer(output->surface, bo);
388 return;
389 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400390}
391
392static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500393drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400394 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100395{
396 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500397 struct drm_compositor *compositor =
398 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500399 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400400 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500401 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100402
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300403 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400404 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300405 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400406 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100407
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400408 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300409 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400410 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300411 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400412 &output->connector_id, 1,
413 &mode->mode_info);
414 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200415 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400416 return;
417 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200418 }
419
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500420 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300421 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500422 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200423 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500424 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500425 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100426
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300427 output->page_flip_pending = 1;
428
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400429 drm_output_set_cursor(output);
430
Jesse Barnes58ef3792012-02-23 09:45:49 -0500431 /*
432 * Now, update all the sprite surfaces
433 */
434 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200435 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500436 drmVBlank vbl = {
437 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
438 .request.sequence = 1,
439 };
440
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200441 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200442 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500443 continue;
444
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200445 if (s->next && !compositor->sprites_hidden)
446 fb_id = s->next->fb_id;
447
Jesse Barnes58ef3792012-02-23 09:45:49 -0500448 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200449 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500450 s->dest_x, s->dest_y,
451 s->dest_w, s->dest_h,
452 s->src_x, s->src_y,
453 s->src_w, s->src_h);
454 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200455 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500456 ret, strerror(errno));
457
Rob Clark5ca1a472012-08-08 20:27:37 -0500458 if (output->pipe > 0)
459 vbl.request.type |= DRM_VBLANK_SECONDARY;
460
Jesse Barnes58ef3792012-02-23 09:45:49 -0500461 /*
462 * Queue a vblank signal so we know when the surface
463 * becomes active on the display or has been replaced.
464 */
465 vbl.request.signal = (unsigned long)s;
466 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
467 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200468 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500469 ret, strerror(errno));
470 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300471
472 s->output = output;
473 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500474 }
475
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500476 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400477}
478
479static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500480vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
481 void *data)
482{
483 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300484 struct drm_output *output = s->output;
485 uint32_t msecs;
486
487 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500488
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200489 if (s->current)
490 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500491
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200492 s->current = s->next;
493 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300494
495 if (!output->page_flip_pending) {
496 msecs = sec * 1000 + usec / 1000;
497 weston_output_finish_frame(&output->base, msecs);
498 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500499}
500
501static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400502page_flip_handler(int fd, unsigned int frame,
503 unsigned int sec, unsigned int usec, void *data)
504{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200505 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400506 uint32_t msecs;
507
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300508 output->page_flip_pending = 0;
509
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510 if (output->current) {
511 if (output->current->is_client_buffer)
512 gbm_bo_destroy(output->current->bo);
513 else
514 gbm_surface_release_buffer(output->surface,
515 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200516 }
517
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300518 output->current = output->next;
519 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400520
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300521 if (!output->vblank_pending) {
522 msecs = sec * 1000 + usec / 1000;
523 weston_output_finish_frame(&output->base, msecs);
524 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200525}
526
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500527static uint32_t
528drm_output_check_sprite_format(struct drm_sprite *s,
529 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500530{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500531 uint32_t i, format;
532
533 format = gbm_bo_get_format(bo);
534
535 if (format == GBM_FORMAT_ARGB8888) {
536 pixman_region32_t r;
537
538 pixman_region32_init(&r);
539 pixman_region32_subtract(&r, &es->transform.boundingbox,
540 &es->transform.opaque);
541
542 if (!pixman_region32_not_empty(&r))
543 format = GBM_FORMAT_XRGB8888;
544
545 pixman_region32_fini(&r);
546 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500547
548 for (i = 0; i < s->count_formats; i++)
549 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500550 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500551
552 return 0;
553}
554
555static int
556drm_surface_transform_supported(struct weston_surface *es)
557{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400558 struct weston_matrix *matrix = &es->transform.matrix;
559 int i;
560
561 if (!es->transform.enabled)
562 return 1;
563
564 for (i = 0; i < 16; i++) {
565 switch (i) {
566 case 10:
567 case 15:
568 if (matrix->d[i] != 1.0)
569 return 0;
570 break;
571 case 0:
572 case 5:
573 case 12:
574 case 13:
575 break;
576 default:
577 if (matrix->d[i] != 0.0)
578 return 0;
579 break;
580 }
581 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500582
583 return 1;
584}
585
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400586static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500587drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400588 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589{
590 struct weston_compositor *ec = output_base->compositor;
591 struct drm_compositor *c =(struct drm_compositor *) ec;
592 struct drm_sprite *s;
593 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500594 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500595 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200596 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500597 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400598 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200600 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200601 return NULL;
602
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500603 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400604 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500605
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300606 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400607 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300608
Pekka Paalanende685b82012-12-04 15:58:12 +0200609 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400610 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200612 if (es->alpha != 1.0f)
613 return NULL;
614
Pekka Paalanende685b82012-12-04 15:58:12 +0200615 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500616 return NULL;
617
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400619 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 wl_list_for_each(s, &c->sprite_list, link) {
622 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
623 continue;
624
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200625 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 found = 1;
627 break;
628 }
629 }
630
631 /* No sprites available */
632 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400633 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400635 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200636 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400637 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400638 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400639
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500640 format = drm_output_check_sprite_format(s, es, bo);
641 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400643 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500644 }
645
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200646 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200647 if (!s->next) {
648 gbm_bo_destroy(bo);
649 return NULL;
650 }
651
Pekka Paalanende685b82012-12-04 15:58:12 +0200652 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400654 box = pixman_region32_extents(&es->transform.boundingbox);
655 s->plane.x = box->x1;
656 s->plane.y = box->y1;
657
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658 /*
659 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200660 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500661 * for us already).
662 */
663 pixman_region32_init(&dest_rect);
664 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
665 &output_base->region);
666 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
667 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200668 tbox = weston_transformed_rect(output_base->width,
669 output_base->height,
670 output_base->transform, *box);
671 s->dest_x = tbox.x1;
672 s->dest_y = tbox.y1;
673 s->dest_w = tbox.x2 - tbox.x1;
674 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500675 pixman_region32_fini(&dest_rect);
676
677 pixman_region32_init(&src_rect);
678 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
679 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500680 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400681
682 weston_surface_from_global_fixed(es,
683 wl_fixed_from_int(box->x1),
684 wl_fixed_from_int(box->y1),
685 &sx1, &sy1);
686 weston_surface_from_global_fixed(es,
687 wl_fixed_from_int(box->x2),
688 wl_fixed_from_int(box->y2),
689 &sx2, &sy2);
690
691 if (sx1 < 0)
692 sx1 = 0;
693 if (sy1 < 0)
694 sy1 = 0;
695 if (sx2 > wl_fixed_from_int(es->geometry.width))
696 sx2 = wl_fixed_from_int(es->geometry.width);
697 if (sy2 > wl_fixed_from_int(es->geometry.height))
698 sy2 = wl_fixed_from_int(es->geometry.height);
699
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200700 tbox.x1 = sx1;
701 tbox.y1 = sy1;
702 tbox.x2 = sx2;
703 tbox.y2 = sy2;
704
705 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
706 wl_fixed_from_int(es->geometry.height),
707 es->buffer_transform, tbox);
708
709 s->src_x = tbox.x1 << 8;
710 s->src_y = tbox.y1 << 8;
711 s->src_w = (tbox.x2 - tbox.x1) << 8;
712 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500713 pixman_region32_fini(&src_rect);
714
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400715 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500716}
717
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400718static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400719drm_output_prepare_cursor_surface(struct weston_output *output_base,
720 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500721{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400722 struct drm_compositor *c =
723 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400724 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400725
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200726 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
727 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400728 if (output->cursor_surface)
729 return NULL;
730 if (es->output_mask != (1u << output_base->id))
731 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500732 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400733 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200734 if (es->buffer_ref.buffer == NULL ||
735 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400736 es->geometry.width > 64 || es->geometry.height > 64)
737 return NULL;
738
739 output->cursor_surface = es;
740
741 return &output->cursor_plane;
742}
743
744static void
745drm_output_set_cursor(struct drm_output *output)
746{
747 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400748 struct drm_compositor *c =
749 (struct drm_compositor *) output->base.compositor;
750 EGLint handle, stride;
751 struct gbm_bo *bo;
752 uint32_t buf[64 * 64];
753 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400754 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500755
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400756 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400757 if (es == NULL) {
758 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
759 return;
760 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500761
Pekka Paalanende685b82012-12-04 15:58:12 +0200762 if (es->buffer_ref.buffer &&
763 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400764 pixman_region32_fini(&output->cursor_plane.damage);
765 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400766 output->current_cursor ^= 1;
767 bo = output->cursor_bo[output->current_cursor];
768 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200769 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
770 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400771 for (i = 0; i < es->geometry.height; i++)
772 memcpy(buf + i * 64, s + i * stride,
773 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500774
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400775 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300776 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400777
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400778 handle = gbm_bo_get_handle(bo).s32;
779 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500780 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300781 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500782 c->cursors_are_broken = 1;
783 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400784 }
785
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400786 x = es->geometry.x - output->base.x;
787 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400788 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500789 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400790 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500791 c->cursors_are_broken = 1;
792 }
793
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400794 output->cursor_plane.x = x;
795 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400796 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500797}
798
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799static void
800drm_assign_planes(struct weston_output *output)
801{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400802 struct drm_compositor *c =
803 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200804 struct drm_output *drm_output = (struct drm_output *) output;
805 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400806 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500807 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400808 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200810 /* Reset the opaque region of the planes */
811 pixman_region32_fini(&drm_output->cursor_plane.opaque);
812 pixman_region32_init(&drm_output->cursor_plane.opaque);
813 pixman_region32_fini(&drm_output->fb_plane.opaque);
814 pixman_region32_init(&drm_output->fb_plane.opaque);
815
816 wl_list_for_each (s, &c->sprite_list, link) {
817 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
818 continue;
819
820 pixman_region32_fini(&s->plane.opaque);
821 pixman_region32_init(&s->plane.opaque);
822 }
823
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824 /*
825 * Find a surface for each sprite in the output using some heuristics:
826 * 1) size
827 * 2) frequency of update
828 * 3) opacity (though some hw might support alpha blending)
829 * 4) clipping (this can be fixed with color keys)
830 *
831 * The idea is to save on blitting since this should save power.
832 * If we can get a large video surface on the sprite for example,
833 * the main display surface may not need to update at all, and
834 * the client buffer can be used directly for the sprite surface
835 * as we do for flipping full screen surfaces.
836 */
837 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400838 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400839 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200840 /* test whether this buffer can ever go into a plane:
841 * non-shm, or small enough to be a cursor
842 */
843 if ((es->buffer_ref.buffer &&
844 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
845 (es->geometry.width <= 64 && es->geometry.height <= 64))
846 es->keep_buffer = 1;
847 else
848 es->keep_buffer = 0;
849
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850 pixman_region32_init(&surface_overlap);
851 pixman_region32_intersect(&surface_overlap, &overlap,
852 &es->transform.boundingbox);
853
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400854 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400855 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400856 next_plane = primary;
857 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400858 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400859 if (next_plane == NULL)
860 next_plane = drm_output_prepare_scanout_surface(output, es);
861 if (next_plane == NULL)
862 next_plane = drm_output_prepare_overlay_surface(output, es);
863 if (next_plane == NULL)
864 next_plane = primary;
865 weston_surface_move_to_plane(es, next_plane);
866 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500867 pixman_region32_union(&overlap, &overlap,
868 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400869
Jesse Barnes58ef3792012-02-23 09:45:49 -0500870 pixman_region32_fini(&surface_overlap);
871 }
872 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500873}
874
Matt Roper361d2ad2011-08-29 13:52:23 -0700875static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500876drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700877{
878 struct drm_output *output = (struct drm_output *) output_base;
879 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200880 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700881 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700882
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200883 if (output->backlight)
884 backlight_destroy(output->backlight);
885
Matt Roper361d2ad2011-08-29 13:52:23 -0700886 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400887 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700888
889 /* Restore original CRTC state */
890 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200891 origcrtc->x, origcrtc->y,
892 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700893 drmModeFreeCrtc(origcrtc);
894
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200895 c->crtc_allocator &= ~(1 << output->crtc_id);
896 c->connector_allocator &= ~(1 << output->connector_id);
897
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100898 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100899
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400900 gbm_surface_destroy(output->surface);
901
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400902 weston_plane_release(&output->fb_plane);
903 weston_plane_release(&output->cursor_plane);
904
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500905 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200906 wl_list_remove(&output->base.link);
907
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400908 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700909 free(output);
910}
911
Alex Wub7b8bda2012-04-17 17:20:48 +0800912static struct drm_mode *
913choose_mode (struct drm_output *output, struct weston_mode *target_mode)
914{
915 struct drm_mode *tmp_mode = NULL, *mode;
916
917 if (output->base.current->width == target_mode->width &&
918 output->base.current->height == target_mode->height &&
919 (output->base.current->refresh == target_mode->refresh ||
920 target_mode->refresh == 0))
921 return (struct drm_mode *)output->base.current;
922
923 wl_list_for_each(mode, &output->base.mode_list, base.link) {
924 if (mode->mode_info.hdisplay == target_mode->width &&
925 mode->mode_info.vdisplay == target_mode->height) {
926 if (mode->mode_info.vrefresh == target_mode->refresh ||
927 target_mode->refresh == 0) {
928 return mode;
929 } else if (!tmp_mode)
930 tmp_mode = mode;
931 }
932 }
933
934 return tmp_mode;
935}
936
937static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200938drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
939
940static int
Alex Wub7b8bda2012-04-17 17:20:48 +0800941drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
942{
943 struct drm_output *output;
944 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +0800945 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +0800946
947 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200948 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800949 return -1;
950 }
951
952 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200953 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800954 return -1;
955 }
956
957 ec = (struct drm_compositor *)output_base->compositor;
958 output = (struct drm_output *)output_base;
959 drm_mode = choose_mode (output, mode);
960
961 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200962 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800963 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200964 }
965
966 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +0800967 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800968
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200969 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800970
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200971 output->base.current = &drm_mode->base;
972 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +0800973 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
974
Alex Wub7b8bda2012-04-17 17:20:48 +0800975 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300976 if (output->current) {
977 if (output->current->is_client_buffer)
978 gbm_bo_destroy(output->current->bo);
979 else
980 gbm_surface_release_buffer(output->surface,
981 output->current->bo);
982 }
983 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800984
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300985 if (output->next) {
986 if (output->next->is_client_buffer)
987 gbm_bo_destroy(output->next->bo);
988 else
989 gbm_surface_release_buffer(output->surface,
990 output->next->bo);
991 }
992 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800993
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200994 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800995 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800996
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200997 if (drm_output_init_egl(output, ec) < 0) {
998 weston_log("failed to init output egl state with new mode");
999 return -1;
1000 }
1001
Alex Wub7b8bda2012-04-17 17:20:48 +08001002 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001003}
1004
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001005static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001006on_drm_input(int fd, uint32_t mask, void *data)
1007{
1008 drmEventContext evctx;
1009
1010 memset(&evctx, 0, sizeof evctx);
1011 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1012 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001013 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001014 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001015
1016 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001017}
1018
1019static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001020init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001021{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001022 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001023 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001024
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001025 sysnum = udev_device_get_sysnum(device);
1026 if (sysnum)
1027 ec->drm.id = atoi(sysnum);
1028 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001029 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001030 return -1;
1031 }
1032
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001033 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001034 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001035 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001036 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001037 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001038 udev_device_get_devnode(device));
1039 return -1;
1040 }
1041
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001042 weston_log("using %s\n", filename);
1043
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001044 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001045
1046 return 0;
1047}
1048
1049static int
1050init_egl(struct drm_compositor *ec)
1051{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001052 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001053
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001054 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001055 NULL) < 0) {
1056 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001057 return -1;
1058 }
1059
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001060 return 0;
1061}
1062
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001063static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001064drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1065{
1066 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001067 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001068
1069 mode = malloc(sizeof *mode);
1070 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001071 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001072
1073 mode->base.flags = 0;
1074 mode->base.width = info->hdisplay;
1075 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001076
1077 /* Calculate higher precision (mHz) refresh rate */
1078 refresh = (info->clock * 1000000LL / info->htotal +
1079 info->vtotal / 2) / info->vtotal;
1080
1081 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1082 refresh *= 2;
1083 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1084 refresh /= 2;
1085 if (info->vscan > 1)
1086 refresh /= info->vscan;
1087
1088 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001089 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001090
1091 if (info->type & DRM_MODE_TYPE_PREFERRED)
1092 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1093
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001094 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1095
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001096 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001097}
1098
1099static int
1100drm_subpixel_to_wayland(int drm_value)
1101{
1102 switch (drm_value) {
1103 default:
1104 case DRM_MODE_SUBPIXEL_UNKNOWN:
1105 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1106 case DRM_MODE_SUBPIXEL_NONE:
1107 return WL_OUTPUT_SUBPIXEL_NONE;
1108 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1109 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1110 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1111 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1112 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1113 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1114 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1115 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1116 }
1117}
1118
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001119/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001120static uint32_t
1121drm_get_backlight(struct drm_output *output)
1122{
1123 long brightness, max_brightness, norm;
1124
1125 brightness = backlight_get_brightness(output->backlight);
1126 max_brightness = backlight_get_max_brightness(output->backlight);
1127
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001128 /* convert it on a scale of 0 to 255 */
1129 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001130
1131 return (uint32_t) norm;
1132}
1133
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001134/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001135static void
1136drm_set_backlight(struct weston_output *output_base, uint32_t value)
1137{
1138 struct drm_output *output = (struct drm_output *) output_base;
1139 long max_brightness, new_brightness;
1140
1141 if (!output->backlight)
1142 return;
1143
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001144 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001145 return;
1146
1147 max_brightness = backlight_get_max_brightness(output->backlight);
1148
1149 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001150 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001151
1152 backlight_set_brightness(output->backlight, new_brightness);
1153}
1154
1155static drmModePropertyPtr
1156drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1157{
1158 drmModePropertyPtr props;
1159 int i;
1160
1161 for (i = 0; i < connector->count_props; i++) {
1162 props = drmModeGetProperty(fd, connector->props[i]);
1163 if (!props)
1164 continue;
1165
1166 if (!strcmp(props->name, name))
1167 return props;
1168
1169 drmModeFreeProperty(props);
1170 }
1171
1172 return NULL;
1173}
1174
1175static void
1176drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1177{
1178 struct drm_output *output = (struct drm_output *) output_base;
1179 struct weston_compositor *ec = output_base->compositor;
1180 struct drm_compositor *c = (struct drm_compositor *) ec;
1181 drmModeConnectorPtr connector;
1182 drmModePropertyPtr prop;
1183
1184 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1185 if (!connector)
1186 return;
1187
1188 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1189 if (!prop) {
1190 drmModeFreeConnector(connector);
1191 return;
1192 }
1193
1194 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1195 prop->prop_id, level);
1196 drmModeFreeProperty(prop);
1197 drmModeFreeConnector(connector);
1198}
1199
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001200static const char *connector_type_names[] = {
1201 "None",
1202 "VGA",
1203 "DVI",
1204 "DVI",
1205 "DVI",
1206 "Composite",
1207 "TV",
1208 "LVDS",
1209 "CTV",
1210 "DIN",
1211 "DP",
1212 "HDMI",
1213 "HDMI",
1214 "TV",
1215 "eDP",
1216};
1217
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001218static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001219find_crtc_for_connector(struct drm_compositor *ec,
1220 drmModeRes *resources, drmModeConnector *connector)
1221{
1222 drmModeEncoder *encoder;
1223 uint32_t possible_crtcs;
1224 int i, j;
1225
1226 for (j = 0; j < connector->count_encoders; j++) {
1227 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1228 if (encoder == NULL) {
1229 weston_log("Failed to get encoder.\n");
1230 return -1;
1231 }
1232 possible_crtcs = encoder->possible_crtcs;
1233 drmModeFreeEncoder(encoder);
1234
1235 for (i = 0; i < resources->count_crtcs; i++) {
1236 if (possible_crtcs & (1 << i) &&
1237 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1238 return i;
1239 }
1240 }
1241
1242 return -1;
1243}
1244
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001245/* Init output state that depends on gl or gbm */
1246static int
1247drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1248{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001249 int i, flags;
1250
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001251 output->surface = gbm_surface_create(ec->gbm,
1252 output->base.current->width,
1253 output->base.current->height,
1254 GBM_FORMAT_XRGB8888,
1255 GBM_BO_USE_SCANOUT |
1256 GBM_BO_USE_RENDERING);
1257 if (!output->surface) {
1258 weston_log("failed to create gbm surface\n");
1259 return -1;
1260 }
1261
1262 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001263 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001264 gbm_surface_destroy(output->surface);
1265 return -1;
1266 }
1267
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001268 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1269
1270 for (i = 0; i < 2; i++) {
1271 if (output->cursor_bo[i])
1272 continue;
1273
1274 output->cursor_bo[i] =
1275 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1276 flags);
1277 }
1278
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001279 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1280 weston_log("cursor buffers unavailable, using gl cursors\n");
1281 ec->cursors_are_broken = 1;
1282 }
1283
1284 return 0;
1285}
1286
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001287static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001288create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001289 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001290 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001291 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001292{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001293 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001294 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1295 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001296 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001297 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001298 drmModeModeInfo crtc_mode;
1299 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001300 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001301 char name[32];
1302 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001303
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001304 i = find_crtc_for_connector(ec, resources, connector);
1305 if (i < 0) {
1306 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001307 return -1;
1308 }
1309
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001310 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001311 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001312 return -1;
1313
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001314 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001315 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1316 output->base.make = "unknown";
1317 output->base.model = "unknown";
1318 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001319
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001320 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1321 type_name = connector_type_names[connector->connector_type];
1322 else
1323 type_name = "UNKNOWN";
1324 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1325 output->name = strdup(name);
1326
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001327 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001328 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001329 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001330 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001331 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001332
Matt Roper361d2ad2011-08-29 13:52:23 -07001333 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1334
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001335 /* Get the current mode on the crtc that's currently driving
1336 * this connector. */
1337 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001338 memset(&crtc_mode, 0, sizeof crtc_mode);
1339 if (encoder != NULL) {
1340 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1341 drmModeFreeEncoder(encoder);
1342 if (crtc == NULL)
1343 goto err_free;
1344 if (crtc->mode_valid)
1345 crtc_mode = crtc->mode;
1346 drmModeFreeCrtc(crtc);
1347 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001348
David Herrmann0f0d54e2011-12-08 17:05:45 +01001349 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001350 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1351 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001352 goto err_free;
1353 }
1354
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001355 preferred = NULL;
1356 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001357 configured = NULL;
1358
1359 wl_list_for_each(temp, &configured_output_list, link) {
1360 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001361 if (temp->mode)
1362 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001363 temp->name, temp->mode);
1364 o = temp;
1365 break;
1366 }
1367 }
1368
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001369 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001370 weston_log("Disabling output %s\n", o->name);
1371
1372 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1373 0, 0, 0, 0, 0, NULL);
1374 goto err_free;
1375 }
1376
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001377 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001378 if (o && o->config == OUTPUT_CONFIG_MODE &&
1379 o->width == drm_mode->base.width &&
1380 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001381 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001382 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001383 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001384 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001385 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001386 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001387
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001388 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001389 configured = drm_output_add_mode(output, &o->crtc_mode);
1390 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001391 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001392 current = configured;
1393 }
1394
Wang Quanxianacb805a2012-07-30 18:09:46 -04001395 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001396 current = drm_output_add_mode(output, &crtc_mode);
1397 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001398 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001399 }
1400
Scott Moreau8ab5d452012-07-30 19:51:08 -06001401 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1402 configured = current;
1403
Wang Quanxianacb805a2012-07-30 18:09:46 -04001404 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001405 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001406 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001407 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001408 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001409 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001410 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001411 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001412
1413 if (output->base.current == NULL) {
1414 weston_log("no available modes for %s\n", output->name);
1415 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001416 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001417
Wang Quanxianacb805a2012-07-30 18:09:46 -04001418 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1419
John Kåre Alsaker94659272012-11-13 19:10:18 +01001420 weston_output_init(&output->base, &ec->base, x, y,
1421 connector->mmWidth, connector->mmHeight,
1422 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1423
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001424 if (drm_output_init_egl(output, ec) < 0) {
1425 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001426 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001427 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001428
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001429 output->backlight = backlight_init(drm_device,
1430 connector->connector_type);
1431 if (output->backlight) {
1432 output->base.set_backlight = drm_set_backlight;
1433 output->base.backlight_current = drm_get_backlight(output);
1434 }
1435
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001436 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1437
Alex Wubd3354b2012-04-17 17:20:49 +08001438 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001439 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001440 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001441 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001442 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001443 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001444
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001445 weston_plane_init(&output->cursor_plane, 0, 0);
1446 weston_plane_init(&output->fb_plane, 0, 0);
1447
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001448 weston_log("Output %s, (connector %d, crtc %d)\n",
1449 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001450 wl_list_for_each(m, &output->base.mode_list, link)
1451 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1452 m->width, m->height, m->refresh / 1000.0,
1453 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1454 ", preferred" : "",
1455 m->flags & WL_OUTPUT_MODE_CURRENT ?
1456 ", current" : "",
1457 connector->count_modes == 0 ?
1458 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001459
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001460 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001461
John Kåre Alsaker94659272012-11-13 19:10:18 +01001462err_output:
1463 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001464err_free:
1465 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1466 base.link) {
1467 wl_list_remove(&drm_mode->base.link);
1468 free(drm_mode);
1469 }
1470
1471 drmModeFreeCrtc(output->original_crtc);
1472 ec->crtc_allocator &= ~(1 << output->crtc_id);
1473 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001474 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001475 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001476
David Herrmann0f0d54e2011-12-08 17:05:45 +01001477 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001478}
1479
Jesse Barnes58ef3792012-02-23 09:45:49 -05001480static void
1481create_sprites(struct drm_compositor *ec)
1482{
1483 struct drm_sprite *sprite;
1484 drmModePlaneRes *plane_res;
1485 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001486 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001487
1488 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1489 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001490 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001491 strerror(errno));
1492 return;
1493 }
1494
1495 for (i = 0; i < plane_res->count_planes; i++) {
1496 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1497 if (!plane)
1498 continue;
1499
1500 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1501 plane->count_formats));
1502 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001503 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001504 __func__);
1505 free(plane);
1506 continue;
1507 }
1508
1509 memset(sprite, 0, sizeof *sprite);
1510
1511 sprite->possible_crtcs = plane->possible_crtcs;
1512 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001513 sprite->current = NULL;
1514 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001515 sprite->compositor = ec;
1516 sprite->count_formats = plane->count_formats;
1517 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001518 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001519 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001520 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001521
1522 wl_list_insert(&ec->sprite_list, &sprite->link);
1523 }
1524
1525 free(plane_res->planes);
1526 free(plane_res);
1527}
1528
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001529static void
1530destroy_sprites(struct drm_compositor *compositor)
1531{
1532 struct drm_sprite *sprite, *next;
1533 struct drm_output *output;
1534
1535 output = container_of(compositor->base.output_list.next,
1536 struct drm_output, base.link);
1537
1538 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1539 drmModeSetPlane(compositor->drm.fd,
1540 sprite->plane_id,
1541 output->crtc_id, 0, 0,
1542 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001543 if (sprite->current)
1544 gbm_bo_destroy(sprite->current->bo);
1545 if (sprite->next)
1546 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001547 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001548 free(sprite);
1549 }
1550}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001551
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001552static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001553create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001554 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001555{
1556 drmModeConnector *connector;
1557 drmModeRes *resources;
1558 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001559 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001560
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001561 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001562 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001563 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001564 return -1;
1565 }
1566
Jesse Barnes58ef3792012-02-23 09:45:49 -05001567 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001568 if (!ec->crtcs) {
1569 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001570 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001571 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001572
Rob Clark4339add2012-08-09 14:18:28 -05001573 ec->min_width = resources->min_width;
1574 ec->max_width = resources->max_width;
1575 ec->min_height = resources->min_height;
1576 ec->max_height = resources->max_height;
1577
Jesse Barnes58ef3792012-02-23 09:45:49 -05001578 ec->num_crtcs = resources->count_crtcs;
1579 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1580
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001581 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001582 connector = drmModeGetConnector(ec->drm.fd,
1583 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001584 if (connector == NULL)
1585 continue;
1586
1587 if (connector->connection == DRM_MODE_CONNECTED &&
1588 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001589 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001590 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001591 connector, x, y,
1592 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001593 drmModeFreeConnector(connector);
1594 continue;
1595 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001596
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001597 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001598 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001599 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001600 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001601
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001602 drmModeFreeConnector(connector);
1603 }
1604
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001605 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001606 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001607 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001608 return -1;
1609 }
1610
1611 drmModeFreeResources(resources);
1612
1613 return 0;
1614}
1615
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001616static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001617update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001618{
1619 drmModeConnector *connector;
1620 drmModeRes *resources;
1621 struct drm_output *output, *next;
1622 int x = 0, y = 0;
1623 int x_offset = 0, y_offset = 0;
1624 uint32_t connected = 0, disconnects = 0;
1625 int i;
1626
1627 resources = drmModeGetResources(ec->drm.fd);
1628 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001629 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001630 return;
1631 }
1632
1633 /* collect new connects */
1634 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001635 int connector_id = resources->connectors[i];
1636
1637 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001638 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001639 continue;
1640
David Herrmann7551cff2011-12-08 17:05:43 +01001641 if (connector->connection != DRM_MODE_CONNECTED) {
1642 drmModeFreeConnector(connector);
1643 continue;
1644 }
1645
Benjamin Franzke117483d2011-08-30 11:38:26 +02001646 connected |= (1 << connector_id);
1647
1648 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001649 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001650 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001651 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001652
1653 /* XXX: not yet needed, we die with 0 outputs */
1654 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001655 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001656 else
1657 x = 0;
1658 y = 0;
1659 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001660 connector, x, y,
1661 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001662 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001663
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001664 }
1665 drmModeFreeConnector(connector);
1666 }
1667 drmModeFreeResources(resources);
1668
1669 disconnects = ec->connector_allocator & ~connected;
1670 if (disconnects) {
1671 wl_list_for_each_safe(output, next, &ec->base.output_list,
1672 base.link) {
1673 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001674 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001675 output->base.x - x_offset,
1676 output->base.y - y_offset);
1677 }
1678
1679 if (disconnects & (1 << output->connector_id)) {
1680 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001681 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001682 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001683 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001684 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001685 }
1686 }
1687 }
1688
1689 /* FIXME: handle zero outputs, without terminating */
1690 if (ec->connector_allocator == 0)
1691 wl_display_terminate(ec->base.wl_display);
1692}
1693
1694static int
David Herrmannd7488c22012-03-11 20:05:21 +01001695udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001696{
David Herrmannd7488c22012-03-11 20:05:21 +01001697 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001698 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001699
1700 sysnum = udev_device_get_sysnum(device);
1701 if (!sysnum || atoi(sysnum) != ec->drm.id)
1702 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001703
David Herrmann6ac52db2012-03-11 20:05:22 +01001704 val = udev_device_get_property_value(device, "HOTPLUG");
1705 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001706 return 0;
1707
David Herrmann6ac52db2012-03-11 20:05:22 +01001708 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001709}
1710
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001711static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001712udev_drm_event(int fd, uint32_t mask, void *data)
1713{
1714 struct drm_compositor *ec = data;
1715 struct udev_device *event;
1716
1717 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001718
David Herrmannd7488c22012-03-11 20:05:21 +01001719 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001720 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001721
1722 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001723
1724 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001725}
1726
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001727static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001728drm_restore(struct weston_compositor *ec)
1729{
1730 struct drm_compositor *d = (struct drm_compositor *) ec;
1731
1732 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1733 weston_log("failed to drop master: %m\n");
1734 tty_reset(d->tty);
1735}
1736
Pekka Paalanen33156972012-08-03 13:30:30 -04001737static const char default_seat[] = "seat0";
1738
1739static void
1740device_added(struct udev_device *udev_device, struct drm_seat *master)
1741{
1742 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001743 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001744 const char *devnode;
1745 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001746 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001747 int fd;
1748
1749 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1750 if (!device_seat)
1751 device_seat = default_seat;
1752
1753 if (strcmp(device_seat, master->seat_id))
1754 return;
1755
1756 c = master->base.compositor;
1757 devnode = udev_device_get_devnode(udev_device);
1758
1759 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001760 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001761 * read. mtdev_get() also expects this. */
1762 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1763 if (fd < 0) {
1764 weston_log("opening input device '%s' failed.\n", devnode);
1765 return;
1766 }
1767
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001768 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001769 if (!device) {
1770 close(fd);
1771 weston_log("not using input device '%s'.\n", devnode);
1772 return;
1773 }
1774
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001775 calibration_values =
1776 udev_device_get_property_value(udev_device,
1777 "WL_CALIBRATION");
1778
1779 if (calibration_values && sscanf(calibration_values,
1780 "%f %f %f %f %f %f",
1781 &device->abs.calibration[0],
1782 &device->abs.calibration[1],
1783 &device->abs.calibration[2],
1784 &device->abs.calibration[3],
1785 &device->abs.calibration[4],
1786 &device->abs.calibration[5]) == 6) {
1787 device->abs.apply_calibration = 1;
1788 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1789 device->abs.calibration[0],
1790 device->abs.calibration[1],
1791 device->abs.calibration[2],
1792 device->abs.calibration[3],
1793 device->abs.calibration[4],
1794 device->abs.calibration[5]);
1795 }
1796
Pekka Paalanen33156972012-08-03 13:30:30 -04001797 wl_list_insert(master->devices_list.prev, &device->link);
1798}
1799
1800static void
1801evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1802{
1803 struct drm_seat *seat = (struct drm_seat *) seat_base;
1804 struct udev_enumerate *e;
1805 struct udev_list_entry *entry;
1806 struct udev_device *device;
1807 const char *path, *sysname;
1808
1809 e = udev_enumerate_new(udev);
1810 udev_enumerate_add_match_subsystem(e, "input");
1811 udev_enumerate_scan_devices(e);
1812 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1813 path = udev_list_entry_get_name(entry);
1814 device = udev_device_new_from_syspath(udev, path);
1815
1816 sysname = udev_device_get_sysname(device);
1817 if (strncmp("event", sysname, 5) != 0) {
1818 udev_device_unref(device);
1819 continue;
1820 }
1821
1822 device_added(device, seat);
1823
1824 udev_device_unref(device);
1825 }
1826 udev_enumerate_unref(e);
1827
1828 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1829
1830 if (wl_list_empty(&seat->devices_list)) {
1831 weston_log(
1832 "warning: no input devices on entering Weston. "
1833 "Possible causes:\n"
1834 "\t- no permissions to read /dev/input/event*\n"
1835 "\t- seats misconfigured "
1836 "(Weston backend option 'seat', "
1837 "udev device property ID_SEAT)\n");
1838 }
1839}
1840
1841static int
1842evdev_udev_handler(int fd, uint32_t mask, void *data)
1843{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001844 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001845 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001846 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001847 const char *action;
1848 const char *devnode;
1849
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001850 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001851 if (!udev_device)
1852 return 1;
1853
1854 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001855 if (!action)
1856 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001857
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001858 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1859 goto out;
1860
1861 if (!strcmp(action, "add")) {
1862 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001863 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001864 else if (!strcmp(action, "remove")) {
1865 devnode = udev_device_get_devnode(udev_device);
1866 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1867 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001868 weston_log("input device %s, %s removed\n",
1869 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001870 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001871 break;
1872 }
1873 }
1874
1875out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001876 udev_device_unref(udev_device);
1877
1878 return 0;
1879}
1880
1881static int
1882evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1883{
1884 struct drm_seat *master = (struct drm_seat *) seat_base;
1885 struct wl_event_loop *loop;
1886 struct weston_compositor *c = master->base.compositor;
1887 int fd;
1888
1889 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1890 if (!master->udev_monitor) {
1891 weston_log("udev: failed to create the udev monitor\n");
1892 return 0;
1893 }
1894
1895 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1896 "input", NULL);
1897
1898 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1899 weston_log("udev: failed to bind the udev monitor\n");
1900 udev_monitor_unref(master->udev_monitor);
1901 return 0;
1902 }
1903
1904 loop = wl_display_get_event_loop(c->wl_display);
1905 fd = udev_monitor_get_fd(master->udev_monitor);
1906 master->udev_monitor_source =
1907 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1908 evdev_udev_handler, master);
1909 if (!master->udev_monitor_source) {
1910 udev_monitor_unref(master->udev_monitor);
1911 return 0;
1912 }
1913
1914 return 1;
1915}
1916
1917static void
1918evdev_disable_udev_monitor(struct weston_seat *seat_base)
1919{
1920 struct drm_seat *seat = (struct drm_seat *) seat_base;
1921
1922 if (!seat->udev_monitor)
1923 return;
1924
1925 udev_monitor_unref(seat->udev_monitor);
1926 seat->udev_monitor = NULL;
1927 wl_event_source_remove(seat->udev_monitor_source);
1928 seat->udev_monitor_source = NULL;
1929}
1930
1931static void
1932drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1933{
1934 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001935 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001936
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001937 wl_list_for_each(device, &seat->devices_list, link)
1938 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001939}
1940
1941static void
1942evdev_input_create(struct weston_compositor *c, struct udev *udev,
1943 const char *seat_id)
1944{
1945 struct drm_seat *seat;
1946
1947 seat = malloc(sizeof *seat);
1948 if (seat == NULL)
1949 return;
1950
1951 memset(seat, 0, sizeof *seat);
1952 weston_seat_init(&seat->base, c);
1953 seat->base.led_update = drm_led_update;
1954
1955 wl_list_init(&seat->devices_list);
1956 seat->seat_id = strdup(seat_id);
1957 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1958 free(seat->seat_id);
1959 free(seat);
1960 return;
1961 }
1962
1963 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001964}
1965
1966static void
1967evdev_remove_devices(struct weston_seat *seat_base)
1968{
1969 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001970 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001971
1972 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001973 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001974
Pekka Paalanend8583512012-08-03 14:39:11 +03001975 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001976 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001977}
1978
1979static void
1980evdev_input_destroy(struct weston_seat *seat_base)
1981{
1982 struct drm_seat *seat = (struct drm_seat *) seat_base;
1983
1984 evdev_remove_devices(seat_base);
1985 evdev_disable_udev_monitor(&seat->base);
1986
1987 weston_seat_release(seat_base);
1988 free(seat->seat_id);
1989 free(seat);
1990}
1991
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001992static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001993drm_free_configured_output(struct drm_configured_output *output)
1994{
1995 free(output->name);
1996 free(output->mode);
1997 free(output);
1998}
1999
2000static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002001drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002002{
2003 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002004 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002005 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002006
Daniel Stone37816df2012-05-16 18:45:18 +01002007 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2008 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002009 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002010 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002011
2012 wl_event_source_remove(d->udev_drm_source);
2013 wl_event_source_remove(d->drm_source);
2014
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002015 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002016
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002017 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002018
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002019 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002020 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002021 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002022 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002023 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002024
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002025 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002026}
2027
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002028static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002029drm_compositor_set_modes(struct drm_compositor *compositor)
2030{
2031 struct drm_output *output;
2032 struct drm_mode *drm_mode;
2033 int ret;
2034
2035 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2036 drm_mode = (struct drm_mode *) output->base.current;
2037 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002038 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002039 &output->connector_id, 1,
2040 &drm_mode->mode_info);
2041 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002042 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002043 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002044 drm_mode->base.width, drm_mode->base.height,
2045 output->base.x, output->base.y);
2046 }
2047 }
2048}
2049
2050static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002051vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002052{
2053 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002054 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002055 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002056 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002057
2058 switch (event) {
2059 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002060 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002061 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002062 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002063 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002064 wl_display_terminate(compositor->wl_display);
2065 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002066 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002067 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002068 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002069 wl_list_for_each(seat, &compositor->seat_list, link) {
2070 evdev_add_devices(ec->udev, seat);
2071 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002072 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002073 break;
2074 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002075 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002076 wl_list_for_each(seat, &compositor->seat_list, link) {
2077 evdev_disable_udev_monitor(seat);
2078 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002079 }
2080
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002081 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002082 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002083 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002084
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002085 /* If we have a repaint scheduled (either from a
2086 * pending pageflip or the idle handler), make sure we
2087 * cancel that so we don't try to pageflip when we're
2088 * vt switched away. The SLEEPING state will prevent
2089 * further attemps at repainting. When we switch
2090 * back, we schedule a repaint, which will process
2091 * pending frame callbacks. */
2092
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002093 wl_list_for_each(output, &ec->base.output_list, base.link) {
2094 output->base.repaint_needed = 0;
2095 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002096 }
2097
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002098 output = container_of(ec->base.output_list.next,
2099 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002100
2101 wl_list_for_each(sprite, &ec->sprite_list, link)
2102 drmModeSetPlane(ec->drm.fd,
2103 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002104 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002105 0, 0, 0, 0, 0, 0, 0, 0);
2106
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002107 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002108 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002109
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002110 break;
2111 };
2112}
2113
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002114static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002115switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002116{
2117 struct drm_compositor *ec = data;
2118
Daniel Stone325fc2d2012-05-30 16:31:58 +01002119 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002120}
2121
David Herrmann0af066f2012-10-29 19:21:16 +01002122/*
2123 * Find primary GPU
2124 * Some systems may have multiple DRM devices attached to a single seat. This
2125 * function loops over all devices and tries to find a PCI device with the
2126 * boot_vga sysfs attribute set to 1.
2127 * If no such device is found, the first DRM device reported by udev is used.
2128 */
2129static struct udev_device*
2130find_primary_gpu(struct drm_compositor *ec, const char *seat)
2131{
2132 struct udev_enumerate *e;
2133 struct udev_list_entry *entry;
2134 const char *path, *device_seat, *id;
2135 struct udev_device *device, *drm_device, *pci;
2136
2137 e = udev_enumerate_new(ec->udev);
2138 udev_enumerate_add_match_subsystem(e, "drm");
2139 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2140
2141 udev_enumerate_scan_devices(e);
2142 drm_device = NULL;
2143 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2144 path = udev_list_entry_get_name(entry);
2145 device = udev_device_new_from_syspath(ec->udev, path);
2146 if (!device)
2147 continue;
2148 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2149 if (!device_seat)
2150 device_seat = default_seat;
2151 if (strcmp(device_seat, seat)) {
2152 udev_device_unref(device);
2153 continue;
2154 }
2155
2156 pci = udev_device_get_parent_with_subsystem_devtype(device,
2157 "pci", NULL);
2158 if (pci) {
2159 id = udev_device_get_sysattr_value(pci, "boot_vga");
2160 if (id && !strcmp(id, "1")) {
2161 if (drm_device)
2162 udev_device_unref(drm_device);
2163 drm_device = device;
2164 break;
2165 }
2166 }
2167
2168 if (!drm_device)
2169 drm_device = device;
2170 else
2171 udev_device_unref(device);
2172 }
2173
2174 udev_enumerate_unref(e);
2175 return drm_device;
2176}
2177
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002178static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002179planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002180{
2181 struct drm_compositor *c = data;
2182
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002183 switch (key) {
2184 case KEY_C:
2185 c->cursors_are_broken ^= 1;
2186 break;
2187 case KEY_V:
2188 c->sprites_are_broken ^= 1;
2189 break;
2190 case KEY_O:
2191 c->sprites_hidden ^= 1;
2192 break;
2193 default:
2194 break;
2195 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002196}
2197
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002198static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002199drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002200 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002201 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002202{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002203 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002204 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002205 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002206 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002207 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002208 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002209
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002210 weston_log("initializing drm backend\n");
2211
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002212 ec = malloc(sizeof *ec);
2213 if (ec == NULL)
2214 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002215 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002216
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002217 /* KMS support for sprites is not complete yet, so disable the
2218 * functionality for now. */
2219 ec->sprites_are_broken = 1;
2220
Daniel Stone725c2c32012-06-22 14:04:36 +01002221 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002222 config_file) < 0) {
2223 weston_log("weston_compositor_init failed\n");
2224 goto err_base;
2225 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002226
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002227 ec->udev = udev_new();
2228 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002229 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002230 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002231 }
2232
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002233 ec->base.wl_display = display;
2234 ec->tty = tty_create(&ec->base, vt_func, tty);
2235 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002236 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002237 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002238 }
2239
David Herrmann0af066f2012-10-29 19:21:16 +01002240 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002241 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002242 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002243 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002244 }
David Herrmann0af066f2012-10-29 19:21:16 +01002245 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002246
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002247 if (init_drm(ec, drm_device) < 0) {
2248 weston_log("failed to initialize kms\n");
2249 goto err_udev_dev;
2250 }
2251
2252 if (init_egl(ec) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002253 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002254 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002255 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002256
2257 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002258 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002259
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002260 ec->base.focus = 1;
2261
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002262 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002263
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002264 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002265 weston_compositor_add_key_binding(&ec->base, key,
2266 MODIFIER_CTRL | MODIFIER_ALT,
2267 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002268
Jesse Barnes58ef3792012-02-23 09:45:49 -05002269 wl_list_init(&ec->sprite_list);
2270 create_sprites(ec);
2271
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002272 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002273 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002274 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002275 }
2276
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002277 path = NULL;
2278
Tiago Vignattice03ec32011-12-19 01:14:03 +02002279 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002280
2281 loop = wl_display_get_event_loop(ec->base.wl_display);
2282 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002283 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002284 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002285
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002286 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2287 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002288 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002289 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002290 }
2291 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2292 "drm", NULL);
2293 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002294 wl_event_loop_add_fd(loop,
2295 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002296 WL_EVENT_READABLE, udev_drm_event, ec);
2297
2298 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002299 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002300 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002301 }
2302
Daniel Stonea96b93c2012-06-22 14:04:37 +01002303 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002304
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002305 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002306 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002307 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002308 planes_binding, ec);
2309 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2310 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002311
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002312 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002313
2314err_udev_monitor:
2315 wl_event_source_remove(ec->udev_drm_source);
2316 udev_monitor_unref(ec->udev_monitor);
2317err_drm_source:
2318 wl_event_source_remove(ec->drm_source);
2319 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2320 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002321err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002322 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002323 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002324 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002325err_udev_dev:
2326 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002327err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002328 tty_destroy(ec->tty);
2329err_udev:
2330 udev_unref(ec->udev);
2331err_compositor:
2332 weston_compositor_shutdown(&ec->base);
2333err_base:
2334 free(ec);
2335 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002336}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002337
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002338static int
2339set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2340{
2341 mode->flags = 0;
2342
2343 if (strcmp(hsync, "+hsync") == 0)
2344 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2345 else if (strcmp(hsync, "-hsync") == 0)
2346 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2347 else
2348 return -1;
2349
2350 if (strcmp(vsync, "+vsync") == 0)
2351 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2352 else if (strcmp(vsync, "-vsync") == 0)
2353 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2354 else
2355 return -1;
2356
2357 return 0;
2358}
2359
2360static int
2361check_for_modeline(struct drm_configured_output *output)
2362{
2363 drmModeModeInfo mode;
2364 char hsync[16];
2365 char vsync[16];
2366 char mode_name[16];
2367 float fclock;
2368
2369 mode.type = DRM_MODE_TYPE_USERDEF;
2370 mode.hskew = 0;
2371 mode.vscan = 0;
2372 mode.vrefresh = 0;
2373
2374 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2375 &fclock, &mode.hdisplay,
2376 &mode.hsync_start,
2377 &mode.hsync_end, &mode.htotal,
2378 &mode.vdisplay,
2379 &mode.vsync_start,
2380 &mode.vsync_end, &mode.vtotal,
2381 hsync, vsync) == 11) {
2382 if (set_sync_flags(&mode, hsync, vsync))
2383 return -1;
2384
2385 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2386 strcpy(mode.name, mode_name);
2387
2388 mode.clock = fclock * 1000;
2389 } else
2390 return -1;
2391
2392 output->crtc_mode = mode;
2393
2394 return 0;
2395}
2396
Scott Moreau8ab5d452012-07-30 19:51:08 -06002397static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002398drm_output_set_transform(struct drm_configured_output *output)
2399{
2400 if (!output_transform) {
2401 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2402 return;
2403 }
2404
2405 if (!strcmp(output_transform, "normal"))
2406 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2407 else if (!strcmp(output_transform, "90"))
2408 output->transform = WL_OUTPUT_TRANSFORM_90;
2409 else if (!strcmp(output_transform, "180"))
2410 output->transform = WL_OUTPUT_TRANSFORM_180;
2411 else if (!strcmp(output_transform, "270"))
2412 output->transform = WL_OUTPUT_TRANSFORM_270;
2413 else if (!strcmp(output_transform, "flipped"))
2414 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2415 else if (!strcmp(output_transform, "flipped-90"))
2416 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2417 else if (!strcmp(output_transform, "flipped-180"))
2418 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2419 else if (!strcmp(output_transform, "flipped-270"))
2420 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2421 else {
2422 weston_log("Invalid transform \"%s\" for output %s\n",
2423 output_transform, output_name);
2424 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2425 }
2426
2427 free(output_transform);
2428 output_transform = NULL;
2429}
2430
2431static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002432output_section_done(void *data)
2433{
2434 struct drm_configured_output *output;
2435
2436 output = malloc(sizeof *output);
2437
Scott Moreau1bad5db2012-08-18 01:04:05 -06002438 if (!output || !output_name || (output_name[0] == 'X') ||
2439 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002440 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002441 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002442 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002443 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002444 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002445 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002446 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002447 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002448 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002449
2450 output->config = OUTPUT_CONFIG_INVALID;
2451 output->name = output_name;
2452 output->mode = output_mode;
2453
Scott Moreau1bad5db2012-08-18 01:04:05 -06002454 if (output_mode) {
2455 if (strcmp(output_mode, "off") == 0)
2456 output->config = OUTPUT_CONFIG_OFF;
2457 else if (strcmp(output_mode, "preferred") == 0)
2458 output->config = OUTPUT_CONFIG_PREFERRED;
2459 else if (strcmp(output_mode, "current") == 0)
2460 output->config = OUTPUT_CONFIG_CURRENT;
2461 else if (sscanf(output_mode, "%dx%d",
2462 &output->width, &output->height) == 2)
2463 output->config = OUTPUT_CONFIG_MODE;
2464 else if (check_for_modeline(output) == 0)
2465 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002466
Scott Moreau1bad5db2012-08-18 01:04:05 -06002467 if (output->config == OUTPUT_CONFIG_INVALID)
2468 weston_log("Invalid mode \"%s\" for output %s\n",
2469 output_mode, output_name);
2470 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002471 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002472
2473 drm_output_set_transform(output);
2474
2475 wl_list_insert(&configured_output_list, &output->link);
2476
2477 if (output_transform)
2478 free(output_transform);
2479 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002480}
2481
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002482WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002483backend_init(struct wl_display *display, int argc, char *argv[],
2484 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002485{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002486 int connector = 0, tty = 0;
2487 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002488
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002489 const struct weston_option drm_options[] = {
2490 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2491 { WESTON_OPTION_STRING, "seat", 0, &seat },
2492 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002493 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002494 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002495
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002496 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002497
Scott Moreau8ab5d452012-07-30 19:51:08 -06002498 wl_list_init(&configured_output_list);
2499
2500 const struct config_key drm_config_keys[] = {
2501 { "name", CONFIG_KEY_STRING, &output_name },
2502 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002503 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002504 };
2505
2506 const struct config_section config_section[] = {
2507 { "output", drm_config_keys,
2508 ARRAY_LENGTH(drm_config_keys), output_section_done },
2509 };
2510
2511 parse_config_file(config_file, config_section,
2512 ARRAY_LENGTH(config_section), NULL);
2513
Daniel Stonec1be8e52012-06-01 11:14:02 -04002514 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2515 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002516}