blob: cc72c741b8fb4c7d8bb83e2d7216a1419499ceee [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033
Benjamin Franzkec649a922011-03-02 11:56:04 +010034#include <xf86drm.h>
35#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050036#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010037
Benjamin Franzke060cf802011-04-30 09:32:11 +020038#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020039#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040040#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010043#include "gl-renderer.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020044#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010045#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040046
Kristian Høgsberg061c4252012-06-28 11:28:15 -040047static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060048static char *output_name;
49static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060050static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060051static struct wl_list configured_output_list;
52
53enum output_config {
54 OUTPUT_CONFIG_INVALID = 0,
55 OUTPUT_CONFIG_OFF,
56 OUTPUT_CONFIG_PREFERRED,
57 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060058 OUTPUT_CONFIG_MODE,
59 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060060};
61
62struct drm_configured_output {
63 char *name;
64 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060065 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060066 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060067 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060068 enum output_config config;
69 struct wl_list link;
70};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040071
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040072struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050073 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
75 struct udev *udev;
76 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040077
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010078 struct udev_monitor *udev_monitor;
79 struct wl_event_source *udev_drm_source;
80
Benjamin Franzke2af7f102011-03-02 11:14:59 +010081 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010082 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010083 int fd;
84 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020085 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050086 uint32_t *crtcs;
87 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050088 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010089 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050090 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020091
Rob Clark4339add2012-08-09 14:18:28 -050092 /* we need these parameters in order to not fail drmModeAddFB2()
93 * due to out of bounds dimensions, and then mistakenly set
94 * sprites_are_broken:
95 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020096 uint32_t min_width, max_width;
97 uint32_t min_height, max_height;
98 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050099
Jesse Barnes58ef3792012-02-23 09:45:49 -0500100 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500101 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200102 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500103
Rob Clarkab5b1e32012-08-09 13:24:45 -0500104 int cursors_are_broken;
105
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400107};
108
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500110 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400111 drmModeModeInfo mode_info;
112};
113
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300114struct drm_output;
115
116struct drm_fb {
117 struct gbm_bo *bo;
118 struct drm_output *output;
119 uint32_t fb_id;
120 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200121 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300122};
123
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400124struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500125 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400127 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400128 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500129 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400130 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700131 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200132
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300133 int vblank_pending;
134 int page_flip_pending;
135
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400136 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400137 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400138 struct weston_plane cursor_plane;
139 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400140 struct weston_surface *cursor_surface;
141 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300142 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200143 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144};
145
Jesse Barnes58ef3792012-02-23 09:45:49 -0500146/*
147 * An output has a primary display plane plus zero or more sprites for
148 * blending display contents.
149 */
150struct drm_sprite {
151 struct wl_list link;
152
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400153 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500154
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200155 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300156 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500157 struct drm_compositor *compositor;
158
Jesse Barnes58ef3792012-02-23 09:45:49 -0500159 uint32_t possible_crtcs;
160 uint32_t plane_id;
161 uint32_t count_formats;
162
163 int32_t src_x, src_y;
164 uint32_t src_w, src_h;
165 uint32_t dest_x, dest_y;
166 uint32_t dest_w, dest_h;
167
168 uint32_t formats[];
169};
170
Pekka Paalanen33156972012-08-03 13:30:30 -0400171struct drm_seat {
172 struct weston_seat base;
173 struct wl_list devices_list;
174 struct udev_monitor *udev_monitor;
175 struct wl_event_source *udev_monitor_source;
176 char *seat_id;
177};
178
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400179static void
180drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400181
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
184{
185 struct weston_compositor *ec = output_base->compositor;
186 struct drm_compositor *c =(struct drm_compositor *) ec;
187 struct drm_output *output = (struct drm_output *) output_base;
188 int crtc;
189
190 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
191 if (c->crtcs[crtc] != output->crtc_id)
192 continue;
193
194 if (supported & (1 << crtc))
195 return -1;
196 }
197
198 return 0;
199}
200
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300201static void
202drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
203{
204 struct drm_fb *fb = data;
205 struct gbm_device *gbm = gbm_bo_get_device(bo);
206
207 if (fb->fb_id)
208 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
209
Pekka Paalanende685b82012-12-04 15:58:12 +0200210 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300211
212 free(data);
213}
214
215static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500216drm_fb_get_from_bo(struct gbm_bo *bo,
217 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300218{
219 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500220 uint32_t width, height, stride, handle;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200221 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300222 int ret;
223
224 if (fb)
225 return fb;
226
227 fb = malloc(sizeof *fb);
228
229 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300230 fb->is_client_buffer = 0;
Pekka Paalanende685b82012-12-04 15:58:12 +0200231 fb->buffer_ref.buffer = NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300232
233 width = gbm_bo_get_width(bo);
234 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400235 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300236 handle = gbm_bo_get_handle(bo).u32;
237
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200238 if (compositor->min_width > width || width > compositor->max_width ||
239 compositor->min_height > height ||
240 height > compositor->max_height) {
241 weston_log("bo geometry out of bounds\n");
242 goto err_free;
243 }
244
245 ret = -1;
246
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200247 if (format && !compositor->no_addfb2) {
248 handles[0] = handle;
249 pitches[0] = stride;
250 offsets[0] = 0;
251
252 ret = drmModeAddFB2(compositor->drm.fd, width, height,
253 format, handles, pitches, offsets,
254 &fb->fb_id, 0);
255 if (ret) {
256 weston_log("addfb2 failed: %m\n");
257 compositor->no_addfb2 = 1;
258 compositor->sprites_are_broken = 1;
259 }
260 }
261
262 if (ret)
263 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
264 stride, handle, &fb->fb_id);
265
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300266 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200267 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200268 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300269 }
270
271 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
272
273 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200274
275err_free:
276 free(fb);
277 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300278}
279
280static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200281drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
282{
Pekka Paalanende685b82012-12-04 15:58:12 +0200283 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200284
285 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200286
Pekka Paalanende685b82012-12-04 15:58:12 +0200287 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200288}
289
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500290static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200291drm_output_check_scanout_format(struct drm_output *output,
292 struct weston_surface *es, struct gbm_bo *bo)
293{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200294 uint32_t format;
295 pixman_region32_t r;
296
297 format = gbm_bo_get_format(bo);
298
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500299 switch (format) {
300 case GBM_FORMAT_XRGB8888:
301 return format;
302 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200303 /* We can only scanout an ARGB buffer if the surface's
304 * opaque region covers the whole output */
305 pixman_region32_init(&r);
306 pixman_region32_subtract(&r, &output->base.region,
307 &es->opaque);
308
309 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500310 format = GBM_FORMAT_XRGB8888;
311 else
312 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200313
314 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200315
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500316 return format;
317 default:
318 return 0;
319 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200320}
321
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400322static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400323drm_output_prepare_scanout_surface(struct weston_output *_output,
324 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500325{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400326 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500327 struct drm_compositor *c =
328 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200329 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300330 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500331 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500332
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500333 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200334 es->geometry.y != output->base.y ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200335 buffer == NULL ||
336 buffer->width != output->base.current->width ||
337 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200338 output->base.transform != es->buffer_transform ||
339 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400340 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500341
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400342 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200343 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500344
Rob Bradford9b101872012-09-14 23:25:41 +0100345 /* Unable to use the buffer for scanout */
346 if (!bo)
347 return NULL;
348
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500349 format = drm_output_check_scanout_format(output, es, bo);
350 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300351 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400352 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300353 }
354
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500355 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356 if (!output->next) {
357 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400358 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500360
Pekka Paalanende685b82012-12-04 15:58:12 +0200361 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500362
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400363 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500364}
365
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500366static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400367drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400368{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200369 struct drm_compositor *c =
370 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300371 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400372
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200373 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400374
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200375 pixman_region32_subtract(&c->base.primary_plane.damage,
376 &c->base.primary_plane.damage, damage);
377
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300378 bo = gbm_surface_lock_front_buffer(output->surface);
379 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200380 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400381 return;
382 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300383
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500384 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300385 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200386 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300387 gbm_surface_release_buffer(output->surface, bo);
388 return;
389 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400390}
391
392static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500393drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400394 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100395{
396 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500397 struct drm_compositor *compositor =
398 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500399 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400400 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500401 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100402
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300403 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400404 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300405 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400406 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100407
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400408 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300409 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400410 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300411 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400412 &output->connector_id, 1,
413 &mode->mode_info);
414 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200415 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400416 return;
417 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200418 }
419
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500420 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300421 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500422 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200423 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500424 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500425 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100426
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300427 output->page_flip_pending = 1;
428
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400429 drm_output_set_cursor(output);
430
Jesse Barnes58ef3792012-02-23 09:45:49 -0500431 /*
432 * Now, update all the sprite surfaces
433 */
434 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200435 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500436 drmVBlank vbl = {
437 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
438 .request.sequence = 1,
439 };
440
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200441 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200442 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500443 continue;
444
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200445 if (s->next && !compositor->sprites_hidden)
446 fb_id = s->next->fb_id;
447
Jesse Barnes58ef3792012-02-23 09:45:49 -0500448 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200449 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500450 s->dest_x, s->dest_y,
451 s->dest_w, s->dest_h,
452 s->src_x, s->src_y,
453 s->src_w, s->src_h);
454 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200455 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500456 ret, strerror(errno));
457
Rob Clark5ca1a472012-08-08 20:27:37 -0500458 if (output->pipe > 0)
459 vbl.request.type |= DRM_VBLANK_SECONDARY;
460
Jesse Barnes58ef3792012-02-23 09:45:49 -0500461 /*
462 * Queue a vblank signal so we know when the surface
463 * becomes active on the display or has been replaced.
464 */
465 vbl.request.signal = (unsigned long)s;
466 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
467 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200468 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500469 ret, strerror(errno));
470 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300471
472 s->output = output;
473 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500474 }
475
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500476 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400477}
478
479static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500480vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
481 void *data)
482{
483 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300484 struct drm_output *output = s->output;
485 uint32_t msecs;
486
487 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500488
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200489 if (s->current)
490 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500491
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200492 s->current = s->next;
493 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300494
495 if (!output->page_flip_pending) {
496 msecs = sec * 1000 + usec / 1000;
497 weston_output_finish_frame(&output->base, msecs);
498 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500499}
500
501static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400502page_flip_handler(int fd, unsigned int frame,
503 unsigned int sec, unsigned int usec, void *data)
504{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200505 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400506 uint32_t msecs;
507
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300508 output->page_flip_pending = 0;
509
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510 if (output->current) {
511 if (output->current->is_client_buffer)
512 gbm_bo_destroy(output->current->bo);
513 else
514 gbm_surface_release_buffer(output->surface,
515 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200516 }
517
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300518 output->current = output->next;
519 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400520
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300521 if (!output->vblank_pending) {
522 msecs = sec * 1000 + usec / 1000;
523 weston_output_finish_frame(&output->base, msecs);
524 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200525}
526
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500527static uint32_t
528drm_output_check_sprite_format(struct drm_sprite *s,
529 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500530{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500531 uint32_t i, format;
532
533 format = gbm_bo_get_format(bo);
534
535 if (format == GBM_FORMAT_ARGB8888) {
536 pixman_region32_t r;
537
538 pixman_region32_init(&r);
539 pixman_region32_subtract(&r, &es->transform.boundingbox,
540 &es->transform.opaque);
541
542 if (!pixman_region32_not_empty(&r))
543 format = GBM_FORMAT_XRGB8888;
544
545 pixman_region32_fini(&r);
546 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500547
548 for (i = 0; i < s->count_formats; i++)
549 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500550 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500551
552 return 0;
553}
554
555static int
556drm_surface_transform_supported(struct weston_surface *es)
557{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400558 struct weston_matrix *matrix = &es->transform.matrix;
559 int i;
560
561 if (!es->transform.enabled)
562 return 1;
563
564 for (i = 0; i < 16; i++) {
565 switch (i) {
566 case 10:
567 case 15:
568 if (matrix->d[i] != 1.0)
569 return 0;
570 break;
571 case 0:
572 case 5:
573 case 12:
574 case 13:
575 break;
576 default:
577 if (matrix->d[i] != 0.0)
578 return 0;
579 break;
580 }
581 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500582
583 return 1;
584}
585
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400586static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500587drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400588 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589{
590 struct weston_compositor *ec = output_base->compositor;
591 struct drm_compositor *c =(struct drm_compositor *) ec;
592 struct drm_sprite *s;
593 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500594 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500595 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200596 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500597 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400598 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200600 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200601 return NULL;
602
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500603 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400604 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500605
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300606 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400607 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300608
Pekka Paalanende685b82012-12-04 15:58:12 +0200609 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400610 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200612 if (es->alpha != 1.0f)
613 return NULL;
614
Pekka Paalanende685b82012-12-04 15:58:12 +0200615 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500616 return NULL;
617
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400619 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 wl_list_for_each(s, &c->sprite_list, link) {
622 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
623 continue;
624
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200625 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 found = 1;
627 break;
628 }
629 }
630
631 /* No sprites available */
632 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400633 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400635 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200636 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400637 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400638 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400639
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500640 format = drm_output_check_sprite_format(s, es, bo);
641 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400643 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500644 }
645
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200646 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200647 if (!s->next) {
648 gbm_bo_destroy(bo);
649 return NULL;
650 }
651
Pekka Paalanende685b82012-12-04 15:58:12 +0200652 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400654 box = pixman_region32_extents(&es->transform.boundingbox);
655 s->plane.x = box->x1;
656 s->plane.y = box->y1;
657
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658 /*
659 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200660 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500661 * for us already).
662 */
663 pixman_region32_init(&dest_rect);
664 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
665 &output_base->region);
666 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
667 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200668 tbox = weston_transformed_rect(output_base->width,
669 output_base->height,
670 output_base->transform, *box);
671 s->dest_x = tbox.x1;
672 s->dest_y = tbox.y1;
673 s->dest_w = tbox.x2 - tbox.x1;
674 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500675 pixman_region32_fini(&dest_rect);
676
677 pixman_region32_init(&src_rect);
678 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
679 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500680 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400681
682 weston_surface_from_global_fixed(es,
683 wl_fixed_from_int(box->x1),
684 wl_fixed_from_int(box->y1),
685 &sx1, &sy1);
686 weston_surface_from_global_fixed(es,
687 wl_fixed_from_int(box->x2),
688 wl_fixed_from_int(box->y2),
689 &sx2, &sy2);
690
691 if (sx1 < 0)
692 sx1 = 0;
693 if (sy1 < 0)
694 sy1 = 0;
695 if (sx2 > wl_fixed_from_int(es->geometry.width))
696 sx2 = wl_fixed_from_int(es->geometry.width);
697 if (sy2 > wl_fixed_from_int(es->geometry.height))
698 sy2 = wl_fixed_from_int(es->geometry.height);
699
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200700 tbox.x1 = sx1;
701 tbox.y1 = sy1;
702 tbox.x2 = sx2;
703 tbox.y2 = sy2;
704
705 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
706 wl_fixed_from_int(es->geometry.height),
707 es->buffer_transform, tbox);
708
709 s->src_x = tbox.x1 << 8;
710 s->src_y = tbox.y1 << 8;
711 s->src_w = (tbox.x2 - tbox.x1) << 8;
712 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500713 pixman_region32_fini(&src_rect);
714
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400715 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500716}
717
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400718static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400719drm_output_prepare_cursor_surface(struct weston_output *output_base,
720 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500721{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400722 struct drm_compositor *c =
723 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400724 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400725
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200726 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
727 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400728 if (output->cursor_surface)
729 return NULL;
730 if (es->output_mask != (1u << output_base->id))
731 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500732 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400733 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200734 if (es->buffer_ref.buffer == NULL ||
735 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400736 es->geometry.width > 64 || es->geometry.height > 64)
737 return NULL;
738
739 output->cursor_surface = es;
740
741 return &output->cursor_plane;
742}
743
744static void
745drm_output_set_cursor(struct drm_output *output)
746{
747 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400748 struct drm_compositor *c =
749 (struct drm_compositor *) output->base.compositor;
750 EGLint handle, stride;
751 struct gbm_bo *bo;
752 uint32_t buf[64 * 64];
753 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400754 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500755
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400756 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400757 if (es == NULL) {
758 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
759 return;
760 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500761
Pekka Paalanende685b82012-12-04 15:58:12 +0200762 if (es->buffer_ref.buffer &&
763 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400764 pixman_region32_fini(&output->cursor_plane.damage);
765 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400766 output->current_cursor ^= 1;
767 bo = output->cursor_bo[output->current_cursor];
768 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200769 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
770 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400771 for (i = 0; i < es->geometry.height; i++)
772 memcpy(buf + i * 64, s + i * stride,
773 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500774
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400775 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300776 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400777
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400778 handle = gbm_bo_get_handle(bo).s32;
779 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500780 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300781 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500782 c->cursors_are_broken = 1;
783 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400784 }
785
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400786 x = es->geometry.x - output->base.x;
787 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400788 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500789 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400790 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500791 c->cursors_are_broken = 1;
792 }
793
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400794 output->cursor_plane.x = x;
795 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400796 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500797}
798
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799static void
800drm_assign_planes(struct weston_output *output)
801{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400802 struct drm_compositor *c =
803 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200804 struct drm_output *drm_output = (struct drm_output *) output;
805 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400806 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500807 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400808 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200810 /* Reset the opaque region of the planes */
811 pixman_region32_fini(&drm_output->cursor_plane.opaque);
812 pixman_region32_init(&drm_output->cursor_plane.opaque);
813 pixman_region32_fini(&drm_output->fb_plane.opaque);
814 pixman_region32_init(&drm_output->fb_plane.opaque);
815
816 wl_list_for_each (s, &c->sprite_list, link) {
817 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
818 continue;
819
820 pixman_region32_fini(&s->plane.opaque);
821 pixman_region32_init(&s->plane.opaque);
822 }
823
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824 /*
825 * Find a surface for each sprite in the output using some heuristics:
826 * 1) size
827 * 2) frequency of update
828 * 3) opacity (though some hw might support alpha blending)
829 * 4) clipping (this can be fixed with color keys)
830 *
831 * The idea is to save on blitting since this should save power.
832 * If we can get a large video surface on the sprite for example,
833 * the main display surface may not need to update at all, and
834 * the client buffer can be used directly for the sprite surface
835 * as we do for flipping full screen surfaces.
836 */
837 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400838 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400839 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200840 /* test whether this buffer can ever go into a plane:
841 * non-shm, or small enough to be a cursor
842 */
843 if ((es->buffer_ref.buffer &&
844 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
845 (es->geometry.width <= 64 && es->geometry.height <= 64))
846 es->keep_buffer = 1;
847 else
848 es->keep_buffer = 0;
849
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850 pixman_region32_init(&surface_overlap);
851 pixman_region32_intersect(&surface_overlap, &overlap,
852 &es->transform.boundingbox);
853
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400854 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400855 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400856 next_plane = primary;
857 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400858 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400859 if (next_plane == NULL)
860 next_plane = drm_output_prepare_scanout_surface(output, es);
861 if (next_plane == NULL)
862 next_plane = drm_output_prepare_overlay_surface(output, es);
863 if (next_plane == NULL)
864 next_plane = primary;
865 weston_surface_move_to_plane(es, next_plane);
866 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500867 pixman_region32_union(&overlap, &overlap,
868 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400869
Jesse Barnes58ef3792012-02-23 09:45:49 -0500870 pixman_region32_fini(&surface_overlap);
871 }
872 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500873}
874
Matt Roper361d2ad2011-08-29 13:52:23 -0700875static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500876drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700877{
878 struct drm_output *output = (struct drm_output *) output_base;
879 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200880 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700881 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700882
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200883 if (output->backlight)
884 backlight_destroy(output->backlight);
885
Matt Roper361d2ad2011-08-29 13:52:23 -0700886 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400887 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700888
889 /* Restore original CRTC state */
890 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200891 origcrtc->x, origcrtc->y,
892 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700893 drmModeFreeCrtc(origcrtc);
894
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200895 c->crtc_allocator &= ~(1 << output->crtc_id);
896 c->connector_allocator &= ~(1 << output->connector_id);
897
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100898 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100899
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400900 gbm_surface_destroy(output->surface);
901
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400902 weston_plane_release(&output->fb_plane);
903 weston_plane_release(&output->cursor_plane);
904
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500905 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200906 wl_list_remove(&output->base.link);
907
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400908 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700909 free(output);
910}
911
Alex Wub7b8bda2012-04-17 17:20:48 +0800912static struct drm_mode *
913choose_mode (struct drm_output *output, struct weston_mode *target_mode)
914{
915 struct drm_mode *tmp_mode = NULL, *mode;
916
917 if (output->base.current->width == target_mode->width &&
918 output->base.current->height == target_mode->height &&
919 (output->base.current->refresh == target_mode->refresh ||
920 target_mode->refresh == 0))
921 return (struct drm_mode *)output->base.current;
922
923 wl_list_for_each(mode, &output->base.mode_list, base.link) {
924 if (mode->mode_info.hdisplay == target_mode->width &&
925 mode->mode_info.vdisplay == target_mode->height) {
926 if (mode->mode_info.vrefresh == target_mode->refresh ||
927 target_mode->refresh == 0) {
928 return mode;
929 } else if (!tmp_mode)
930 tmp_mode = mode;
931 }
932 }
933
934 return tmp_mode;
935}
936
937static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200938drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
939
940static int
Alex Wub7b8bda2012-04-17 17:20:48 +0800941drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
942{
943 struct drm_output *output;
944 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +0800945 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +0800946
947 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200948 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800949 return -1;
950 }
951
952 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200953 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800954 return -1;
955 }
956
957 ec = (struct drm_compositor *)output_base->compositor;
958 output = (struct drm_output *)output_base;
959 drm_mode = choose_mode (output, mode);
960
961 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200962 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800963 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200964 }
965
966 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +0800967 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800968
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200969 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800970
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200971 output->base.current = &drm_mode->base;
972 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +0800973 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
974
Alex Wub7b8bda2012-04-17 17:20:48 +0800975 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300976 if (output->current) {
977 if (output->current->is_client_buffer)
978 gbm_bo_destroy(output->current->bo);
979 else
980 gbm_surface_release_buffer(output->surface,
981 output->current->bo);
982 }
983 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800984
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300985 if (output->next) {
986 if (output->next->is_client_buffer)
987 gbm_bo_destroy(output->next->bo);
988 else
989 gbm_surface_release_buffer(output->surface,
990 output->next->bo);
991 }
992 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800993
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200994 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800995 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800996
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200997 if (drm_output_init_egl(output, ec) < 0) {
998 weston_log("failed to init output egl state with new mode");
999 return -1;
1000 }
1001
Alex Wub7b8bda2012-04-17 17:20:48 +08001002 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001003}
1004
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001005static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001006on_drm_input(int fd, uint32_t mask, void *data)
1007{
1008 drmEventContext evctx;
1009
1010 memset(&evctx, 0, sizeof evctx);
1011 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1012 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001013 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001014 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001015
1016 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001017}
1018
1019static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001020init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001021{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001022 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001023 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001024
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001025 sysnum = udev_device_get_sysnum(device);
1026 if (sysnum)
1027 ec->drm.id = atoi(sysnum);
1028 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001029 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001030 return -1;
1031 }
1032
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001033 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001034 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001035 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001036 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001037 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001038 udev_device_get_devnode(device));
1039 return -1;
1040 }
1041
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001042 weston_log("using %s\n", filename);
1043
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001044 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001045 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001046
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001047 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001048 NULL) < 0) {
1049 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001050 return -1;
1051 }
1052
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001053 return 0;
1054}
1055
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001056static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001057drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1058{
1059 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001060 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001061
1062 mode = malloc(sizeof *mode);
1063 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001064 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001065
1066 mode->base.flags = 0;
1067 mode->base.width = info->hdisplay;
1068 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001069
1070 /* Calculate higher precision (mHz) refresh rate */
1071 refresh = (info->clock * 1000000LL / info->htotal +
1072 info->vtotal / 2) / info->vtotal;
1073
1074 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1075 refresh *= 2;
1076 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1077 refresh /= 2;
1078 if (info->vscan > 1)
1079 refresh /= info->vscan;
1080
1081 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001082 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001083
1084 if (info->type & DRM_MODE_TYPE_PREFERRED)
1085 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1086
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001087 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1088
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001089 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001090}
1091
1092static int
1093drm_subpixel_to_wayland(int drm_value)
1094{
1095 switch (drm_value) {
1096 default:
1097 case DRM_MODE_SUBPIXEL_UNKNOWN:
1098 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1099 case DRM_MODE_SUBPIXEL_NONE:
1100 return WL_OUTPUT_SUBPIXEL_NONE;
1101 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1102 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1103 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1104 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1105 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1106 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1107 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1108 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1109 }
1110}
1111
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001112/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001113static uint32_t
1114drm_get_backlight(struct drm_output *output)
1115{
1116 long brightness, max_brightness, norm;
1117
1118 brightness = backlight_get_brightness(output->backlight);
1119 max_brightness = backlight_get_max_brightness(output->backlight);
1120
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001121 /* convert it on a scale of 0 to 255 */
1122 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001123
1124 return (uint32_t) norm;
1125}
1126
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001127/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001128static void
1129drm_set_backlight(struct weston_output *output_base, uint32_t value)
1130{
1131 struct drm_output *output = (struct drm_output *) output_base;
1132 long max_brightness, new_brightness;
1133
1134 if (!output->backlight)
1135 return;
1136
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001137 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001138 return;
1139
1140 max_brightness = backlight_get_max_brightness(output->backlight);
1141
1142 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001143 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001144
1145 backlight_set_brightness(output->backlight, new_brightness);
1146}
1147
1148static drmModePropertyPtr
1149drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1150{
1151 drmModePropertyPtr props;
1152 int i;
1153
1154 for (i = 0; i < connector->count_props; i++) {
1155 props = drmModeGetProperty(fd, connector->props[i]);
1156 if (!props)
1157 continue;
1158
1159 if (!strcmp(props->name, name))
1160 return props;
1161
1162 drmModeFreeProperty(props);
1163 }
1164
1165 return NULL;
1166}
1167
1168static void
1169drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1170{
1171 struct drm_output *output = (struct drm_output *) output_base;
1172 struct weston_compositor *ec = output_base->compositor;
1173 struct drm_compositor *c = (struct drm_compositor *) ec;
1174 drmModeConnectorPtr connector;
1175 drmModePropertyPtr prop;
1176
1177 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1178 if (!connector)
1179 return;
1180
1181 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1182 if (!prop) {
1183 drmModeFreeConnector(connector);
1184 return;
1185 }
1186
1187 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1188 prop->prop_id, level);
1189 drmModeFreeProperty(prop);
1190 drmModeFreeConnector(connector);
1191}
1192
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001193static const char *connector_type_names[] = {
1194 "None",
1195 "VGA",
1196 "DVI",
1197 "DVI",
1198 "DVI",
1199 "Composite",
1200 "TV",
1201 "LVDS",
1202 "CTV",
1203 "DIN",
1204 "DP",
1205 "HDMI",
1206 "HDMI",
1207 "TV",
1208 "eDP",
1209};
1210
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001211static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001212find_crtc_for_connector(struct drm_compositor *ec,
1213 drmModeRes *resources, drmModeConnector *connector)
1214{
1215 drmModeEncoder *encoder;
1216 uint32_t possible_crtcs;
1217 int i, j;
1218
1219 for (j = 0; j < connector->count_encoders; j++) {
1220 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1221 if (encoder == NULL) {
1222 weston_log("Failed to get encoder.\n");
1223 return -1;
1224 }
1225 possible_crtcs = encoder->possible_crtcs;
1226 drmModeFreeEncoder(encoder);
1227
1228 for (i = 0; i < resources->count_crtcs; i++) {
1229 if (possible_crtcs & (1 << i) &&
1230 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1231 return i;
1232 }
1233 }
1234
1235 return -1;
1236}
1237
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001238/* Init output state that depends on gl or gbm */
1239static int
1240drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1241{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001242 int i, flags;
1243
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001244 output->surface = gbm_surface_create(ec->gbm,
1245 output->base.current->width,
1246 output->base.current->height,
1247 GBM_FORMAT_XRGB8888,
1248 GBM_BO_USE_SCANOUT |
1249 GBM_BO_USE_RENDERING);
1250 if (!output->surface) {
1251 weston_log("failed to create gbm surface\n");
1252 return -1;
1253 }
1254
1255 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001256 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001257 gbm_surface_destroy(output->surface);
1258 return -1;
1259 }
1260
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001261 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1262
1263 for (i = 0; i < 2; i++) {
1264 if (output->cursor_bo[i])
1265 continue;
1266
1267 output->cursor_bo[i] =
1268 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1269 flags);
1270 }
1271
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001272 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1273 weston_log("cursor buffers unavailable, using gl cursors\n");
1274 ec->cursors_are_broken = 1;
1275 }
1276
1277 return 0;
1278}
1279
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001280static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001281create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001282 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001283 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001284 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001285{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001286 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001287 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1288 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001289 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001290 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001291 drmModeModeInfo crtc_mode;
1292 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001293 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001294 char name[32];
1295 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001296
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001297 i = find_crtc_for_connector(ec, resources, connector);
1298 if (i < 0) {
1299 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001300 return -1;
1301 }
1302
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001303 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001304 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001305 return -1;
1306
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001307 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001308 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1309 output->base.make = "unknown";
1310 output->base.model = "unknown";
1311 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001312
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001313 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1314 type_name = connector_type_names[connector->connector_type];
1315 else
1316 type_name = "UNKNOWN";
1317 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1318 output->name = strdup(name);
1319
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001320 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001321 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001322 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001323 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001324 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001325
Matt Roper361d2ad2011-08-29 13:52:23 -07001326 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1327
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001328 /* Get the current mode on the crtc that's currently driving
1329 * this connector. */
1330 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001331 memset(&crtc_mode, 0, sizeof crtc_mode);
1332 if (encoder != NULL) {
1333 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1334 drmModeFreeEncoder(encoder);
1335 if (crtc == NULL)
1336 goto err_free;
1337 if (crtc->mode_valid)
1338 crtc_mode = crtc->mode;
1339 drmModeFreeCrtc(crtc);
1340 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001341
David Herrmann0f0d54e2011-12-08 17:05:45 +01001342 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001343 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1344 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001345 goto err_free;
1346 }
1347
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001348 preferred = NULL;
1349 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001350 configured = NULL;
1351
1352 wl_list_for_each(temp, &configured_output_list, link) {
1353 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001354 if (temp->mode)
1355 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001356 temp->name, temp->mode);
1357 o = temp;
1358 break;
1359 }
1360 }
1361
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001362 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001363 weston_log("Disabling output %s\n", o->name);
1364
1365 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1366 0, 0, 0, 0, 0, NULL);
1367 goto err_free;
1368 }
1369
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001370 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001371 if (o && o->config == OUTPUT_CONFIG_MODE &&
1372 o->width == drm_mode->base.width &&
1373 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001374 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001375 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001376 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001377 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001378 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001379 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001380
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001381 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001382 configured = drm_output_add_mode(output, &o->crtc_mode);
1383 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001384 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001385 current = configured;
1386 }
1387
Wang Quanxianacb805a2012-07-30 18:09:46 -04001388 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001389 current = drm_output_add_mode(output, &crtc_mode);
1390 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001391 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001392 }
1393
Scott Moreau8ab5d452012-07-30 19:51:08 -06001394 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1395 configured = current;
1396
Wang Quanxianacb805a2012-07-30 18:09:46 -04001397 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001398 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001399 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001400 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001401 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001402 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001403 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001404 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001405
1406 if (output->base.current == NULL) {
1407 weston_log("no available modes for %s\n", output->name);
1408 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001409 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001410
Wang Quanxianacb805a2012-07-30 18:09:46 -04001411 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1412
John Kåre Alsaker94659272012-11-13 19:10:18 +01001413 weston_output_init(&output->base, &ec->base, x, y,
1414 connector->mmWidth, connector->mmHeight,
1415 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1416
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001417 if (drm_output_init_egl(output, ec) < 0) {
1418 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001419 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001420 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001421
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001422 output->backlight = backlight_init(drm_device,
1423 connector->connector_type);
1424 if (output->backlight) {
1425 output->base.set_backlight = drm_set_backlight;
1426 output->base.backlight_current = drm_get_backlight(output);
1427 }
1428
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001429 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1430
Alex Wubd3354b2012-04-17 17:20:49 +08001431 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001432 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001433 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001434 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001435 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001436 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001437
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001438 weston_plane_init(&output->cursor_plane, 0, 0);
1439 weston_plane_init(&output->fb_plane, 0, 0);
1440
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001441 weston_log("Output %s, (connector %d, crtc %d)\n",
1442 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001443 wl_list_for_each(m, &output->base.mode_list, link)
1444 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1445 m->width, m->height, m->refresh / 1000.0,
1446 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1447 ", preferred" : "",
1448 m->flags & WL_OUTPUT_MODE_CURRENT ?
1449 ", current" : "",
1450 connector->count_modes == 0 ?
1451 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001452
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001453 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001454
John Kåre Alsaker94659272012-11-13 19:10:18 +01001455err_output:
1456 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001457err_free:
1458 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1459 base.link) {
1460 wl_list_remove(&drm_mode->base.link);
1461 free(drm_mode);
1462 }
1463
1464 drmModeFreeCrtc(output->original_crtc);
1465 ec->crtc_allocator &= ~(1 << output->crtc_id);
1466 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001467 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001468 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001469
David Herrmann0f0d54e2011-12-08 17:05:45 +01001470 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001471}
1472
Jesse Barnes58ef3792012-02-23 09:45:49 -05001473static void
1474create_sprites(struct drm_compositor *ec)
1475{
1476 struct drm_sprite *sprite;
1477 drmModePlaneRes *plane_res;
1478 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001479 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001480
1481 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1482 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001483 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001484 strerror(errno));
1485 return;
1486 }
1487
1488 for (i = 0; i < plane_res->count_planes; i++) {
1489 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1490 if (!plane)
1491 continue;
1492
1493 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1494 plane->count_formats));
1495 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001496 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001497 __func__);
1498 free(plane);
1499 continue;
1500 }
1501
1502 memset(sprite, 0, sizeof *sprite);
1503
1504 sprite->possible_crtcs = plane->possible_crtcs;
1505 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001506 sprite->current = NULL;
1507 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001508 sprite->compositor = ec;
1509 sprite->count_formats = plane->count_formats;
1510 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001511 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001512 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001513 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001514
1515 wl_list_insert(&ec->sprite_list, &sprite->link);
1516 }
1517
1518 free(plane_res->planes);
1519 free(plane_res);
1520}
1521
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001522static void
1523destroy_sprites(struct drm_compositor *compositor)
1524{
1525 struct drm_sprite *sprite, *next;
1526 struct drm_output *output;
1527
1528 output = container_of(compositor->base.output_list.next,
1529 struct drm_output, base.link);
1530
1531 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1532 drmModeSetPlane(compositor->drm.fd,
1533 sprite->plane_id,
1534 output->crtc_id, 0, 0,
1535 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001536 if (sprite->current)
1537 gbm_bo_destroy(sprite->current->bo);
1538 if (sprite->next)
1539 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001540 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001541 free(sprite);
1542 }
1543}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001544
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001545static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001546create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001547 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001548{
1549 drmModeConnector *connector;
1550 drmModeRes *resources;
1551 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001552 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001553
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001554 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001555 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001556 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001557 return -1;
1558 }
1559
Jesse Barnes58ef3792012-02-23 09:45:49 -05001560 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001561 if (!ec->crtcs) {
1562 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001563 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001564 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001565
Rob Clark4339add2012-08-09 14:18:28 -05001566 ec->min_width = resources->min_width;
1567 ec->max_width = resources->max_width;
1568 ec->min_height = resources->min_height;
1569 ec->max_height = resources->max_height;
1570
Jesse Barnes58ef3792012-02-23 09:45:49 -05001571 ec->num_crtcs = resources->count_crtcs;
1572 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1573
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001574 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001575 connector = drmModeGetConnector(ec->drm.fd,
1576 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001577 if (connector == NULL)
1578 continue;
1579
1580 if (connector->connection == DRM_MODE_CONNECTED &&
1581 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001582 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001583 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001584 connector, x, y,
1585 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001586 drmModeFreeConnector(connector);
1587 continue;
1588 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001589
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001590 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001591 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001592 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001593 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001594
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001595 drmModeFreeConnector(connector);
1596 }
1597
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001598 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001599 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001600 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001601 return -1;
1602 }
1603
1604 drmModeFreeResources(resources);
1605
1606 return 0;
1607}
1608
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001609static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001610update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001611{
1612 drmModeConnector *connector;
1613 drmModeRes *resources;
1614 struct drm_output *output, *next;
1615 int x = 0, y = 0;
1616 int x_offset = 0, y_offset = 0;
1617 uint32_t connected = 0, disconnects = 0;
1618 int i;
1619
1620 resources = drmModeGetResources(ec->drm.fd);
1621 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001622 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001623 return;
1624 }
1625
1626 /* collect new connects */
1627 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001628 int connector_id = resources->connectors[i];
1629
1630 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001631 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001632 continue;
1633
David Herrmann7551cff2011-12-08 17:05:43 +01001634 if (connector->connection != DRM_MODE_CONNECTED) {
1635 drmModeFreeConnector(connector);
1636 continue;
1637 }
1638
Benjamin Franzke117483d2011-08-30 11:38:26 +02001639 connected |= (1 << connector_id);
1640
1641 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001642 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001643 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001644 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001645
1646 /* XXX: not yet needed, we die with 0 outputs */
1647 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001648 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001649 else
1650 x = 0;
1651 y = 0;
1652 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001653 connector, x, y,
1654 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001655 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001656
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001657 }
1658 drmModeFreeConnector(connector);
1659 }
1660 drmModeFreeResources(resources);
1661
1662 disconnects = ec->connector_allocator & ~connected;
1663 if (disconnects) {
1664 wl_list_for_each_safe(output, next, &ec->base.output_list,
1665 base.link) {
1666 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001667 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001668 output->base.x - x_offset,
1669 output->base.y - y_offset);
1670 }
1671
1672 if (disconnects & (1 << output->connector_id)) {
1673 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001674 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001675 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001676 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001677 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001678 }
1679 }
1680 }
1681
1682 /* FIXME: handle zero outputs, without terminating */
1683 if (ec->connector_allocator == 0)
1684 wl_display_terminate(ec->base.wl_display);
1685}
1686
1687static int
David Herrmannd7488c22012-03-11 20:05:21 +01001688udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001689{
David Herrmannd7488c22012-03-11 20:05:21 +01001690 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001691 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001692
1693 sysnum = udev_device_get_sysnum(device);
1694 if (!sysnum || atoi(sysnum) != ec->drm.id)
1695 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001696
David Herrmann6ac52db2012-03-11 20:05:22 +01001697 val = udev_device_get_property_value(device, "HOTPLUG");
1698 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001699 return 0;
1700
David Herrmann6ac52db2012-03-11 20:05:22 +01001701 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001702}
1703
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001704static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001705udev_drm_event(int fd, uint32_t mask, void *data)
1706{
1707 struct drm_compositor *ec = data;
1708 struct udev_device *event;
1709
1710 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001711
David Herrmannd7488c22012-03-11 20:05:21 +01001712 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001713 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001714
1715 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001716
1717 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001718}
1719
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001720static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001721drm_restore(struct weston_compositor *ec)
1722{
1723 struct drm_compositor *d = (struct drm_compositor *) ec;
1724
1725 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1726 weston_log("failed to drop master: %m\n");
1727 tty_reset(d->tty);
1728}
1729
Pekka Paalanen33156972012-08-03 13:30:30 -04001730static const char default_seat[] = "seat0";
1731
1732static void
1733device_added(struct udev_device *udev_device, struct drm_seat *master)
1734{
1735 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001736 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001737 const char *devnode;
1738 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001739 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001740 int fd;
1741
1742 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1743 if (!device_seat)
1744 device_seat = default_seat;
1745
1746 if (strcmp(device_seat, master->seat_id))
1747 return;
1748
1749 c = master->base.compositor;
1750 devnode = udev_device_get_devnode(udev_device);
1751
1752 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001753 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001754 * read. mtdev_get() also expects this. */
1755 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1756 if (fd < 0) {
1757 weston_log("opening input device '%s' failed.\n", devnode);
1758 return;
1759 }
1760
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001761 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001762 if (!device) {
1763 close(fd);
1764 weston_log("not using input device '%s'.\n", devnode);
1765 return;
1766 }
1767
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001768 calibration_values =
1769 udev_device_get_property_value(udev_device,
1770 "WL_CALIBRATION");
1771
1772 if (calibration_values && sscanf(calibration_values,
1773 "%f %f %f %f %f %f",
1774 &device->abs.calibration[0],
1775 &device->abs.calibration[1],
1776 &device->abs.calibration[2],
1777 &device->abs.calibration[3],
1778 &device->abs.calibration[4],
1779 &device->abs.calibration[5]) == 6) {
1780 device->abs.apply_calibration = 1;
1781 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1782 device->abs.calibration[0],
1783 device->abs.calibration[1],
1784 device->abs.calibration[2],
1785 device->abs.calibration[3],
1786 device->abs.calibration[4],
1787 device->abs.calibration[5]);
1788 }
1789
Pekka Paalanen33156972012-08-03 13:30:30 -04001790 wl_list_insert(master->devices_list.prev, &device->link);
1791}
1792
1793static void
1794evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1795{
1796 struct drm_seat *seat = (struct drm_seat *) seat_base;
1797 struct udev_enumerate *e;
1798 struct udev_list_entry *entry;
1799 struct udev_device *device;
1800 const char *path, *sysname;
1801
1802 e = udev_enumerate_new(udev);
1803 udev_enumerate_add_match_subsystem(e, "input");
1804 udev_enumerate_scan_devices(e);
1805 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1806 path = udev_list_entry_get_name(entry);
1807 device = udev_device_new_from_syspath(udev, path);
1808
1809 sysname = udev_device_get_sysname(device);
1810 if (strncmp("event", sysname, 5) != 0) {
1811 udev_device_unref(device);
1812 continue;
1813 }
1814
1815 device_added(device, seat);
1816
1817 udev_device_unref(device);
1818 }
1819 udev_enumerate_unref(e);
1820
1821 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1822
1823 if (wl_list_empty(&seat->devices_list)) {
1824 weston_log(
1825 "warning: no input devices on entering Weston. "
1826 "Possible causes:\n"
1827 "\t- no permissions to read /dev/input/event*\n"
1828 "\t- seats misconfigured "
1829 "(Weston backend option 'seat', "
1830 "udev device property ID_SEAT)\n");
1831 }
1832}
1833
1834static int
1835evdev_udev_handler(int fd, uint32_t mask, void *data)
1836{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001837 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001838 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001839 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001840 const char *action;
1841 const char *devnode;
1842
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001843 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001844 if (!udev_device)
1845 return 1;
1846
1847 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001848 if (!action)
1849 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001850
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001851 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1852 goto out;
1853
1854 if (!strcmp(action, "add")) {
1855 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001856 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001857 else if (!strcmp(action, "remove")) {
1858 devnode = udev_device_get_devnode(udev_device);
1859 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1860 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001861 weston_log("input device %s, %s removed\n",
1862 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001863 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001864 break;
1865 }
1866 }
1867
1868out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001869 udev_device_unref(udev_device);
1870
1871 return 0;
1872}
1873
1874static int
1875evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1876{
1877 struct drm_seat *master = (struct drm_seat *) seat_base;
1878 struct wl_event_loop *loop;
1879 struct weston_compositor *c = master->base.compositor;
1880 int fd;
1881
1882 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1883 if (!master->udev_monitor) {
1884 weston_log("udev: failed to create the udev monitor\n");
1885 return 0;
1886 }
1887
1888 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1889 "input", NULL);
1890
1891 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1892 weston_log("udev: failed to bind the udev monitor\n");
1893 udev_monitor_unref(master->udev_monitor);
1894 return 0;
1895 }
1896
1897 loop = wl_display_get_event_loop(c->wl_display);
1898 fd = udev_monitor_get_fd(master->udev_monitor);
1899 master->udev_monitor_source =
1900 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1901 evdev_udev_handler, master);
1902 if (!master->udev_monitor_source) {
1903 udev_monitor_unref(master->udev_monitor);
1904 return 0;
1905 }
1906
1907 return 1;
1908}
1909
1910static void
1911evdev_disable_udev_monitor(struct weston_seat *seat_base)
1912{
1913 struct drm_seat *seat = (struct drm_seat *) seat_base;
1914
1915 if (!seat->udev_monitor)
1916 return;
1917
1918 udev_monitor_unref(seat->udev_monitor);
1919 seat->udev_monitor = NULL;
1920 wl_event_source_remove(seat->udev_monitor_source);
1921 seat->udev_monitor_source = NULL;
1922}
1923
1924static void
1925drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1926{
1927 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001928 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001929
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001930 wl_list_for_each(device, &seat->devices_list, link)
1931 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001932}
1933
1934static void
1935evdev_input_create(struct weston_compositor *c, struct udev *udev,
1936 const char *seat_id)
1937{
1938 struct drm_seat *seat;
1939
1940 seat = malloc(sizeof *seat);
1941 if (seat == NULL)
1942 return;
1943
1944 memset(seat, 0, sizeof *seat);
1945 weston_seat_init(&seat->base, c);
1946 seat->base.led_update = drm_led_update;
1947
1948 wl_list_init(&seat->devices_list);
1949 seat->seat_id = strdup(seat_id);
1950 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1951 free(seat->seat_id);
1952 free(seat);
1953 return;
1954 }
1955
1956 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001957}
1958
1959static void
1960evdev_remove_devices(struct weston_seat *seat_base)
1961{
1962 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001963 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001964
1965 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001966 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001967
Pekka Paalanend8583512012-08-03 14:39:11 +03001968 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001969 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001970}
1971
1972static void
1973evdev_input_destroy(struct weston_seat *seat_base)
1974{
1975 struct drm_seat *seat = (struct drm_seat *) seat_base;
1976
1977 evdev_remove_devices(seat_base);
1978 evdev_disable_udev_monitor(&seat->base);
1979
1980 weston_seat_release(seat_base);
1981 free(seat->seat_id);
1982 free(seat);
1983}
1984
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001985static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001986drm_free_configured_output(struct drm_configured_output *output)
1987{
1988 free(output->name);
1989 free(output->mode);
1990 free(output);
1991}
1992
1993static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001994drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001995{
1996 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001997 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001998 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001999
Daniel Stone37816df2012-05-16 18:45:18 +01002000 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2001 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002002 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002003 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002004
2005 wl_event_source_remove(d->udev_drm_source);
2006 wl_event_source_remove(d->drm_source);
2007
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002008 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002009
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002010 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002011
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002012 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002013 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002014 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002015 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002016 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002017
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002018 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002019}
2020
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002021static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002022drm_compositor_set_modes(struct drm_compositor *compositor)
2023{
2024 struct drm_output *output;
2025 struct drm_mode *drm_mode;
2026 int ret;
2027
2028 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2029 drm_mode = (struct drm_mode *) output->base.current;
2030 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002031 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002032 &output->connector_id, 1,
2033 &drm_mode->mode_info);
2034 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002035 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002036 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002037 drm_mode->base.width, drm_mode->base.height,
2038 output->base.x, output->base.y);
2039 }
2040 }
2041}
2042
2043static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002044vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002045{
2046 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002047 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002048 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002049 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002050
2051 switch (event) {
2052 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002053 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002054 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002055 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002056 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002057 wl_display_terminate(compositor->wl_display);
2058 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002059 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002060 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002061 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002062 wl_list_for_each(seat, &compositor->seat_list, link) {
2063 evdev_add_devices(ec->udev, seat);
2064 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002065 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002066 break;
2067 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002068 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002069 wl_list_for_each(seat, &compositor->seat_list, link) {
2070 evdev_disable_udev_monitor(seat);
2071 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002072 }
2073
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002074 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002075 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002076 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002077
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002078 /* If we have a repaint scheduled (either from a
2079 * pending pageflip or the idle handler), make sure we
2080 * cancel that so we don't try to pageflip when we're
2081 * vt switched away. The SLEEPING state will prevent
2082 * further attemps at repainting. When we switch
2083 * back, we schedule a repaint, which will process
2084 * pending frame callbacks. */
2085
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002086 wl_list_for_each(output, &ec->base.output_list, base.link) {
2087 output->base.repaint_needed = 0;
2088 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002089 }
2090
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002091 output = container_of(ec->base.output_list.next,
2092 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002093
2094 wl_list_for_each(sprite, &ec->sprite_list, link)
2095 drmModeSetPlane(ec->drm.fd,
2096 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002097 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002098 0, 0, 0, 0, 0, 0, 0, 0);
2099
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002100 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002101 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002102
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002103 break;
2104 };
2105}
2106
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002107static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002108switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002109{
2110 struct drm_compositor *ec = data;
2111
Daniel Stone325fc2d2012-05-30 16:31:58 +01002112 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002113}
2114
David Herrmann0af066f2012-10-29 19:21:16 +01002115/*
2116 * Find primary GPU
2117 * Some systems may have multiple DRM devices attached to a single seat. This
2118 * function loops over all devices and tries to find a PCI device with the
2119 * boot_vga sysfs attribute set to 1.
2120 * If no such device is found, the first DRM device reported by udev is used.
2121 */
2122static struct udev_device*
2123find_primary_gpu(struct drm_compositor *ec, const char *seat)
2124{
2125 struct udev_enumerate *e;
2126 struct udev_list_entry *entry;
2127 const char *path, *device_seat, *id;
2128 struct udev_device *device, *drm_device, *pci;
2129
2130 e = udev_enumerate_new(ec->udev);
2131 udev_enumerate_add_match_subsystem(e, "drm");
2132 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2133
2134 udev_enumerate_scan_devices(e);
2135 drm_device = NULL;
2136 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2137 path = udev_list_entry_get_name(entry);
2138 device = udev_device_new_from_syspath(ec->udev, path);
2139 if (!device)
2140 continue;
2141 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2142 if (!device_seat)
2143 device_seat = default_seat;
2144 if (strcmp(device_seat, seat)) {
2145 udev_device_unref(device);
2146 continue;
2147 }
2148
2149 pci = udev_device_get_parent_with_subsystem_devtype(device,
2150 "pci", NULL);
2151 if (pci) {
2152 id = udev_device_get_sysattr_value(pci, "boot_vga");
2153 if (id && !strcmp(id, "1")) {
2154 if (drm_device)
2155 udev_device_unref(drm_device);
2156 drm_device = device;
2157 break;
2158 }
2159 }
2160
2161 if (!drm_device)
2162 drm_device = device;
2163 else
2164 udev_device_unref(device);
2165 }
2166
2167 udev_enumerate_unref(e);
2168 return drm_device;
2169}
2170
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002171static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002172planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002173{
2174 struct drm_compositor *c = data;
2175
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002176 switch (key) {
2177 case KEY_C:
2178 c->cursors_are_broken ^= 1;
2179 break;
2180 case KEY_V:
2181 c->sprites_are_broken ^= 1;
2182 break;
2183 case KEY_O:
2184 c->sprites_hidden ^= 1;
2185 break;
2186 default:
2187 break;
2188 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002189}
2190
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002191static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002192drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002193 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002194 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002195{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002196 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002197 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002198 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002199 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002200 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002201 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002202
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002203 weston_log("initializing drm backend\n");
2204
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002205 ec = malloc(sizeof *ec);
2206 if (ec == NULL)
2207 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002208 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002209
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002210 /* KMS support for sprites is not complete yet, so disable the
2211 * functionality for now. */
2212 ec->sprites_are_broken = 1;
2213
Daniel Stone725c2c32012-06-22 14:04:36 +01002214 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002215 config_file) < 0) {
2216 weston_log("weston_compositor_init failed\n");
2217 goto err_base;
2218 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002219
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002220 ec->udev = udev_new();
2221 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002222 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002223 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002224 }
2225
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002226 ec->base.wl_display = display;
2227 ec->tty = tty_create(&ec->base, vt_func, tty);
2228 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002229 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002230 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002231 }
2232
David Herrmann0af066f2012-10-29 19:21:16 +01002233 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002234 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002235 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002236 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002237 }
David Herrmann0af066f2012-10-29 19:21:16 +01002238 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002239
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002240 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002241 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002242 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002243 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002244
2245 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002246 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002247
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002248 ec->base.focus = 1;
2249
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002250 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002251
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002252 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002253 weston_compositor_add_key_binding(&ec->base, key,
2254 MODIFIER_CTRL | MODIFIER_ALT,
2255 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002256
Jesse Barnes58ef3792012-02-23 09:45:49 -05002257 wl_list_init(&ec->sprite_list);
2258 create_sprites(ec);
2259
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002260 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002261 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002262 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002263 }
2264
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002265 path = NULL;
2266
Tiago Vignattice03ec32011-12-19 01:14:03 +02002267 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002268
2269 loop = wl_display_get_event_loop(ec->base.wl_display);
2270 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002271 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002272 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002273
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002274 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2275 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002276 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002277 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002278 }
2279 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2280 "drm", NULL);
2281 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002282 wl_event_loop_add_fd(loop,
2283 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002284 WL_EVENT_READABLE, udev_drm_event, ec);
2285
2286 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002287 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002288 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002289 }
2290
Daniel Stonea96b93c2012-06-22 14:04:37 +01002291 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002292
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002293 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002294 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002295 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002296 planes_binding, ec);
2297 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2298 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002299
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002300 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002301
2302err_udev_monitor:
2303 wl_event_source_remove(ec->udev_drm_source);
2304 udev_monitor_unref(ec->udev_monitor);
2305err_drm_source:
2306 wl_event_source_remove(ec->drm_source);
2307 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2308 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002309err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002310 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002311 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002312 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002313err_udev_dev:
2314 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002315err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002316 tty_destroy(ec->tty);
2317err_udev:
2318 udev_unref(ec->udev);
2319err_compositor:
2320 weston_compositor_shutdown(&ec->base);
2321err_base:
2322 free(ec);
2323 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002324}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002325
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002326static int
2327set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2328{
2329 mode->flags = 0;
2330
2331 if (strcmp(hsync, "+hsync") == 0)
2332 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2333 else if (strcmp(hsync, "-hsync") == 0)
2334 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2335 else
2336 return -1;
2337
2338 if (strcmp(vsync, "+vsync") == 0)
2339 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2340 else if (strcmp(vsync, "-vsync") == 0)
2341 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2342 else
2343 return -1;
2344
2345 return 0;
2346}
2347
2348static int
2349check_for_modeline(struct drm_configured_output *output)
2350{
2351 drmModeModeInfo mode;
2352 char hsync[16];
2353 char vsync[16];
2354 char mode_name[16];
2355 float fclock;
2356
2357 mode.type = DRM_MODE_TYPE_USERDEF;
2358 mode.hskew = 0;
2359 mode.vscan = 0;
2360 mode.vrefresh = 0;
2361
2362 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2363 &fclock, &mode.hdisplay,
2364 &mode.hsync_start,
2365 &mode.hsync_end, &mode.htotal,
2366 &mode.vdisplay,
2367 &mode.vsync_start,
2368 &mode.vsync_end, &mode.vtotal,
2369 hsync, vsync) == 11) {
2370 if (set_sync_flags(&mode, hsync, vsync))
2371 return -1;
2372
2373 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2374 strcpy(mode.name, mode_name);
2375
2376 mode.clock = fclock * 1000;
2377 } else
2378 return -1;
2379
2380 output->crtc_mode = mode;
2381
2382 return 0;
2383}
2384
Scott Moreau8ab5d452012-07-30 19:51:08 -06002385static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002386drm_output_set_transform(struct drm_configured_output *output)
2387{
2388 if (!output_transform) {
2389 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2390 return;
2391 }
2392
2393 if (!strcmp(output_transform, "normal"))
2394 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2395 else if (!strcmp(output_transform, "90"))
2396 output->transform = WL_OUTPUT_TRANSFORM_90;
2397 else if (!strcmp(output_transform, "180"))
2398 output->transform = WL_OUTPUT_TRANSFORM_180;
2399 else if (!strcmp(output_transform, "270"))
2400 output->transform = WL_OUTPUT_TRANSFORM_270;
2401 else if (!strcmp(output_transform, "flipped"))
2402 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2403 else if (!strcmp(output_transform, "flipped-90"))
2404 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2405 else if (!strcmp(output_transform, "flipped-180"))
2406 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2407 else if (!strcmp(output_transform, "flipped-270"))
2408 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2409 else {
2410 weston_log("Invalid transform \"%s\" for output %s\n",
2411 output_transform, output_name);
2412 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2413 }
2414
2415 free(output_transform);
2416 output_transform = NULL;
2417}
2418
2419static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002420output_section_done(void *data)
2421{
2422 struct drm_configured_output *output;
2423
2424 output = malloc(sizeof *output);
2425
Scott Moreau1bad5db2012-08-18 01:04:05 -06002426 if (!output || !output_name || (output_name[0] == 'X') ||
2427 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002428 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002429 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002430 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002431 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002432 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002433 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002434 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002435 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002436 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002437
2438 output->config = OUTPUT_CONFIG_INVALID;
2439 output->name = output_name;
2440 output->mode = output_mode;
2441
Scott Moreau1bad5db2012-08-18 01:04:05 -06002442 if (output_mode) {
2443 if (strcmp(output_mode, "off") == 0)
2444 output->config = OUTPUT_CONFIG_OFF;
2445 else if (strcmp(output_mode, "preferred") == 0)
2446 output->config = OUTPUT_CONFIG_PREFERRED;
2447 else if (strcmp(output_mode, "current") == 0)
2448 output->config = OUTPUT_CONFIG_CURRENT;
2449 else if (sscanf(output_mode, "%dx%d",
2450 &output->width, &output->height) == 2)
2451 output->config = OUTPUT_CONFIG_MODE;
2452 else if (check_for_modeline(output) == 0)
2453 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002454
Scott Moreau1bad5db2012-08-18 01:04:05 -06002455 if (output->config == OUTPUT_CONFIG_INVALID)
2456 weston_log("Invalid mode \"%s\" for output %s\n",
2457 output_mode, output_name);
2458 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002459 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002460
2461 drm_output_set_transform(output);
2462
2463 wl_list_insert(&configured_output_list, &output->link);
2464
2465 if (output_transform)
2466 free(output_transform);
2467 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002468}
2469
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002470WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002471backend_init(struct wl_display *display, int argc, char *argv[],
2472 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002473{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002474 int connector = 0, tty = 0;
2475 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002476
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002477 const struct weston_option drm_options[] = {
2478 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2479 { WESTON_OPTION_STRING, "seat", 0, &seat },
2480 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002481 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002482 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002483
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002484 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002485
Scott Moreau8ab5d452012-07-30 19:51:08 -06002486 wl_list_init(&configured_output_list);
2487
2488 const struct config_key drm_config_keys[] = {
2489 { "name", CONFIG_KEY_STRING, &output_name },
2490 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002491 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002492 };
2493
2494 const struct config_section config_section[] = {
2495 { "output", drm_config_keys,
2496 ARRAY_LENGTH(drm_config_keys), output_section_done },
2497 };
2498
2499 parse_config_file(config_file, config_section,
2500 ARRAY_LENGTH(config_section), NULL);
2501
Daniel Stonec1be8e52012-06-01 11:14:02 -04002502 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2503 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002504}