blob: 1aec473a59401822d39e6725d599f7285ea9e949 [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
1275static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001276create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001277 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001278 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001279 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001280{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001281 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001282 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1283 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001284 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001285 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001286 drmModeModeInfo crtc_mode;
1287 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001288 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001289 char name[32];
1290 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001291
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001292 i = find_crtc_for_connector(ec, resources, connector);
1293 if (i < 0) {
1294 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001295 return -1;
1296 }
1297
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001298 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001299 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001300 return -1;
1301
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001302 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001303 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1304 output->base.make = "unknown";
1305 output->base.model = "unknown";
1306 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001307
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001308 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1309 type_name = connector_type_names[connector->connector_type];
1310 else
1311 type_name = "UNKNOWN";
1312 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1313 output->name = strdup(name);
1314
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001315 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001316 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001317 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001318 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001319 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001320
Matt Roper361d2ad2011-08-29 13:52:23 -07001321 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1322
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001323 /* Get the current mode on the crtc that's currently driving
1324 * this connector. */
1325 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001326 memset(&crtc_mode, 0, sizeof crtc_mode);
1327 if (encoder != NULL) {
1328 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1329 drmModeFreeEncoder(encoder);
1330 if (crtc == NULL)
1331 goto err_free;
1332 if (crtc->mode_valid)
1333 crtc_mode = crtc->mode;
1334 drmModeFreeCrtc(crtc);
1335 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001336
David Herrmann0f0d54e2011-12-08 17:05:45 +01001337 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001338 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1339 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001340 goto err_free;
1341 }
1342
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001343 preferred = NULL;
1344 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001345 configured = NULL;
1346
1347 wl_list_for_each(temp, &configured_output_list, link) {
1348 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001349 if (temp->mode)
1350 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001351 temp->name, temp->mode);
1352 o = temp;
1353 break;
1354 }
1355 }
1356
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001357 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001358 weston_log("Disabling output %s\n", o->name);
1359
1360 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1361 0, 0, 0, 0, 0, NULL);
1362 goto err_free;
1363 }
1364
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001365 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001366 if (o && o->config == OUTPUT_CONFIG_MODE &&
1367 o->width == drm_mode->base.width &&
1368 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001369 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001370 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001371 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001372 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001373 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001374 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001375
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001376 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001377 configured = drm_output_add_mode(output, &o->crtc_mode);
1378 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001379 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001380 current = configured;
1381 }
1382
Wang Quanxianacb805a2012-07-30 18:09:46 -04001383 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001384 current = drm_output_add_mode(output, &crtc_mode);
1385 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001386 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001387 }
1388
Scott Moreau8ab5d452012-07-30 19:51:08 -06001389 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1390 configured = current;
1391
Wang Quanxianacb805a2012-07-30 18:09:46 -04001392 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001393 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001394 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001395 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001396 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001397 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001398 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001399 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001400
1401 if (output->base.current == NULL) {
1402 weston_log("no available modes for %s\n", output->name);
1403 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001404 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001405
Wang Quanxianacb805a2012-07-30 18:09:46 -04001406 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1407
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001408 output->surface = gbm_surface_create(ec->gbm,
1409 output->base.current->width,
1410 output->base.current->height,
1411 GBM_FORMAT_XRGB8888,
1412 GBM_BO_USE_SCANOUT |
1413 GBM_BO_USE_RENDERING);
1414 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001415 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001416 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001417 }
1418
John Kåre Alsaker94659272012-11-13 19:10:18 +01001419 weston_output_init(&output->base, &ec->base, x, y,
1420 connector->mmWidth, connector->mmHeight,
1421 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1422
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001423 if (gl_renderer_output_create(&output->base, output->surface) < 0)
John Kåre Alsaker94659272012-11-13 19:10:18 +01001424 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001425
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001426 output->cursor_bo[0] =
1427 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1428 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1429 output->cursor_bo[1] =
1430 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1431 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001432 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1433 weston_log("cursor buffers unavailable, using gl cursors\n");
1434 ec->cursors_are_broken = 1;
1435 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001436
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001437 output->backlight = backlight_init(drm_device,
1438 connector->connector_type);
1439 if (output->backlight) {
1440 output->base.set_backlight = drm_set_backlight;
1441 output->base.backlight_current = drm_get_backlight(output);
1442 }
1443
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001444 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1445
Alex Wubd3354b2012-04-17 17:20:49 +08001446 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001447 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001448 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001449 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001450 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001451 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001452
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001453 weston_plane_init(&output->cursor_plane, 0, 0);
1454 weston_plane_init(&output->fb_plane, 0, 0);
1455
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001456 weston_log("Output %s, (connector %d, crtc %d)\n",
1457 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001458 wl_list_for_each(m, &output->base.mode_list, link)
1459 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1460 m->width, m->height, m->refresh / 1000.0,
1461 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1462 ", preferred" : "",
1463 m->flags & WL_OUTPUT_MODE_CURRENT ?
1464 ", current" : "",
1465 connector->count_modes == 0 ?
1466 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001467
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001468 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001469
John Kåre Alsaker94659272012-11-13 19:10:18 +01001470err_output:
1471 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001472 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001473err_free:
1474 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1475 base.link) {
1476 wl_list_remove(&drm_mode->base.link);
1477 free(drm_mode);
1478 }
1479
1480 drmModeFreeCrtc(output->original_crtc);
1481 ec->crtc_allocator &= ~(1 << output->crtc_id);
1482 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001483 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001484 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001485
David Herrmann0f0d54e2011-12-08 17:05:45 +01001486 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001487}
1488
Jesse Barnes58ef3792012-02-23 09:45:49 -05001489static void
1490create_sprites(struct drm_compositor *ec)
1491{
1492 struct drm_sprite *sprite;
1493 drmModePlaneRes *plane_res;
1494 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001495 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001496
1497 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1498 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001499 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001500 strerror(errno));
1501 return;
1502 }
1503
1504 for (i = 0; i < plane_res->count_planes; i++) {
1505 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1506 if (!plane)
1507 continue;
1508
1509 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1510 plane->count_formats));
1511 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001512 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001513 __func__);
1514 free(plane);
1515 continue;
1516 }
1517
1518 memset(sprite, 0, sizeof *sprite);
1519
1520 sprite->possible_crtcs = plane->possible_crtcs;
1521 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001522 sprite->current = NULL;
1523 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001524 sprite->compositor = ec;
1525 sprite->count_formats = plane->count_formats;
1526 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001527 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001528 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001529 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001530
1531 wl_list_insert(&ec->sprite_list, &sprite->link);
1532 }
1533
1534 free(plane_res->planes);
1535 free(plane_res);
1536}
1537
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001538static void
1539destroy_sprites(struct drm_compositor *compositor)
1540{
1541 struct drm_sprite *sprite, *next;
1542 struct drm_output *output;
1543
1544 output = container_of(compositor->base.output_list.next,
1545 struct drm_output, base.link);
1546
1547 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1548 drmModeSetPlane(compositor->drm.fd,
1549 sprite->plane_id,
1550 output->crtc_id, 0, 0,
1551 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001552 if (sprite->current)
1553 gbm_bo_destroy(sprite->current->bo);
1554 if (sprite->next)
1555 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001556 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001557 free(sprite);
1558 }
1559}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001560
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001561static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001562create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001563 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001564{
1565 drmModeConnector *connector;
1566 drmModeRes *resources;
1567 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001568 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001569
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001570 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001571 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001572 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001573 return -1;
1574 }
1575
Jesse Barnes58ef3792012-02-23 09:45:49 -05001576 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001577 if (!ec->crtcs) {
1578 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001579 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001580 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001581
Rob Clark4339add2012-08-09 14:18:28 -05001582 ec->min_width = resources->min_width;
1583 ec->max_width = resources->max_width;
1584 ec->min_height = resources->min_height;
1585 ec->max_height = resources->max_height;
1586
Jesse Barnes58ef3792012-02-23 09:45:49 -05001587 ec->num_crtcs = resources->count_crtcs;
1588 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1589
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001590 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001591 connector = drmModeGetConnector(ec->drm.fd,
1592 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001593 if (connector == NULL)
1594 continue;
1595
1596 if (connector->connection == DRM_MODE_CONNECTED &&
1597 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001598 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001599 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001600 connector, x, y,
1601 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001602 drmModeFreeConnector(connector);
1603 continue;
1604 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001605
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001606 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001607 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001608 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001609 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001610
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001611 drmModeFreeConnector(connector);
1612 }
1613
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001614 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001615 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001616 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001617 return -1;
1618 }
1619
1620 drmModeFreeResources(resources);
1621
1622 return 0;
1623}
1624
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001625static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001626update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001627{
1628 drmModeConnector *connector;
1629 drmModeRes *resources;
1630 struct drm_output *output, *next;
1631 int x = 0, y = 0;
1632 int x_offset = 0, y_offset = 0;
1633 uint32_t connected = 0, disconnects = 0;
1634 int i;
1635
1636 resources = drmModeGetResources(ec->drm.fd);
1637 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001638 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001639 return;
1640 }
1641
1642 /* collect new connects */
1643 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001644 int connector_id = resources->connectors[i];
1645
1646 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001647 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001648 continue;
1649
David Herrmann7551cff2011-12-08 17:05:43 +01001650 if (connector->connection != DRM_MODE_CONNECTED) {
1651 drmModeFreeConnector(connector);
1652 continue;
1653 }
1654
Benjamin Franzke117483d2011-08-30 11:38:26 +02001655 connected |= (1 << connector_id);
1656
1657 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001658 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001659 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001660 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001661
1662 /* XXX: not yet needed, we die with 0 outputs */
1663 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001664 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001665 else
1666 x = 0;
1667 y = 0;
1668 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001669 connector, x, y,
1670 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001671 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001672
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001673 }
1674 drmModeFreeConnector(connector);
1675 }
1676 drmModeFreeResources(resources);
1677
1678 disconnects = ec->connector_allocator & ~connected;
1679 if (disconnects) {
1680 wl_list_for_each_safe(output, next, &ec->base.output_list,
1681 base.link) {
1682 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001683 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001684 output->base.x - x_offset,
1685 output->base.y - y_offset);
1686 }
1687
1688 if (disconnects & (1 << output->connector_id)) {
1689 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001690 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001691 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001692 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001693 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001694 }
1695 }
1696 }
1697
1698 /* FIXME: handle zero outputs, without terminating */
1699 if (ec->connector_allocator == 0)
1700 wl_display_terminate(ec->base.wl_display);
1701}
1702
1703static int
David Herrmannd7488c22012-03-11 20:05:21 +01001704udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001705{
David Herrmannd7488c22012-03-11 20:05:21 +01001706 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001707 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001708
1709 sysnum = udev_device_get_sysnum(device);
1710 if (!sysnum || atoi(sysnum) != ec->drm.id)
1711 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001712
David Herrmann6ac52db2012-03-11 20:05:22 +01001713 val = udev_device_get_property_value(device, "HOTPLUG");
1714 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001715 return 0;
1716
David Herrmann6ac52db2012-03-11 20:05:22 +01001717 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001718}
1719
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001720static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001721udev_drm_event(int fd, uint32_t mask, void *data)
1722{
1723 struct drm_compositor *ec = data;
1724 struct udev_device *event;
1725
1726 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001727
David Herrmannd7488c22012-03-11 20:05:21 +01001728 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001729 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001730
1731 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001732
1733 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001734}
1735
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001736static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001737drm_restore(struct weston_compositor *ec)
1738{
1739 struct drm_compositor *d = (struct drm_compositor *) ec;
1740
1741 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1742 weston_log("failed to drop master: %m\n");
1743 tty_reset(d->tty);
1744}
1745
Pekka Paalanen33156972012-08-03 13:30:30 -04001746static const char default_seat[] = "seat0";
1747
1748static void
1749device_added(struct udev_device *udev_device, struct drm_seat *master)
1750{
1751 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001752 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001753 const char *devnode;
1754 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001755 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001756 int fd;
1757
1758 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1759 if (!device_seat)
1760 device_seat = default_seat;
1761
1762 if (strcmp(device_seat, master->seat_id))
1763 return;
1764
1765 c = master->base.compositor;
1766 devnode = udev_device_get_devnode(udev_device);
1767
1768 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001769 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001770 * read. mtdev_get() also expects this. */
1771 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1772 if (fd < 0) {
1773 weston_log("opening input device '%s' failed.\n", devnode);
1774 return;
1775 }
1776
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001777 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001778 if (!device) {
1779 close(fd);
1780 weston_log("not using input device '%s'.\n", devnode);
1781 return;
1782 }
1783
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001784 calibration_values =
1785 udev_device_get_property_value(udev_device,
1786 "WL_CALIBRATION");
1787
1788 if (calibration_values && sscanf(calibration_values,
1789 "%f %f %f %f %f %f",
1790 &device->abs.calibration[0],
1791 &device->abs.calibration[1],
1792 &device->abs.calibration[2],
1793 &device->abs.calibration[3],
1794 &device->abs.calibration[4],
1795 &device->abs.calibration[5]) == 6) {
1796 device->abs.apply_calibration = 1;
1797 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1798 device->abs.calibration[0],
1799 device->abs.calibration[1],
1800 device->abs.calibration[2],
1801 device->abs.calibration[3],
1802 device->abs.calibration[4],
1803 device->abs.calibration[5]);
1804 }
1805
Pekka Paalanen33156972012-08-03 13:30:30 -04001806 wl_list_insert(master->devices_list.prev, &device->link);
1807}
1808
1809static void
1810evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1811{
1812 struct drm_seat *seat = (struct drm_seat *) seat_base;
1813 struct udev_enumerate *e;
1814 struct udev_list_entry *entry;
1815 struct udev_device *device;
1816 const char *path, *sysname;
1817
1818 e = udev_enumerate_new(udev);
1819 udev_enumerate_add_match_subsystem(e, "input");
1820 udev_enumerate_scan_devices(e);
1821 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1822 path = udev_list_entry_get_name(entry);
1823 device = udev_device_new_from_syspath(udev, path);
1824
1825 sysname = udev_device_get_sysname(device);
1826 if (strncmp("event", sysname, 5) != 0) {
1827 udev_device_unref(device);
1828 continue;
1829 }
1830
1831 device_added(device, seat);
1832
1833 udev_device_unref(device);
1834 }
1835 udev_enumerate_unref(e);
1836
1837 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1838
1839 if (wl_list_empty(&seat->devices_list)) {
1840 weston_log(
1841 "warning: no input devices on entering Weston. "
1842 "Possible causes:\n"
1843 "\t- no permissions to read /dev/input/event*\n"
1844 "\t- seats misconfigured "
1845 "(Weston backend option 'seat', "
1846 "udev device property ID_SEAT)\n");
1847 }
1848}
1849
1850static int
1851evdev_udev_handler(int fd, uint32_t mask, void *data)
1852{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001853 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001854 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001855 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001856 const char *action;
1857 const char *devnode;
1858
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001859 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001860 if (!udev_device)
1861 return 1;
1862
1863 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001864 if (!action)
1865 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001866
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001867 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1868 goto out;
1869
1870 if (!strcmp(action, "add")) {
1871 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001872 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001873 else if (!strcmp(action, "remove")) {
1874 devnode = udev_device_get_devnode(udev_device);
1875 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1876 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001877 weston_log("input device %s, %s removed\n",
1878 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001879 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001880 break;
1881 }
1882 }
1883
1884out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001885 udev_device_unref(udev_device);
1886
1887 return 0;
1888}
1889
1890static int
1891evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1892{
1893 struct drm_seat *master = (struct drm_seat *) seat_base;
1894 struct wl_event_loop *loop;
1895 struct weston_compositor *c = master->base.compositor;
1896 int fd;
1897
1898 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1899 if (!master->udev_monitor) {
1900 weston_log("udev: failed to create the udev monitor\n");
1901 return 0;
1902 }
1903
1904 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1905 "input", NULL);
1906
1907 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1908 weston_log("udev: failed to bind the udev monitor\n");
1909 udev_monitor_unref(master->udev_monitor);
1910 return 0;
1911 }
1912
1913 loop = wl_display_get_event_loop(c->wl_display);
1914 fd = udev_monitor_get_fd(master->udev_monitor);
1915 master->udev_monitor_source =
1916 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1917 evdev_udev_handler, master);
1918 if (!master->udev_monitor_source) {
1919 udev_monitor_unref(master->udev_monitor);
1920 return 0;
1921 }
1922
1923 return 1;
1924}
1925
1926static void
1927evdev_disable_udev_monitor(struct weston_seat *seat_base)
1928{
1929 struct drm_seat *seat = (struct drm_seat *) seat_base;
1930
1931 if (!seat->udev_monitor)
1932 return;
1933
1934 udev_monitor_unref(seat->udev_monitor);
1935 seat->udev_monitor = NULL;
1936 wl_event_source_remove(seat->udev_monitor_source);
1937 seat->udev_monitor_source = NULL;
1938}
1939
1940static void
1941drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1942{
1943 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001944 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001945
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001946 wl_list_for_each(device, &seat->devices_list, link)
1947 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001948}
1949
1950static void
1951evdev_input_create(struct weston_compositor *c, struct udev *udev,
1952 const char *seat_id)
1953{
1954 struct drm_seat *seat;
1955
1956 seat = malloc(sizeof *seat);
1957 if (seat == NULL)
1958 return;
1959
1960 memset(seat, 0, sizeof *seat);
1961 weston_seat_init(&seat->base, c);
1962 seat->base.led_update = drm_led_update;
1963
1964 wl_list_init(&seat->devices_list);
1965 seat->seat_id = strdup(seat_id);
1966 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1967 free(seat->seat_id);
1968 free(seat);
1969 return;
1970 }
1971
1972 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001973}
1974
1975static void
1976evdev_remove_devices(struct weston_seat *seat_base)
1977{
1978 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001979 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001980
1981 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001982 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001983
Pekka Paalanend8583512012-08-03 14:39:11 +03001984 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001985 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001986}
1987
1988static void
1989evdev_input_destroy(struct weston_seat *seat_base)
1990{
1991 struct drm_seat *seat = (struct drm_seat *) seat_base;
1992
1993 evdev_remove_devices(seat_base);
1994 evdev_disable_udev_monitor(&seat->base);
1995
1996 weston_seat_release(seat_base);
1997 free(seat->seat_id);
1998 free(seat);
1999}
2000
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002001static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002002drm_free_configured_output(struct drm_configured_output *output)
2003{
2004 free(output->name);
2005 free(output->mode);
2006 free(output);
2007}
2008
2009static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002010drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002011{
2012 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002013 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002014 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002015
Daniel Stone37816df2012-05-16 18:45:18 +01002016 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2017 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002018 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002019 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002020
2021 wl_event_source_remove(d->udev_drm_source);
2022 wl_event_source_remove(d->drm_source);
2023
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002024 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002025
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002026 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002027
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002028 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002029 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002030 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002031 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002032 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002033
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002034 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002035}
2036
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002037static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002038drm_compositor_set_modes(struct drm_compositor *compositor)
2039{
2040 struct drm_output *output;
2041 struct drm_mode *drm_mode;
2042 int ret;
2043
2044 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2045 drm_mode = (struct drm_mode *) output->base.current;
2046 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002047 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002048 &output->connector_id, 1,
2049 &drm_mode->mode_info);
2050 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002051 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002052 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002053 drm_mode->base.width, drm_mode->base.height,
2054 output->base.x, output->base.y);
2055 }
2056 }
2057}
2058
2059static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002060vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002061{
2062 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002063 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002064 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002065 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002066
2067 switch (event) {
2068 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002069 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002070 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002071 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002072 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002073 wl_display_terminate(compositor->wl_display);
2074 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002075 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002076 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002077 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002078 wl_list_for_each(seat, &compositor->seat_list, link) {
2079 evdev_add_devices(ec->udev, seat);
2080 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002081 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002082 break;
2083 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002084 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002085 wl_list_for_each(seat, &compositor->seat_list, link) {
2086 evdev_disable_udev_monitor(seat);
2087 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002088 }
2089
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002090 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002091 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002092 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002093
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002094 /* If we have a repaint scheduled (either from a
2095 * pending pageflip or the idle handler), make sure we
2096 * cancel that so we don't try to pageflip when we're
2097 * vt switched away. The SLEEPING state will prevent
2098 * further attemps at repainting. When we switch
2099 * back, we schedule a repaint, which will process
2100 * pending frame callbacks. */
2101
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002102 wl_list_for_each(output, &ec->base.output_list, base.link) {
2103 output->base.repaint_needed = 0;
2104 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002105 }
2106
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002107 output = container_of(ec->base.output_list.next,
2108 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002109
2110 wl_list_for_each(sprite, &ec->sprite_list, link)
2111 drmModeSetPlane(ec->drm.fd,
2112 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002113 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002114 0, 0, 0, 0, 0, 0, 0, 0);
2115
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002116 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002117 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002118
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002119 break;
2120 };
2121}
2122
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002123static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002124switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002125{
2126 struct drm_compositor *ec = data;
2127
Daniel Stone325fc2d2012-05-30 16:31:58 +01002128 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002129}
2130
David Herrmann0af066f2012-10-29 19:21:16 +01002131/*
2132 * Find primary GPU
2133 * Some systems may have multiple DRM devices attached to a single seat. This
2134 * function loops over all devices and tries to find a PCI device with the
2135 * boot_vga sysfs attribute set to 1.
2136 * If no such device is found, the first DRM device reported by udev is used.
2137 */
2138static struct udev_device*
2139find_primary_gpu(struct drm_compositor *ec, const char *seat)
2140{
2141 struct udev_enumerate *e;
2142 struct udev_list_entry *entry;
2143 const char *path, *device_seat, *id;
2144 struct udev_device *device, *drm_device, *pci;
2145
2146 e = udev_enumerate_new(ec->udev);
2147 udev_enumerate_add_match_subsystem(e, "drm");
2148 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2149
2150 udev_enumerate_scan_devices(e);
2151 drm_device = NULL;
2152 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2153 path = udev_list_entry_get_name(entry);
2154 device = udev_device_new_from_syspath(ec->udev, path);
2155 if (!device)
2156 continue;
2157 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2158 if (!device_seat)
2159 device_seat = default_seat;
2160 if (strcmp(device_seat, seat)) {
2161 udev_device_unref(device);
2162 continue;
2163 }
2164
2165 pci = udev_device_get_parent_with_subsystem_devtype(device,
2166 "pci", NULL);
2167 if (pci) {
2168 id = udev_device_get_sysattr_value(pci, "boot_vga");
2169 if (id && !strcmp(id, "1")) {
2170 if (drm_device)
2171 udev_device_unref(drm_device);
2172 drm_device = device;
2173 break;
2174 }
2175 }
2176
2177 if (!drm_device)
2178 drm_device = device;
2179 else
2180 udev_device_unref(device);
2181 }
2182
2183 udev_enumerate_unref(e);
2184 return drm_device;
2185}
2186
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002187static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002188planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002189{
2190 struct drm_compositor *c = data;
2191
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002192 switch (key) {
2193 case KEY_C:
2194 c->cursors_are_broken ^= 1;
2195 break;
2196 case KEY_V:
2197 c->sprites_are_broken ^= 1;
2198 break;
2199 case KEY_O:
2200 c->sprites_hidden ^= 1;
2201 break;
2202 default:
2203 break;
2204 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002205}
2206
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002207static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002208drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002209 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002210 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002211{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002212 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002213 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002214 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002215 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002216 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002217 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002218
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002219 weston_log("initializing drm backend\n");
2220
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002221 ec = malloc(sizeof *ec);
2222 if (ec == NULL)
2223 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002224 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002225
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002226 /* KMS support for sprites is not complete yet, so disable the
2227 * functionality for now. */
2228 ec->sprites_are_broken = 1;
2229
Daniel Stone725c2c32012-06-22 14:04:36 +01002230 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002231 config_file) < 0) {
2232 weston_log("weston_compositor_init failed\n");
2233 goto err_base;
2234 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002235
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002236 ec->udev = udev_new();
2237 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002238 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002239 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002240 }
2241
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002242 ec->base.wl_display = display;
2243 ec->tty = tty_create(&ec->base, vt_func, tty);
2244 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002245 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002246 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002247 }
2248
David Herrmann0af066f2012-10-29 19:21:16 +01002249 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002250 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002251 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002252 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002253 }
David Herrmann0af066f2012-10-29 19:21:16 +01002254 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002255
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002256 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002257 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002258 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002259 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002260
2261 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002262 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002263
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002264 ec->base.focus = 1;
2265
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002266 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002267
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002268 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002269 weston_compositor_add_key_binding(&ec->base, key,
2270 MODIFIER_CTRL | MODIFIER_ALT,
2271 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002272
Jesse Barnes58ef3792012-02-23 09:45:49 -05002273 wl_list_init(&ec->sprite_list);
2274 create_sprites(ec);
2275
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002276 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002277 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002278 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002279 }
2280
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002281 path = NULL;
2282
Tiago Vignattice03ec32011-12-19 01:14:03 +02002283 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002284
2285 loop = wl_display_get_event_loop(ec->base.wl_display);
2286 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002287 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002288 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002289
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002290 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2291 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002292 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002293 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002294 }
2295 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2296 "drm", NULL);
2297 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002298 wl_event_loop_add_fd(loop,
2299 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002300 WL_EVENT_READABLE, udev_drm_event, ec);
2301
2302 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002303 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002304 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002305 }
2306
Daniel Stonea96b93c2012-06-22 14:04:37 +01002307 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002308
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002309 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002310 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002311 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002312 planes_binding, ec);
2313 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2314 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002315
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002316 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002317
2318err_udev_monitor:
2319 wl_event_source_remove(ec->udev_drm_source);
2320 udev_monitor_unref(ec->udev_monitor);
2321err_drm_source:
2322 wl_event_source_remove(ec->drm_source);
2323 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2324 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002325err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002326 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002327 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002328 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002329err_udev_dev:
2330 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002331err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002332 tty_destroy(ec->tty);
2333err_udev:
2334 udev_unref(ec->udev);
2335err_compositor:
2336 weston_compositor_shutdown(&ec->base);
2337err_base:
2338 free(ec);
2339 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002340}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002341
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002342static int
2343set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2344{
2345 mode->flags = 0;
2346
2347 if (strcmp(hsync, "+hsync") == 0)
2348 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2349 else if (strcmp(hsync, "-hsync") == 0)
2350 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2351 else
2352 return -1;
2353
2354 if (strcmp(vsync, "+vsync") == 0)
2355 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2356 else if (strcmp(vsync, "-vsync") == 0)
2357 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2358 else
2359 return -1;
2360
2361 return 0;
2362}
2363
2364static int
2365check_for_modeline(struct drm_configured_output *output)
2366{
2367 drmModeModeInfo mode;
2368 char hsync[16];
2369 char vsync[16];
2370 char mode_name[16];
2371 float fclock;
2372
2373 mode.type = DRM_MODE_TYPE_USERDEF;
2374 mode.hskew = 0;
2375 mode.vscan = 0;
2376 mode.vrefresh = 0;
2377
2378 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2379 &fclock, &mode.hdisplay,
2380 &mode.hsync_start,
2381 &mode.hsync_end, &mode.htotal,
2382 &mode.vdisplay,
2383 &mode.vsync_start,
2384 &mode.vsync_end, &mode.vtotal,
2385 hsync, vsync) == 11) {
2386 if (set_sync_flags(&mode, hsync, vsync))
2387 return -1;
2388
2389 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2390 strcpy(mode.name, mode_name);
2391
2392 mode.clock = fclock * 1000;
2393 } else
2394 return -1;
2395
2396 output->crtc_mode = mode;
2397
2398 return 0;
2399}
2400
Scott Moreau8ab5d452012-07-30 19:51:08 -06002401static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002402drm_output_set_transform(struct drm_configured_output *output)
2403{
2404 if (!output_transform) {
2405 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2406 return;
2407 }
2408
2409 if (!strcmp(output_transform, "normal"))
2410 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2411 else if (!strcmp(output_transform, "90"))
2412 output->transform = WL_OUTPUT_TRANSFORM_90;
2413 else if (!strcmp(output_transform, "180"))
2414 output->transform = WL_OUTPUT_TRANSFORM_180;
2415 else if (!strcmp(output_transform, "270"))
2416 output->transform = WL_OUTPUT_TRANSFORM_270;
2417 else if (!strcmp(output_transform, "flipped"))
2418 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2419 else if (!strcmp(output_transform, "flipped-90"))
2420 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2421 else if (!strcmp(output_transform, "flipped-180"))
2422 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2423 else if (!strcmp(output_transform, "flipped-270"))
2424 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2425 else {
2426 weston_log("Invalid transform \"%s\" for output %s\n",
2427 output_transform, output_name);
2428 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2429 }
2430
2431 free(output_transform);
2432 output_transform = NULL;
2433}
2434
2435static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002436output_section_done(void *data)
2437{
2438 struct drm_configured_output *output;
2439
2440 output = malloc(sizeof *output);
2441
Scott Moreau1bad5db2012-08-18 01:04:05 -06002442 if (!output || !output_name || (output_name[0] == 'X') ||
2443 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002444 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002445 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002446 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002447 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002448 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002449 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002450 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002451 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002452 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002453
2454 output->config = OUTPUT_CONFIG_INVALID;
2455 output->name = output_name;
2456 output->mode = output_mode;
2457
Scott Moreau1bad5db2012-08-18 01:04:05 -06002458 if (output_mode) {
2459 if (strcmp(output_mode, "off") == 0)
2460 output->config = OUTPUT_CONFIG_OFF;
2461 else if (strcmp(output_mode, "preferred") == 0)
2462 output->config = OUTPUT_CONFIG_PREFERRED;
2463 else if (strcmp(output_mode, "current") == 0)
2464 output->config = OUTPUT_CONFIG_CURRENT;
2465 else if (sscanf(output_mode, "%dx%d",
2466 &output->width, &output->height) == 2)
2467 output->config = OUTPUT_CONFIG_MODE;
2468 else if (check_for_modeline(output) == 0)
2469 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002470
Scott Moreau1bad5db2012-08-18 01:04:05 -06002471 if (output->config == OUTPUT_CONFIG_INVALID)
2472 weston_log("Invalid mode \"%s\" for output %s\n",
2473 output_mode, output_name);
2474 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002475 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002476
2477 drm_output_set_transform(output);
2478
2479 wl_list_insert(&configured_output_list, &output->link);
2480
2481 if (output_transform)
2482 free(output_transform);
2483 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002484}
2485
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002486WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002487backend_init(struct wl_display *display, int argc, char *argv[],
2488 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002489{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002490 int connector = 0, tty = 0;
2491 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002492
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002493 const struct weston_option drm_options[] = {
2494 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2495 { WESTON_OPTION_STRING, "seat", 0, &seat },
2496 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002497 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002498 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002499
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002500 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002501
Scott Moreau8ab5d452012-07-30 19:51:08 -06002502 wl_list_init(&configured_output_list);
2503
2504 const struct config_key drm_config_keys[] = {
2505 { "name", CONFIG_KEY_STRING, &output_name },
2506 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002507 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002508 };
2509
2510 const struct config_section config_section[] = {
2511 { "output", drm_config_keys,
2512 ARRAY_LENGTH(drm_config_keys), output_section_done },
2513 };
2514
2515 parse_config_file(config_file, config_section,
2516 ARRAY_LENGTH(config_section), NULL);
2517
Daniel Stonec1be8e52012-06-01 11:14:02 -04002518 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2519 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002520}