blob: d443c638782f3c340dce5fc47e40270315775da4 [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
938drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
939{
940 struct drm_output *output;
941 struct drm_mode *drm_mode;
942 int ret;
943 struct drm_compositor *ec;
944 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800945
946 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200947 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800948 return -1;
949 }
950
951 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200952 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800953 return -1;
954 }
955
956 ec = (struct drm_compositor *)output_base->compositor;
957 output = (struct drm_output *)output_base;
958 drm_mode = choose_mode (output, mode);
959
960 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200961 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800962 return -1;
963 } else if (&drm_mode->base == output->base.current) {
964 return 0;
965 } else if (drm_mode->base.width == output->base.current->width &&
966 drm_mode->base.height == output->base.current->height) {
967 /* only change refresh value */
968 ret = drmModeSetCrtc(ec->drm.fd,
969 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300970 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800971 &output->connector_id, 1, &drm_mode->mode_info);
972
973 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200974 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800975 drm_mode->base.width,
976 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400977 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800978 ret = -1;
979 } else {
980 output->base.current->flags = 0;
981 output->base.current = &drm_mode->base;
982 drm_mode->base.flags =
983 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
984 ret = 0;
985 }
986
987 return ret;
988 }
989
990 drm_mode->base.flags =
991 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
992
993 surface = gbm_surface_create(ec->gbm,
994 drm_mode->base.width,
995 drm_mode->base.height,
996 GBM_FORMAT_XRGB8888,
997 GBM_BO_USE_SCANOUT |
998 GBM_BO_USE_RENDERING);
999 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001000 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001001 return -1;
1002 }
1003
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001004 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +08001005
Ander Conselvan de Oliveira2e7a3ab2012-12-14 13:37:27 -02001006 if (gl_renderer_output_create(&output->base, surface) < 0) {
John Kåre Alsaker94659272012-11-13 19:10:18 +01001007 weston_log("failed to create renderer output\n");
1008 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +08001009 }
1010
Alex Wub7b8bda2012-04-17 17:20:48 +08001011 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001012 if (output->current) {
1013 if (output->current->is_client_buffer)
1014 gbm_bo_destroy(output->current->bo);
1015 else
1016 gbm_surface_release_buffer(output->surface,
1017 output->current->bo);
1018 }
1019 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001020
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001021 if (output->next) {
1022 if (output->next->is_client_buffer)
1023 gbm_bo_destroy(output->next->bo);
1024 else
1025 gbm_surface_release_buffer(output->surface,
1026 output->next->bo);
1027 }
1028 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001029
Alex Wub7b8bda2012-04-17 17:20:48 +08001030 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001031 output->surface = surface;
1032
1033 /*update output*/
1034 output->base.current = &drm_mode->base;
Alex Wub7b8bda2012-04-17 17:20:48 +08001035 return 0;
1036
John Kåre Alsaker94659272012-11-13 19:10:18 +01001037err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +08001038 gbm_surface_destroy(surface);
1039 return -1;
1040}
1041
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001042static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001043on_drm_input(int fd, uint32_t mask, void *data)
1044{
1045 drmEventContext evctx;
1046
1047 memset(&evctx, 0, sizeof evctx);
1048 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1049 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001050 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001051 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001052
1053 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001054}
1055
1056static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001057init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001058{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001059 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001060 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001061
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001062 sysnum = udev_device_get_sysnum(device);
1063 if (sysnum)
1064 ec->drm.id = atoi(sysnum);
1065 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001066 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001067 return -1;
1068 }
1069
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001070 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001071 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001072 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001073 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001074 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001075 udev_device_get_devnode(device));
1076 return -1;
1077 }
1078
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001079 weston_log("using %s\n", filename);
1080
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001081 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001082 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001083
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001084 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001085 NULL) < 0) {
1086 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001087 return -1;
1088 }
1089
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001090 return 0;
1091}
1092
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001093static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001094drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1095{
1096 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001097 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001098
1099 mode = malloc(sizeof *mode);
1100 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001101 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001102
1103 mode->base.flags = 0;
1104 mode->base.width = info->hdisplay;
1105 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001106
1107 /* Calculate higher precision (mHz) refresh rate */
1108 refresh = (info->clock * 1000000LL / info->htotal +
1109 info->vtotal / 2) / info->vtotal;
1110
1111 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1112 refresh *= 2;
1113 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1114 refresh /= 2;
1115 if (info->vscan > 1)
1116 refresh /= info->vscan;
1117
1118 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001119 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001120
1121 if (info->type & DRM_MODE_TYPE_PREFERRED)
1122 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1123
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001124 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1125
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001126 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001127}
1128
1129static int
1130drm_subpixel_to_wayland(int drm_value)
1131{
1132 switch (drm_value) {
1133 default:
1134 case DRM_MODE_SUBPIXEL_UNKNOWN:
1135 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1136 case DRM_MODE_SUBPIXEL_NONE:
1137 return WL_OUTPUT_SUBPIXEL_NONE;
1138 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1139 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1140 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1141 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1142 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1143 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1144 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1145 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1146 }
1147}
1148
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001149/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001150static uint32_t
1151drm_get_backlight(struct drm_output *output)
1152{
1153 long brightness, max_brightness, norm;
1154
1155 brightness = backlight_get_brightness(output->backlight);
1156 max_brightness = backlight_get_max_brightness(output->backlight);
1157
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001158 /* convert it on a scale of 0 to 255 */
1159 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001160
1161 return (uint32_t) norm;
1162}
1163
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001164/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001165static void
1166drm_set_backlight(struct weston_output *output_base, uint32_t value)
1167{
1168 struct drm_output *output = (struct drm_output *) output_base;
1169 long max_brightness, new_brightness;
1170
1171 if (!output->backlight)
1172 return;
1173
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001174 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001175 return;
1176
1177 max_brightness = backlight_get_max_brightness(output->backlight);
1178
1179 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001180 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001181
1182 backlight_set_brightness(output->backlight, new_brightness);
1183}
1184
1185static drmModePropertyPtr
1186drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1187{
1188 drmModePropertyPtr props;
1189 int i;
1190
1191 for (i = 0; i < connector->count_props; i++) {
1192 props = drmModeGetProperty(fd, connector->props[i]);
1193 if (!props)
1194 continue;
1195
1196 if (!strcmp(props->name, name))
1197 return props;
1198
1199 drmModeFreeProperty(props);
1200 }
1201
1202 return NULL;
1203}
1204
1205static void
1206drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1207{
1208 struct drm_output *output = (struct drm_output *) output_base;
1209 struct weston_compositor *ec = output_base->compositor;
1210 struct drm_compositor *c = (struct drm_compositor *) ec;
1211 drmModeConnectorPtr connector;
1212 drmModePropertyPtr prop;
1213
1214 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1215 if (!connector)
1216 return;
1217
1218 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1219 if (!prop) {
1220 drmModeFreeConnector(connector);
1221 return;
1222 }
1223
1224 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1225 prop->prop_id, level);
1226 drmModeFreeProperty(prop);
1227 drmModeFreeConnector(connector);
1228}
1229
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001230static const char *connector_type_names[] = {
1231 "None",
1232 "VGA",
1233 "DVI",
1234 "DVI",
1235 "DVI",
1236 "Composite",
1237 "TV",
1238 "LVDS",
1239 "CTV",
1240 "DIN",
1241 "DP",
1242 "HDMI",
1243 "HDMI",
1244 "TV",
1245 "eDP",
1246};
1247
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001248static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001249find_crtc_for_connector(struct drm_compositor *ec,
1250 drmModeRes *resources, drmModeConnector *connector)
1251{
1252 drmModeEncoder *encoder;
1253 uint32_t possible_crtcs;
1254 int i, j;
1255
1256 for (j = 0; j < connector->count_encoders; j++) {
1257 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1258 if (encoder == NULL) {
1259 weston_log("Failed to get encoder.\n");
1260 return -1;
1261 }
1262 possible_crtcs = encoder->possible_crtcs;
1263 drmModeFreeEncoder(encoder);
1264
1265 for (i = 0; i < resources->count_crtcs; i++) {
1266 if (possible_crtcs & (1 << i) &&
1267 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1268 return i;
1269 }
1270 }
1271
1272 return -1;
1273}
1274
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001275/* Init output state that depends on gl or gbm */
1276static int
1277drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1278{
1279 output->surface = gbm_surface_create(ec->gbm,
1280 output->base.current->width,
1281 output->base.current->height,
1282 GBM_FORMAT_XRGB8888,
1283 GBM_BO_USE_SCANOUT |
1284 GBM_BO_USE_RENDERING);
1285 if (!output->surface) {
1286 weston_log("failed to create gbm surface\n");
1287 return -1;
1288 }
1289
1290 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
1291 gbm_surface_destroy(output->surface);
1292 return -1;
1293 }
1294
1295 output->cursor_bo[0] =
1296 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1297 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1298 output->cursor_bo[1] =
1299 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1300 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1301 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1302 weston_log("cursor buffers unavailable, using gl cursors\n");
1303 ec->cursors_are_broken = 1;
1304 }
1305
1306 return 0;
1307}
1308
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001309static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001310create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001311 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001312 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001313 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001314{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001315 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001316 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1317 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001318 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001319 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001320 drmModeModeInfo crtc_mode;
1321 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001322 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001323 char name[32];
1324 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001325
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001326 i = find_crtc_for_connector(ec, resources, connector);
1327 if (i < 0) {
1328 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001329 return -1;
1330 }
1331
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001332 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001333 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001334 return -1;
1335
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001336 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001337 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1338 output->base.make = "unknown";
1339 output->base.model = "unknown";
1340 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001341
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001342 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1343 type_name = connector_type_names[connector->connector_type];
1344 else
1345 type_name = "UNKNOWN";
1346 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1347 output->name = strdup(name);
1348
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001349 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001350 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001351 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001352 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001353 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001354
Matt Roper361d2ad2011-08-29 13:52:23 -07001355 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1356
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001357 /* Get the current mode on the crtc that's currently driving
1358 * this connector. */
1359 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001360 memset(&crtc_mode, 0, sizeof crtc_mode);
1361 if (encoder != NULL) {
1362 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1363 drmModeFreeEncoder(encoder);
1364 if (crtc == NULL)
1365 goto err_free;
1366 if (crtc->mode_valid)
1367 crtc_mode = crtc->mode;
1368 drmModeFreeCrtc(crtc);
1369 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001370
David Herrmann0f0d54e2011-12-08 17:05:45 +01001371 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001372 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1373 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001374 goto err_free;
1375 }
1376
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001377 preferred = NULL;
1378 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001379 configured = NULL;
1380
1381 wl_list_for_each(temp, &configured_output_list, link) {
1382 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001383 if (temp->mode)
1384 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001385 temp->name, temp->mode);
1386 o = temp;
1387 break;
1388 }
1389 }
1390
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001391 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001392 weston_log("Disabling output %s\n", o->name);
1393
1394 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1395 0, 0, 0, 0, 0, NULL);
1396 goto err_free;
1397 }
1398
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001399 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001400 if (o && o->config == OUTPUT_CONFIG_MODE &&
1401 o->width == drm_mode->base.width &&
1402 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001403 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001404 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001405 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001406 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001407 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001408 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001409
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001410 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001411 configured = drm_output_add_mode(output, &o->crtc_mode);
1412 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001413 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001414 current = configured;
1415 }
1416
Wang Quanxianacb805a2012-07-30 18:09:46 -04001417 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001418 current = drm_output_add_mode(output, &crtc_mode);
1419 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001421 }
1422
Scott Moreau8ab5d452012-07-30 19:51:08 -06001423 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1424 configured = current;
1425
Wang Quanxianacb805a2012-07-30 18:09:46 -04001426 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001427 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001428 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001429 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001430 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001431 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001432 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001433 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001434
1435 if (output->base.current == NULL) {
1436 weston_log("no available modes for %s\n", output->name);
1437 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001438 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001439
Wang Quanxianacb805a2012-07-30 18:09:46 -04001440 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1441
John Kåre Alsaker94659272012-11-13 19:10:18 +01001442 weston_output_init(&output->base, &ec->base, x, y,
1443 connector->mmWidth, connector->mmHeight,
1444 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1445
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001446 if (drm_output_init_egl(output, ec) < 0) {
1447 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001448 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001449 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001450
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001451 output->backlight = backlight_init(drm_device,
1452 connector->connector_type);
1453 if (output->backlight) {
1454 output->base.set_backlight = drm_set_backlight;
1455 output->base.backlight_current = drm_get_backlight(output);
1456 }
1457
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001458 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1459
Alex Wubd3354b2012-04-17 17:20:49 +08001460 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001461 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001462 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001463 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001464 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001465 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001466
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001467 weston_plane_init(&output->cursor_plane, 0, 0);
1468 weston_plane_init(&output->fb_plane, 0, 0);
1469
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001470 weston_log("Output %s, (connector %d, crtc %d)\n",
1471 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001472 wl_list_for_each(m, &output->base.mode_list, link)
1473 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1474 m->width, m->height, m->refresh / 1000.0,
1475 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1476 ", preferred" : "",
1477 m->flags & WL_OUTPUT_MODE_CURRENT ?
1478 ", current" : "",
1479 connector->count_modes == 0 ?
1480 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001481
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001482 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001483
John Kåre Alsaker94659272012-11-13 19:10:18 +01001484err_output:
1485 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001486err_free:
1487 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1488 base.link) {
1489 wl_list_remove(&drm_mode->base.link);
1490 free(drm_mode);
1491 }
1492
1493 drmModeFreeCrtc(output->original_crtc);
1494 ec->crtc_allocator &= ~(1 << output->crtc_id);
1495 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001496 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001497 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001498
David Herrmann0f0d54e2011-12-08 17:05:45 +01001499 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001500}
1501
Jesse Barnes58ef3792012-02-23 09:45:49 -05001502static void
1503create_sprites(struct drm_compositor *ec)
1504{
1505 struct drm_sprite *sprite;
1506 drmModePlaneRes *plane_res;
1507 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001508 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001509
1510 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1511 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001512 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001513 strerror(errno));
1514 return;
1515 }
1516
1517 for (i = 0; i < plane_res->count_planes; i++) {
1518 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1519 if (!plane)
1520 continue;
1521
1522 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1523 plane->count_formats));
1524 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001525 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001526 __func__);
1527 free(plane);
1528 continue;
1529 }
1530
1531 memset(sprite, 0, sizeof *sprite);
1532
1533 sprite->possible_crtcs = plane->possible_crtcs;
1534 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001535 sprite->current = NULL;
1536 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001537 sprite->compositor = ec;
1538 sprite->count_formats = plane->count_formats;
1539 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001540 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001541 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001542 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001543
1544 wl_list_insert(&ec->sprite_list, &sprite->link);
1545 }
1546
1547 free(plane_res->planes);
1548 free(plane_res);
1549}
1550
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001551static void
1552destroy_sprites(struct drm_compositor *compositor)
1553{
1554 struct drm_sprite *sprite, *next;
1555 struct drm_output *output;
1556
1557 output = container_of(compositor->base.output_list.next,
1558 struct drm_output, base.link);
1559
1560 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1561 drmModeSetPlane(compositor->drm.fd,
1562 sprite->plane_id,
1563 output->crtc_id, 0, 0,
1564 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001565 if (sprite->current)
1566 gbm_bo_destroy(sprite->current->bo);
1567 if (sprite->next)
1568 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001569 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001570 free(sprite);
1571 }
1572}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001573
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001574static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001575create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001576 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001577{
1578 drmModeConnector *connector;
1579 drmModeRes *resources;
1580 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001581 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001582
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001583 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001584 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001585 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001586 return -1;
1587 }
1588
Jesse Barnes58ef3792012-02-23 09:45:49 -05001589 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001590 if (!ec->crtcs) {
1591 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001592 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001593 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001594
Rob Clark4339add2012-08-09 14:18:28 -05001595 ec->min_width = resources->min_width;
1596 ec->max_width = resources->max_width;
1597 ec->min_height = resources->min_height;
1598 ec->max_height = resources->max_height;
1599
Jesse Barnes58ef3792012-02-23 09:45:49 -05001600 ec->num_crtcs = resources->count_crtcs;
1601 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1602
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001603 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001604 connector = drmModeGetConnector(ec->drm.fd,
1605 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001606 if (connector == NULL)
1607 continue;
1608
1609 if (connector->connection == DRM_MODE_CONNECTED &&
1610 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001611 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001612 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001613 connector, x, y,
1614 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001615 drmModeFreeConnector(connector);
1616 continue;
1617 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001618
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001619 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001620 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001621 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001622 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001623
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001624 drmModeFreeConnector(connector);
1625 }
1626
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001627 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001628 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001629 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001630 return -1;
1631 }
1632
1633 drmModeFreeResources(resources);
1634
1635 return 0;
1636}
1637
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001638static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001639update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001640{
1641 drmModeConnector *connector;
1642 drmModeRes *resources;
1643 struct drm_output *output, *next;
1644 int x = 0, y = 0;
1645 int x_offset = 0, y_offset = 0;
1646 uint32_t connected = 0, disconnects = 0;
1647 int i;
1648
1649 resources = drmModeGetResources(ec->drm.fd);
1650 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001651 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001652 return;
1653 }
1654
1655 /* collect new connects */
1656 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001657 int connector_id = resources->connectors[i];
1658
1659 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001660 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001661 continue;
1662
David Herrmann7551cff2011-12-08 17:05:43 +01001663 if (connector->connection != DRM_MODE_CONNECTED) {
1664 drmModeFreeConnector(connector);
1665 continue;
1666 }
1667
Benjamin Franzke117483d2011-08-30 11:38:26 +02001668 connected |= (1 << connector_id);
1669
1670 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001671 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001672 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001673 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001674
1675 /* XXX: not yet needed, we die with 0 outputs */
1676 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001677 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001678 else
1679 x = 0;
1680 y = 0;
1681 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001682 connector, x, y,
1683 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001684 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001685
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001686 }
1687 drmModeFreeConnector(connector);
1688 }
1689 drmModeFreeResources(resources);
1690
1691 disconnects = ec->connector_allocator & ~connected;
1692 if (disconnects) {
1693 wl_list_for_each_safe(output, next, &ec->base.output_list,
1694 base.link) {
1695 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001696 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001697 output->base.x - x_offset,
1698 output->base.y - y_offset);
1699 }
1700
1701 if (disconnects & (1 << output->connector_id)) {
1702 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001703 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001704 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001705 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001706 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001707 }
1708 }
1709 }
1710
1711 /* FIXME: handle zero outputs, without terminating */
1712 if (ec->connector_allocator == 0)
1713 wl_display_terminate(ec->base.wl_display);
1714}
1715
1716static int
David Herrmannd7488c22012-03-11 20:05:21 +01001717udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001718{
David Herrmannd7488c22012-03-11 20:05:21 +01001719 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001720 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001721
1722 sysnum = udev_device_get_sysnum(device);
1723 if (!sysnum || atoi(sysnum) != ec->drm.id)
1724 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001725
David Herrmann6ac52db2012-03-11 20:05:22 +01001726 val = udev_device_get_property_value(device, "HOTPLUG");
1727 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001728 return 0;
1729
David Herrmann6ac52db2012-03-11 20:05:22 +01001730 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001731}
1732
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001733static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001734udev_drm_event(int fd, uint32_t mask, void *data)
1735{
1736 struct drm_compositor *ec = data;
1737 struct udev_device *event;
1738
1739 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001740
David Herrmannd7488c22012-03-11 20:05:21 +01001741 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001742 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001743
1744 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001745
1746 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001747}
1748
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001749static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001750drm_restore(struct weston_compositor *ec)
1751{
1752 struct drm_compositor *d = (struct drm_compositor *) ec;
1753
1754 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1755 weston_log("failed to drop master: %m\n");
1756 tty_reset(d->tty);
1757}
1758
Pekka Paalanen33156972012-08-03 13:30:30 -04001759static const char default_seat[] = "seat0";
1760
1761static void
1762device_added(struct udev_device *udev_device, struct drm_seat *master)
1763{
1764 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001765 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001766 const char *devnode;
1767 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001768 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001769 int fd;
1770
1771 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1772 if (!device_seat)
1773 device_seat = default_seat;
1774
1775 if (strcmp(device_seat, master->seat_id))
1776 return;
1777
1778 c = master->base.compositor;
1779 devnode = udev_device_get_devnode(udev_device);
1780
1781 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001782 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001783 * read. mtdev_get() also expects this. */
1784 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1785 if (fd < 0) {
1786 weston_log("opening input device '%s' failed.\n", devnode);
1787 return;
1788 }
1789
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001790 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001791 if (!device) {
1792 close(fd);
1793 weston_log("not using input device '%s'.\n", devnode);
1794 return;
1795 }
1796
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001797 calibration_values =
1798 udev_device_get_property_value(udev_device,
1799 "WL_CALIBRATION");
1800
1801 if (calibration_values && sscanf(calibration_values,
1802 "%f %f %f %f %f %f",
1803 &device->abs.calibration[0],
1804 &device->abs.calibration[1],
1805 &device->abs.calibration[2],
1806 &device->abs.calibration[3],
1807 &device->abs.calibration[4],
1808 &device->abs.calibration[5]) == 6) {
1809 device->abs.apply_calibration = 1;
1810 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1811 device->abs.calibration[0],
1812 device->abs.calibration[1],
1813 device->abs.calibration[2],
1814 device->abs.calibration[3],
1815 device->abs.calibration[4],
1816 device->abs.calibration[5]);
1817 }
1818
Pekka Paalanen33156972012-08-03 13:30:30 -04001819 wl_list_insert(master->devices_list.prev, &device->link);
1820}
1821
1822static void
1823evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1824{
1825 struct drm_seat *seat = (struct drm_seat *) seat_base;
1826 struct udev_enumerate *e;
1827 struct udev_list_entry *entry;
1828 struct udev_device *device;
1829 const char *path, *sysname;
1830
1831 e = udev_enumerate_new(udev);
1832 udev_enumerate_add_match_subsystem(e, "input");
1833 udev_enumerate_scan_devices(e);
1834 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1835 path = udev_list_entry_get_name(entry);
1836 device = udev_device_new_from_syspath(udev, path);
1837
1838 sysname = udev_device_get_sysname(device);
1839 if (strncmp("event", sysname, 5) != 0) {
1840 udev_device_unref(device);
1841 continue;
1842 }
1843
1844 device_added(device, seat);
1845
1846 udev_device_unref(device);
1847 }
1848 udev_enumerate_unref(e);
1849
1850 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1851
1852 if (wl_list_empty(&seat->devices_list)) {
1853 weston_log(
1854 "warning: no input devices on entering Weston. "
1855 "Possible causes:\n"
1856 "\t- no permissions to read /dev/input/event*\n"
1857 "\t- seats misconfigured "
1858 "(Weston backend option 'seat', "
1859 "udev device property ID_SEAT)\n");
1860 }
1861}
1862
1863static int
1864evdev_udev_handler(int fd, uint32_t mask, void *data)
1865{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001866 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001867 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001868 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001869 const char *action;
1870 const char *devnode;
1871
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001872 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001873 if (!udev_device)
1874 return 1;
1875
1876 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001877 if (!action)
1878 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001879
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001880 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1881 goto out;
1882
1883 if (!strcmp(action, "add")) {
1884 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001885 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001886 else if (!strcmp(action, "remove")) {
1887 devnode = udev_device_get_devnode(udev_device);
1888 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1889 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001890 weston_log("input device %s, %s removed\n",
1891 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001892 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001893 break;
1894 }
1895 }
1896
1897out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001898 udev_device_unref(udev_device);
1899
1900 return 0;
1901}
1902
1903static int
1904evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1905{
1906 struct drm_seat *master = (struct drm_seat *) seat_base;
1907 struct wl_event_loop *loop;
1908 struct weston_compositor *c = master->base.compositor;
1909 int fd;
1910
1911 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1912 if (!master->udev_monitor) {
1913 weston_log("udev: failed to create the udev monitor\n");
1914 return 0;
1915 }
1916
1917 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1918 "input", NULL);
1919
1920 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1921 weston_log("udev: failed to bind the udev monitor\n");
1922 udev_monitor_unref(master->udev_monitor);
1923 return 0;
1924 }
1925
1926 loop = wl_display_get_event_loop(c->wl_display);
1927 fd = udev_monitor_get_fd(master->udev_monitor);
1928 master->udev_monitor_source =
1929 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1930 evdev_udev_handler, master);
1931 if (!master->udev_monitor_source) {
1932 udev_monitor_unref(master->udev_monitor);
1933 return 0;
1934 }
1935
1936 return 1;
1937}
1938
1939static void
1940evdev_disable_udev_monitor(struct weston_seat *seat_base)
1941{
1942 struct drm_seat *seat = (struct drm_seat *) seat_base;
1943
1944 if (!seat->udev_monitor)
1945 return;
1946
1947 udev_monitor_unref(seat->udev_monitor);
1948 seat->udev_monitor = NULL;
1949 wl_event_source_remove(seat->udev_monitor_source);
1950 seat->udev_monitor_source = NULL;
1951}
1952
1953static void
1954drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1955{
1956 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001957 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001958
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001959 wl_list_for_each(device, &seat->devices_list, link)
1960 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001961}
1962
1963static void
1964evdev_input_create(struct weston_compositor *c, struct udev *udev,
1965 const char *seat_id)
1966{
1967 struct drm_seat *seat;
1968
1969 seat = malloc(sizeof *seat);
1970 if (seat == NULL)
1971 return;
1972
1973 memset(seat, 0, sizeof *seat);
1974 weston_seat_init(&seat->base, c);
1975 seat->base.led_update = drm_led_update;
1976
1977 wl_list_init(&seat->devices_list);
1978 seat->seat_id = strdup(seat_id);
1979 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1980 free(seat->seat_id);
1981 free(seat);
1982 return;
1983 }
1984
1985 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001986}
1987
1988static void
1989evdev_remove_devices(struct weston_seat *seat_base)
1990{
1991 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001992 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001993
1994 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001995 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001996
Pekka Paalanend8583512012-08-03 14:39:11 +03001997 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001998 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001999}
2000
2001static void
2002evdev_input_destroy(struct weston_seat *seat_base)
2003{
2004 struct drm_seat *seat = (struct drm_seat *) seat_base;
2005
2006 evdev_remove_devices(seat_base);
2007 evdev_disable_udev_monitor(&seat->base);
2008
2009 weston_seat_release(seat_base);
2010 free(seat->seat_id);
2011 free(seat);
2012}
2013
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002014static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002015drm_free_configured_output(struct drm_configured_output *output)
2016{
2017 free(output->name);
2018 free(output->mode);
2019 free(output);
2020}
2021
2022static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002023drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002024{
2025 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002026 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002027 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002028
Daniel Stone37816df2012-05-16 18:45:18 +01002029 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2030 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002031 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002032 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002033
2034 wl_event_source_remove(d->udev_drm_source);
2035 wl_event_source_remove(d->drm_source);
2036
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002037 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002038
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002039 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002040
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002041 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002042 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002043 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002044 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002045 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002046
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002047 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002048}
2049
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002050static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002051drm_compositor_set_modes(struct drm_compositor *compositor)
2052{
2053 struct drm_output *output;
2054 struct drm_mode *drm_mode;
2055 int ret;
2056
2057 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2058 drm_mode = (struct drm_mode *) output->base.current;
2059 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002060 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002061 &output->connector_id, 1,
2062 &drm_mode->mode_info);
2063 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002064 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002065 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002066 drm_mode->base.width, drm_mode->base.height,
2067 output->base.x, output->base.y);
2068 }
2069 }
2070}
2071
2072static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002073vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002074{
2075 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002076 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002077 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002078 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002079
2080 switch (event) {
2081 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002082 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002083 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002084 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002085 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002086 wl_display_terminate(compositor->wl_display);
2087 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002088 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002089 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002090 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002091 wl_list_for_each(seat, &compositor->seat_list, link) {
2092 evdev_add_devices(ec->udev, seat);
2093 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002094 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002095 break;
2096 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002097 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002098 wl_list_for_each(seat, &compositor->seat_list, link) {
2099 evdev_disable_udev_monitor(seat);
2100 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002101 }
2102
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002103 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002104 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002105 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002106
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002107 /* If we have a repaint scheduled (either from a
2108 * pending pageflip or the idle handler), make sure we
2109 * cancel that so we don't try to pageflip when we're
2110 * vt switched away. The SLEEPING state will prevent
2111 * further attemps at repainting. When we switch
2112 * back, we schedule a repaint, which will process
2113 * pending frame callbacks. */
2114
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002115 wl_list_for_each(output, &ec->base.output_list, base.link) {
2116 output->base.repaint_needed = 0;
2117 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002118 }
2119
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002120 output = container_of(ec->base.output_list.next,
2121 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002122
2123 wl_list_for_each(sprite, &ec->sprite_list, link)
2124 drmModeSetPlane(ec->drm.fd,
2125 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002126 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002127 0, 0, 0, 0, 0, 0, 0, 0);
2128
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002129 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002130 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002131
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002132 break;
2133 };
2134}
2135
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002136static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002137switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002138{
2139 struct drm_compositor *ec = data;
2140
Daniel Stone325fc2d2012-05-30 16:31:58 +01002141 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002142}
2143
David Herrmann0af066f2012-10-29 19:21:16 +01002144/*
2145 * Find primary GPU
2146 * Some systems may have multiple DRM devices attached to a single seat. This
2147 * function loops over all devices and tries to find a PCI device with the
2148 * boot_vga sysfs attribute set to 1.
2149 * If no such device is found, the first DRM device reported by udev is used.
2150 */
2151static struct udev_device*
2152find_primary_gpu(struct drm_compositor *ec, const char *seat)
2153{
2154 struct udev_enumerate *e;
2155 struct udev_list_entry *entry;
2156 const char *path, *device_seat, *id;
2157 struct udev_device *device, *drm_device, *pci;
2158
2159 e = udev_enumerate_new(ec->udev);
2160 udev_enumerate_add_match_subsystem(e, "drm");
2161 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2162
2163 udev_enumerate_scan_devices(e);
2164 drm_device = NULL;
2165 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2166 path = udev_list_entry_get_name(entry);
2167 device = udev_device_new_from_syspath(ec->udev, path);
2168 if (!device)
2169 continue;
2170 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2171 if (!device_seat)
2172 device_seat = default_seat;
2173 if (strcmp(device_seat, seat)) {
2174 udev_device_unref(device);
2175 continue;
2176 }
2177
2178 pci = udev_device_get_parent_with_subsystem_devtype(device,
2179 "pci", NULL);
2180 if (pci) {
2181 id = udev_device_get_sysattr_value(pci, "boot_vga");
2182 if (id && !strcmp(id, "1")) {
2183 if (drm_device)
2184 udev_device_unref(drm_device);
2185 drm_device = device;
2186 break;
2187 }
2188 }
2189
2190 if (!drm_device)
2191 drm_device = device;
2192 else
2193 udev_device_unref(device);
2194 }
2195
2196 udev_enumerate_unref(e);
2197 return drm_device;
2198}
2199
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002200static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002201planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002202{
2203 struct drm_compositor *c = data;
2204
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002205 switch (key) {
2206 case KEY_C:
2207 c->cursors_are_broken ^= 1;
2208 break;
2209 case KEY_V:
2210 c->sprites_are_broken ^= 1;
2211 break;
2212 case KEY_O:
2213 c->sprites_hidden ^= 1;
2214 break;
2215 default:
2216 break;
2217 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002218}
2219
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002220static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002221drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002222 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002223 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002224{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002225 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002226 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002227 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002228 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002229 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002230 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002231
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002232 weston_log("initializing drm backend\n");
2233
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002234 ec = malloc(sizeof *ec);
2235 if (ec == NULL)
2236 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002237 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002238
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002239 /* KMS support for sprites is not complete yet, so disable the
2240 * functionality for now. */
2241 ec->sprites_are_broken = 1;
2242
Daniel Stone725c2c32012-06-22 14:04:36 +01002243 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002244 config_file) < 0) {
2245 weston_log("weston_compositor_init failed\n");
2246 goto err_base;
2247 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002248
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002249 ec->udev = udev_new();
2250 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002251 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002252 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002253 }
2254
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002255 ec->base.wl_display = display;
2256 ec->tty = tty_create(&ec->base, vt_func, tty);
2257 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002258 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002259 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002260 }
2261
David Herrmann0af066f2012-10-29 19:21:16 +01002262 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002263 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002264 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002265 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002266 }
David Herrmann0af066f2012-10-29 19:21:16 +01002267 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002268
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002269 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002270 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002271 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002272 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002273
2274 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002275 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002276
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002277 ec->base.focus = 1;
2278
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002279 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002280
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002281 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002282 weston_compositor_add_key_binding(&ec->base, key,
2283 MODIFIER_CTRL | MODIFIER_ALT,
2284 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002285
Jesse Barnes58ef3792012-02-23 09:45:49 -05002286 wl_list_init(&ec->sprite_list);
2287 create_sprites(ec);
2288
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002289 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002290 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002291 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002292 }
2293
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002294 path = NULL;
2295
Tiago Vignattice03ec32011-12-19 01:14:03 +02002296 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002297
2298 loop = wl_display_get_event_loop(ec->base.wl_display);
2299 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002300 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002301 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002302
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002303 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2304 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002305 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002306 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002307 }
2308 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2309 "drm", NULL);
2310 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002311 wl_event_loop_add_fd(loop,
2312 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002313 WL_EVENT_READABLE, udev_drm_event, ec);
2314
2315 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002316 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002317 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002318 }
2319
Daniel Stonea96b93c2012-06-22 14:04:37 +01002320 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002321
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002322 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002323 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002324 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002325 planes_binding, ec);
2326 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2327 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002328
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002329 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002330
2331err_udev_monitor:
2332 wl_event_source_remove(ec->udev_drm_source);
2333 udev_monitor_unref(ec->udev_monitor);
2334err_drm_source:
2335 wl_event_source_remove(ec->drm_source);
2336 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2337 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002338err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002339 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002340 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002341 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002342err_udev_dev:
2343 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002344err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002345 tty_destroy(ec->tty);
2346err_udev:
2347 udev_unref(ec->udev);
2348err_compositor:
2349 weston_compositor_shutdown(&ec->base);
2350err_base:
2351 free(ec);
2352 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002353}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002354
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002355static int
2356set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2357{
2358 mode->flags = 0;
2359
2360 if (strcmp(hsync, "+hsync") == 0)
2361 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2362 else if (strcmp(hsync, "-hsync") == 0)
2363 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2364 else
2365 return -1;
2366
2367 if (strcmp(vsync, "+vsync") == 0)
2368 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2369 else if (strcmp(vsync, "-vsync") == 0)
2370 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2371 else
2372 return -1;
2373
2374 return 0;
2375}
2376
2377static int
2378check_for_modeline(struct drm_configured_output *output)
2379{
2380 drmModeModeInfo mode;
2381 char hsync[16];
2382 char vsync[16];
2383 char mode_name[16];
2384 float fclock;
2385
2386 mode.type = DRM_MODE_TYPE_USERDEF;
2387 mode.hskew = 0;
2388 mode.vscan = 0;
2389 mode.vrefresh = 0;
2390
2391 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2392 &fclock, &mode.hdisplay,
2393 &mode.hsync_start,
2394 &mode.hsync_end, &mode.htotal,
2395 &mode.vdisplay,
2396 &mode.vsync_start,
2397 &mode.vsync_end, &mode.vtotal,
2398 hsync, vsync) == 11) {
2399 if (set_sync_flags(&mode, hsync, vsync))
2400 return -1;
2401
2402 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2403 strcpy(mode.name, mode_name);
2404
2405 mode.clock = fclock * 1000;
2406 } else
2407 return -1;
2408
2409 output->crtc_mode = mode;
2410
2411 return 0;
2412}
2413
Scott Moreau8ab5d452012-07-30 19:51:08 -06002414static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002415drm_output_set_transform(struct drm_configured_output *output)
2416{
2417 if (!output_transform) {
2418 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2419 return;
2420 }
2421
2422 if (!strcmp(output_transform, "normal"))
2423 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2424 else if (!strcmp(output_transform, "90"))
2425 output->transform = WL_OUTPUT_TRANSFORM_90;
2426 else if (!strcmp(output_transform, "180"))
2427 output->transform = WL_OUTPUT_TRANSFORM_180;
2428 else if (!strcmp(output_transform, "270"))
2429 output->transform = WL_OUTPUT_TRANSFORM_270;
2430 else if (!strcmp(output_transform, "flipped"))
2431 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2432 else if (!strcmp(output_transform, "flipped-90"))
2433 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2434 else if (!strcmp(output_transform, "flipped-180"))
2435 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2436 else if (!strcmp(output_transform, "flipped-270"))
2437 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2438 else {
2439 weston_log("Invalid transform \"%s\" for output %s\n",
2440 output_transform, output_name);
2441 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2442 }
2443
2444 free(output_transform);
2445 output_transform = NULL;
2446}
2447
2448static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002449output_section_done(void *data)
2450{
2451 struct drm_configured_output *output;
2452
2453 output = malloc(sizeof *output);
2454
Scott Moreau1bad5db2012-08-18 01:04:05 -06002455 if (!output || !output_name || (output_name[0] == 'X') ||
2456 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002457 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002458 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002459 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002460 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002461 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002462 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002463 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002464 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002465 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002466
2467 output->config = OUTPUT_CONFIG_INVALID;
2468 output->name = output_name;
2469 output->mode = output_mode;
2470
Scott Moreau1bad5db2012-08-18 01:04:05 -06002471 if (output_mode) {
2472 if (strcmp(output_mode, "off") == 0)
2473 output->config = OUTPUT_CONFIG_OFF;
2474 else if (strcmp(output_mode, "preferred") == 0)
2475 output->config = OUTPUT_CONFIG_PREFERRED;
2476 else if (strcmp(output_mode, "current") == 0)
2477 output->config = OUTPUT_CONFIG_CURRENT;
2478 else if (sscanf(output_mode, "%dx%d",
2479 &output->width, &output->height) == 2)
2480 output->config = OUTPUT_CONFIG_MODE;
2481 else if (check_for_modeline(output) == 0)
2482 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002483
Scott Moreau1bad5db2012-08-18 01:04:05 -06002484 if (output->config == OUTPUT_CONFIG_INVALID)
2485 weston_log("Invalid mode \"%s\" for output %s\n",
2486 output_mode, output_name);
2487 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002488 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002489
2490 drm_output_set_transform(output);
2491
2492 wl_list_insert(&configured_output_list, &output->link);
2493
2494 if (output_transform)
2495 free(output_transform);
2496 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002497}
2498
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002499WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002500backend_init(struct wl_display *display, int argc, char *argv[],
2501 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002502{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002503 int connector = 0, tty = 0;
2504 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002505
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002506 const struct weston_option drm_options[] = {
2507 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2508 { WESTON_OPTION_STRING, "seat", 0, &seat },
2509 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002510 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002511 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002512
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002513 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002514
Scott Moreau8ab5d452012-07-30 19:51:08 -06002515 wl_list_init(&configured_output_list);
2516
2517 const struct config_key drm_config_keys[] = {
2518 { "name", CONFIG_KEY_STRING, &output_name },
2519 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002520 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002521 };
2522
2523 const struct config_section config_section[] = {
2524 { "output", drm_config_keys,
2525 ARRAY_LENGTH(drm_config_keys), output_section_done },
2526 };
2527
2528 parse_config_file(config_file, config_section,
2529 ARRAY_LENGTH(config_section), NULL);
2530
Daniel Stonec1be8e52012-06-01 11:14:02 -04002531 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2532 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002533}