blob: c44da97dd667ceab62d380624e057fe33f54f42c [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 *
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200216drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_compositor *compositor)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300217{
218 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200219 uint32_t width, height, stride, handle, format;
220 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300221 int ret;
222
223 if (fb)
224 return fb;
225
226 fb = malloc(sizeof *fb);
227
228 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300229 fb->is_client_buffer = 0;
Pekka Paalanende685b82012-12-04 15:58:12 +0200230 fb->buffer_ref.buffer = NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300231
232 width = gbm_bo_get_width(bo);
233 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400234 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300235 handle = gbm_bo_get_handle(bo).u32;
236
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200237 if (compositor->min_width > width || width > compositor->max_width ||
238 compositor->min_height > height ||
239 height > compositor->max_height) {
240 weston_log("bo geometry out of bounds\n");
241 goto err_free;
242 }
243
244 ret = -1;
245
246 format = gbm_bo_get_format(bo);
247
248 if (format && !compositor->no_addfb2) {
249 handles[0] = handle;
250 pitches[0] = stride;
251 offsets[0] = 0;
252
253 ret = drmModeAddFB2(compositor->drm.fd, width, height,
254 format, handles, pitches, offsets,
255 &fb->fb_id, 0);
256 if (ret) {
257 weston_log("addfb2 failed: %m\n");
258 compositor->no_addfb2 = 1;
259 compositor->sprites_are_broken = 1;
260 }
261 }
262
263 if (ret)
264 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
265 stride, handle, &fb->fb_id);
266
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300267 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200268 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200269 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300270 }
271
272 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
273
274 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200275
276err_free:
277 free(fb);
278 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300279}
280
281static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200282drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
283{
Pekka Paalanende685b82012-12-04 15:58:12 +0200284 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200285
286 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200287
Pekka Paalanende685b82012-12-04 15:58:12 +0200288 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200289}
290
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200291static int
292drm_output_check_scanout_format(struct drm_output *output,
293 struct weston_surface *es, struct gbm_bo *bo)
294{
295 int ret = 0;
296 uint32_t format;
297 pixman_region32_t r;
298
299 format = gbm_bo_get_format(bo);
300
301 if (format == GBM_FORMAT_XRGB8888)
302 ret = 1;
303 else if (format == GBM_FORMAT_ARGB8888) {
304 /* We can only scanout an ARGB buffer if the surface's
305 * opaque region covers the whole output */
306 pixman_region32_init(&r);
307 pixman_region32_subtract(&r, &output->base.region,
308 &es->opaque);
309
310 if (!pixman_region32_not_empty(&r))
311 ret = 1;
312
313 pixman_region32_fini(&r);
314 }
315
316 return ret;
317}
318
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400319static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400320drm_output_prepare_scanout_surface(struct weston_output *_output,
321 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500322{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400323 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500324 struct drm_compositor *c =
325 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200326 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500328
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500329 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200330 es->geometry.y != output->base.y ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200331 buffer == NULL ||
332 buffer->width != output->base.current->width ||
333 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200334 output->base.transform != es->buffer_transform ||
335 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400336 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500337
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400338 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200339 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500340
Rob Bradford9b101872012-09-14 23:25:41 +0100341 /* Unable to use the buffer for scanout */
342 if (!bo)
343 return NULL;
344
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200345 if (!drm_output_check_scanout_format(output, es, bo)) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300346 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400347 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300348 }
349
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200350 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300351 if (!output->next) {
352 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400353 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500355
Pekka Paalanende685b82012-12-04 15:58:12 +0200356 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500357
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400358 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500359}
360
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500361static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400362drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400363{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 struct drm_compositor *c =
365 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400367
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200368 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400369
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200370 pixman_region32_subtract(&c->base.primary_plane.damage,
371 &c->base.primary_plane.damage, damage);
372
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300373 bo = gbm_surface_lock_front_buffer(output->surface);
374 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200375 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400376 return;
377 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300378
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300380 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200381 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300382 gbm_surface_release_buffer(output->surface, bo);
383 return;
384 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400385}
386
387static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500388drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400389 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100390{
391 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500392 struct drm_compositor *compositor =
393 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500394 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400395 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500396 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100397
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300398 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400399 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300400 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400401 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100402
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400403 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400405 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300406 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400407 &output->connector_id, 1,
408 &mode->mode_info);
409 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200410 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400411 return;
412 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200413 }
414
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500415 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300416 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500417 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200418 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500419 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500420 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100421
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300422 output->page_flip_pending = 1;
423
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400424 drm_output_set_cursor(output);
425
Jesse Barnes58ef3792012-02-23 09:45:49 -0500426 /*
427 * Now, update all the sprite surfaces
428 */
429 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200430 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500431 drmVBlank vbl = {
432 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
433 .request.sequence = 1,
434 };
435
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200436 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200437 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500438 continue;
439
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200440 if (s->next && !compositor->sprites_hidden)
441 fb_id = s->next->fb_id;
442
Jesse Barnes58ef3792012-02-23 09:45:49 -0500443 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200444 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500445 s->dest_x, s->dest_y,
446 s->dest_w, s->dest_h,
447 s->src_x, s->src_y,
448 s->src_w, s->src_h);
449 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200450 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500451 ret, strerror(errno));
452
Rob Clark5ca1a472012-08-08 20:27:37 -0500453 if (output->pipe > 0)
454 vbl.request.type |= DRM_VBLANK_SECONDARY;
455
Jesse Barnes58ef3792012-02-23 09:45:49 -0500456 /*
457 * Queue a vblank signal so we know when the surface
458 * becomes active on the display or has been replaced.
459 */
460 vbl.request.signal = (unsigned long)s;
461 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
462 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200463 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500464 ret, strerror(errno));
465 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300466
467 s->output = output;
468 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500469 }
470
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500471 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400472}
473
474static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500475vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
476 void *data)
477{
478 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300479 struct drm_output *output = s->output;
480 uint32_t msecs;
481
482 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500483
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200484 if (s->current)
485 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500486
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200487 s->current = s->next;
488 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300489
490 if (!output->page_flip_pending) {
491 msecs = sec * 1000 + usec / 1000;
492 weston_output_finish_frame(&output->base, msecs);
493 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500494}
495
496static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400497page_flip_handler(int fd, unsigned int frame,
498 unsigned int sec, unsigned int usec, void *data)
499{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200500 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400501 uint32_t msecs;
502
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300503 output->page_flip_pending = 0;
504
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300505 if (output->current) {
506 if (output->current->is_client_buffer)
507 gbm_bo_destroy(output->current->bo);
508 else
509 gbm_surface_release_buffer(output->surface,
510 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200511 }
512
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300513 output->current = output->next;
514 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300516 if (!output->vblank_pending) {
517 msecs = sec * 1000 + usec / 1000;
518 weston_output_finish_frame(&output->base, msecs);
519 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200520}
521
522static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500523drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
524{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400525 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500526
527 for (i = 0; i < s->count_formats; i++)
528 if (s->formats[i] == format)
529 return 1;
530
531 return 0;
532}
533
534static int
535drm_surface_transform_supported(struct weston_surface *es)
536{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400537 struct weston_matrix *matrix = &es->transform.matrix;
538 int i;
539
540 if (!es->transform.enabled)
541 return 1;
542
543 for (i = 0; i < 16; i++) {
544 switch (i) {
545 case 10:
546 case 15:
547 if (matrix->d[i] != 1.0)
548 return 0;
549 break;
550 case 0:
551 case 5:
552 case 12:
553 case 13:
554 break;
555 default:
556 if (matrix->d[i] != 0.0)
557 return 0;
558 break;
559 }
560 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500561
562 return 1;
563}
564
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400565static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500566drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400567 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500568{
569 struct weston_compositor *ec = output_base->compositor;
570 struct drm_compositor *c =(struct drm_compositor *) ec;
571 struct drm_sprite *s;
572 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500573 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200575 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500576 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400577 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500578
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200579 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200580 return NULL;
581
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500582 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400583 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500584
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300585 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400586 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300587
Pekka Paalanende685b82012-12-04 15:58:12 +0200588 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400589 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500590
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200591 if (es->alpha != 1.0f)
592 return NULL;
593
Pekka Paalanende685b82012-12-04 15:58:12 +0200594 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500595 return NULL;
596
Jesse Barnes58ef3792012-02-23 09:45:49 -0500597 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400598 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600 wl_list_for_each(s, &c->sprite_list, link) {
601 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
602 continue;
603
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200604 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 found = 1;
606 break;
607 }
608 }
609
610 /* No sprites available */
611 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400612 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400614 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200615 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400616 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400617 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400618
Jesse Barnes58ef3792012-02-23 09:45:49 -0500619 format = gbm_bo_get_format(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200621 if (!drm_surface_format_supported(s, format)) {
622 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400623 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 }
625
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200626 s->next = drm_fb_get_from_bo(bo, c);
627 if (!s->next) {
628 gbm_bo_destroy(bo);
629 return NULL;
630 }
631
Pekka Paalanende685b82012-12-04 15:58:12 +0200632 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500633
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400634 box = pixman_region32_extents(&es->transform.boundingbox);
635 s->plane.x = box->x1;
636 s->plane.y = box->y1;
637
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638 /*
639 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200640 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 * for us already).
642 */
643 pixman_region32_init(&dest_rect);
644 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
645 &output_base->region);
646 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
647 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200648 tbox = weston_transformed_rect(output_base->width,
649 output_base->height,
650 output_base->transform, *box);
651 s->dest_x = tbox.x1;
652 s->dest_y = tbox.y1;
653 s->dest_w = tbox.x2 - tbox.x1;
654 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655 pixman_region32_fini(&dest_rect);
656
657 pixman_region32_init(&src_rect);
658 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
659 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500660 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400661
662 weston_surface_from_global_fixed(es,
663 wl_fixed_from_int(box->x1),
664 wl_fixed_from_int(box->y1),
665 &sx1, &sy1);
666 weston_surface_from_global_fixed(es,
667 wl_fixed_from_int(box->x2),
668 wl_fixed_from_int(box->y2),
669 &sx2, &sy2);
670
671 if (sx1 < 0)
672 sx1 = 0;
673 if (sy1 < 0)
674 sy1 = 0;
675 if (sx2 > wl_fixed_from_int(es->geometry.width))
676 sx2 = wl_fixed_from_int(es->geometry.width);
677 if (sy2 > wl_fixed_from_int(es->geometry.height))
678 sy2 = wl_fixed_from_int(es->geometry.height);
679
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200680 tbox.x1 = sx1;
681 tbox.y1 = sy1;
682 tbox.x2 = sx2;
683 tbox.y2 = sy2;
684
685 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
686 wl_fixed_from_int(es->geometry.height),
687 es->buffer_transform, tbox);
688
689 s->src_x = tbox.x1 << 8;
690 s->src_y = tbox.y1 << 8;
691 s->src_w = (tbox.x2 - tbox.x1) << 8;
692 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500693 pixman_region32_fini(&src_rect);
694
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400695 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500696}
697
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400698static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400699drm_output_prepare_cursor_surface(struct weston_output *output_base,
700 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500701{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400702 struct drm_compositor *c =
703 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400704 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400705
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200706 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
707 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400708 if (output->cursor_surface)
709 return NULL;
710 if (es->output_mask != (1u << output_base->id))
711 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500712 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400713 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200714 if (es->buffer_ref.buffer == NULL ||
715 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400716 es->geometry.width > 64 || es->geometry.height > 64)
717 return NULL;
718
719 output->cursor_surface = es;
720
721 return &output->cursor_plane;
722}
723
724static void
725drm_output_set_cursor(struct drm_output *output)
726{
727 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400728 struct drm_compositor *c =
729 (struct drm_compositor *) output->base.compositor;
730 EGLint handle, stride;
731 struct gbm_bo *bo;
732 uint32_t buf[64 * 64];
733 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400734 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500735
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400736 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400737 if (es == NULL) {
738 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
739 return;
740 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500741
Pekka Paalanende685b82012-12-04 15:58:12 +0200742 if (es->buffer_ref.buffer &&
743 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400744 pixman_region32_fini(&output->cursor_plane.damage);
745 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400746 output->current_cursor ^= 1;
747 bo = output->cursor_bo[output->current_cursor];
748 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200749 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
750 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400751 for (i = 0; i < es->geometry.height; i++)
752 memcpy(buf + i * 64, s + i * stride,
753 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500754
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400755 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300756 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400757
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400758 handle = gbm_bo_get_handle(bo).s32;
759 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500760 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300761 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500762 c->cursors_are_broken = 1;
763 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400764 }
765
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400766 x = es->geometry.x - output->base.x;
767 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400768 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500769 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400770 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500771 c->cursors_are_broken = 1;
772 }
773
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400774 output->cursor_plane.x = x;
775 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400776 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500777}
778
Jesse Barnes58ef3792012-02-23 09:45:49 -0500779static void
780drm_assign_planes(struct weston_output *output)
781{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400782 struct drm_compositor *c =
783 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200784 struct drm_output *drm_output = (struct drm_output *) output;
785 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400786 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500787 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400788 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500789
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200790 /* Reset the opaque region of the planes */
791 pixman_region32_fini(&drm_output->cursor_plane.opaque);
792 pixman_region32_init(&drm_output->cursor_plane.opaque);
793 pixman_region32_fini(&drm_output->fb_plane.opaque);
794 pixman_region32_init(&drm_output->fb_plane.opaque);
795
796 wl_list_for_each (s, &c->sprite_list, link) {
797 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
798 continue;
799
800 pixman_region32_fini(&s->plane.opaque);
801 pixman_region32_init(&s->plane.opaque);
802 }
803
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804 /*
805 * Find a surface for each sprite in the output using some heuristics:
806 * 1) size
807 * 2) frequency of update
808 * 3) opacity (though some hw might support alpha blending)
809 * 4) clipping (this can be fixed with color keys)
810 *
811 * The idea is to save on blitting since this should save power.
812 * If we can get a large video surface on the sprite for example,
813 * the main display surface may not need to update at all, and
814 * the client buffer can be used directly for the sprite surface
815 * as we do for flipping full screen surfaces.
816 */
817 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400818 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400819 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200820 /* test whether this buffer can ever go into a plane:
821 * non-shm, or small enough to be a cursor
822 */
823 if ((es->buffer_ref.buffer &&
824 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
825 (es->geometry.width <= 64 && es->geometry.height <= 64))
826 es->keep_buffer = 1;
827 else
828 es->keep_buffer = 0;
829
Jesse Barnes58ef3792012-02-23 09:45:49 -0500830 pixman_region32_init(&surface_overlap);
831 pixman_region32_intersect(&surface_overlap, &overlap,
832 &es->transform.boundingbox);
833
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400835 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400836 next_plane = primary;
837 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400838 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400839 if (next_plane == NULL)
840 next_plane = drm_output_prepare_scanout_surface(output, es);
841 if (next_plane == NULL)
842 next_plane = drm_output_prepare_overlay_surface(output, es);
843 if (next_plane == NULL)
844 next_plane = primary;
845 weston_surface_move_to_plane(es, next_plane);
846 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500847 pixman_region32_union(&overlap, &overlap,
848 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400849
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850 pixman_region32_fini(&surface_overlap);
851 }
852 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500853}
854
Matt Roper361d2ad2011-08-29 13:52:23 -0700855static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500856drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700857{
858 struct drm_output *output = (struct drm_output *) output_base;
859 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200860 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700861 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700862
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200863 if (output->backlight)
864 backlight_destroy(output->backlight);
865
Matt Roper361d2ad2011-08-29 13:52:23 -0700866 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400867 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700868
869 /* Restore original CRTC state */
870 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200871 origcrtc->x, origcrtc->y,
872 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700873 drmModeFreeCrtc(origcrtc);
874
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200875 c->crtc_allocator &= ~(1 << output->crtc_id);
876 c->connector_allocator &= ~(1 << output->connector_id);
877
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100878 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100879
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400880 gbm_surface_destroy(output->surface);
881
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400882 weston_plane_release(&output->fb_plane);
883 weston_plane_release(&output->cursor_plane);
884
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500885 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200886 wl_list_remove(&output->base.link);
887
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400888 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700889 free(output);
890}
891
Alex Wub7b8bda2012-04-17 17:20:48 +0800892static struct drm_mode *
893choose_mode (struct drm_output *output, struct weston_mode *target_mode)
894{
895 struct drm_mode *tmp_mode = NULL, *mode;
896
897 if (output->base.current->width == target_mode->width &&
898 output->base.current->height == target_mode->height &&
899 (output->base.current->refresh == target_mode->refresh ||
900 target_mode->refresh == 0))
901 return (struct drm_mode *)output->base.current;
902
903 wl_list_for_each(mode, &output->base.mode_list, base.link) {
904 if (mode->mode_info.hdisplay == target_mode->width &&
905 mode->mode_info.vdisplay == target_mode->height) {
906 if (mode->mode_info.vrefresh == target_mode->refresh ||
907 target_mode->refresh == 0) {
908 return mode;
909 } else if (!tmp_mode)
910 tmp_mode = mode;
911 }
912 }
913
914 return tmp_mode;
915}
916
917static int
918drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
919{
920 struct drm_output *output;
921 struct drm_mode *drm_mode;
922 int ret;
923 struct drm_compositor *ec;
924 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800925
926 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200927 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800928 return -1;
929 }
930
931 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200932 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800933 return -1;
934 }
935
936 ec = (struct drm_compositor *)output_base->compositor;
937 output = (struct drm_output *)output_base;
938 drm_mode = choose_mode (output, mode);
939
940 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200941 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800942 return -1;
943 } else if (&drm_mode->base == output->base.current) {
944 return 0;
945 } else if (drm_mode->base.width == output->base.current->width &&
946 drm_mode->base.height == output->base.current->height) {
947 /* only change refresh value */
948 ret = drmModeSetCrtc(ec->drm.fd,
949 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300950 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800951 &output->connector_id, 1, &drm_mode->mode_info);
952
953 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200954 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800955 drm_mode->base.width,
956 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400957 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800958 ret = -1;
959 } else {
960 output->base.current->flags = 0;
961 output->base.current = &drm_mode->base;
962 drm_mode->base.flags =
963 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
964 ret = 0;
965 }
966
967 return ret;
968 }
969
970 drm_mode->base.flags =
971 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
972
973 surface = gbm_surface_create(ec->gbm,
974 drm_mode->base.width,
975 drm_mode->base.height,
976 GBM_FORMAT_XRGB8888,
977 GBM_BO_USE_SCANOUT |
978 GBM_BO_USE_RENDERING);
979 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200980 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800981 return -1;
982 }
983
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100984 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800985
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100986 if (!gl_renderer_output_create(&output->base, surface)) {
John Kåre Alsaker94659272012-11-13 19:10:18 +0100987 weston_log("failed to create renderer output\n");
988 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +0800989 }
990
991 ret = drmModeSetCrtc(ec->drm.fd,
992 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300993 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800994 &output->connector_id, 1, &drm_mode->mode_info);
995 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200996 weston_log("failed to set mode\n");
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100997 goto err_gl;
Alex Wub7b8bda2012-04-17 17:20:48 +0800998 }
999
1000 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001001 if (output->current) {
1002 if (output->current->is_client_buffer)
1003 gbm_bo_destroy(output->current->bo);
1004 else
1005 gbm_surface_release_buffer(output->surface,
1006 output->current->bo);
1007 }
1008 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001009
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001010 if (output->next) {
1011 if (output->next->is_client_buffer)
1012 gbm_bo_destroy(output->next->bo);
1013 else
1014 gbm_surface_release_buffer(output->surface,
1015 output->next->bo);
1016 }
1017 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001018
Alex Wub7b8bda2012-04-17 17:20:48 +08001019 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001020 output->surface = surface;
1021
1022 /*update output*/
1023 output->base.current = &drm_mode->base;
1024 output->base.dirty = 1;
1025 weston_output_move(&output->base, output->base.x, output->base.y);
1026 return 0;
1027
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001028err_gl:
1029 gl_renderer_output_destroy(&output->base);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001030err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +08001031 gbm_surface_destroy(surface);
1032 return -1;
1033}
1034
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001035static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001036on_drm_input(int fd, uint32_t mask, void *data)
1037{
1038 drmEventContext evctx;
1039
1040 memset(&evctx, 0, sizeof evctx);
1041 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1042 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001043 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001044 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001045
1046 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001047}
1048
1049static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001050init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001051{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001052 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001053 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001054
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001055 sysnum = udev_device_get_sysnum(device);
1056 if (sysnum)
1057 ec->drm.id = atoi(sysnum);
1058 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001059 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001060 return -1;
1061 }
1062
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001063 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001064 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001065 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001066 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001067 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001068 udev_device_get_devnode(device));
1069 return -1;
1070 }
1071
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001072 weston_log("using %s\n", filename);
1073
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001074 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001075 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001076
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001077 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001078 NULL) < 0) {
1079 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001080 return -1;
1081 }
1082
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001083 return 0;
1084}
1085
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001086static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001087drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1088{
1089 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001090 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001091
1092 mode = malloc(sizeof *mode);
1093 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001094 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001095
1096 mode->base.flags = 0;
1097 mode->base.width = info->hdisplay;
1098 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001099
1100 /* Calculate higher precision (mHz) refresh rate */
1101 refresh = (info->clock * 1000000LL / info->htotal +
1102 info->vtotal / 2) / info->vtotal;
1103
1104 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1105 refresh *= 2;
1106 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1107 refresh /= 2;
1108 if (info->vscan > 1)
1109 refresh /= info->vscan;
1110
1111 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001112 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001113
1114 if (info->type & DRM_MODE_TYPE_PREFERRED)
1115 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1116
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001117 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1118
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001119 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001120}
1121
1122static int
1123drm_subpixel_to_wayland(int drm_value)
1124{
1125 switch (drm_value) {
1126 default:
1127 case DRM_MODE_SUBPIXEL_UNKNOWN:
1128 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1129 case DRM_MODE_SUBPIXEL_NONE:
1130 return WL_OUTPUT_SUBPIXEL_NONE;
1131 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1132 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1133 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1134 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1135 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1136 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1137 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1138 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1139 }
1140}
1141
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001142/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001143static uint32_t
1144drm_get_backlight(struct drm_output *output)
1145{
1146 long brightness, max_brightness, norm;
1147
1148 brightness = backlight_get_brightness(output->backlight);
1149 max_brightness = backlight_get_max_brightness(output->backlight);
1150
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001151 /* convert it on a scale of 0 to 255 */
1152 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001153
1154 return (uint32_t) norm;
1155}
1156
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001157/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001158static void
1159drm_set_backlight(struct weston_output *output_base, uint32_t value)
1160{
1161 struct drm_output *output = (struct drm_output *) output_base;
1162 long max_brightness, new_brightness;
1163
1164 if (!output->backlight)
1165 return;
1166
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001167 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001168 return;
1169
1170 max_brightness = backlight_get_max_brightness(output->backlight);
1171
1172 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001173 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001174
1175 backlight_set_brightness(output->backlight, new_brightness);
1176}
1177
1178static drmModePropertyPtr
1179drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1180{
1181 drmModePropertyPtr props;
1182 int i;
1183
1184 for (i = 0; i < connector->count_props; i++) {
1185 props = drmModeGetProperty(fd, connector->props[i]);
1186 if (!props)
1187 continue;
1188
1189 if (!strcmp(props->name, name))
1190 return props;
1191
1192 drmModeFreeProperty(props);
1193 }
1194
1195 return NULL;
1196}
1197
1198static void
1199drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1200{
1201 struct drm_output *output = (struct drm_output *) output_base;
1202 struct weston_compositor *ec = output_base->compositor;
1203 struct drm_compositor *c = (struct drm_compositor *) ec;
1204 drmModeConnectorPtr connector;
1205 drmModePropertyPtr prop;
1206
1207 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1208 if (!connector)
1209 return;
1210
1211 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1212 if (!prop) {
1213 drmModeFreeConnector(connector);
1214 return;
1215 }
1216
1217 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1218 prop->prop_id, level);
1219 drmModeFreeProperty(prop);
1220 drmModeFreeConnector(connector);
1221}
1222
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001223static const char *connector_type_names[] = {
1224 "None",
1225 "VGA",
1226 "DVI",
1227 "DVI",
1228 "DVI",
1229 "Composite",
1230 "TV",
1231 "LVDS",
1232 "CTV",
1233 "DIN",
1234 "DP",
1235 "HDMI",
1236 "HDMI",
1237 "TV",
1238 "eDP",
1239};
1240
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001241static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001242find_crtc_for_connector(struct drm_compositor *ec,
1243 drmModeRes *resources, drmModeConnector *connector)
1244{
1245 drmModeEncoder *encoder;
1246 uint32_t possible_crtcs;
1247 int i, j;
1248
1249 for (j = 0; j < connector->count_encoders; j++) {
1250 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1251 if (encoder == NULL) {
1252 weston_log("Failed to get encoder.\n");
1253 return -1;
1254 }
1255 possible_crtcs = encoder->possible_crtcs;
1256 drmModeFreeEncoder(encoder);
1257
1258 for (i = 0; i < resources->count_crtcs; i++) {
1259 if (possible_crtcs & (1 << i) &&
1260 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1261 return i;
1262 }
1263 }
1264
1265 return -1;
1266}
1267
1268static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001269create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001270 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001271 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001272 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001273{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001274 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001275 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1276 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001277 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001278 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001279 drmModeModeInfo crtc_mode;
1280 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001281 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001282 char name[32];
1283 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001284
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001285 i = find_crtc_for_connector(ec, resources, connector);
1286 if (i < 0) {
1287 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001288 return -1;
1289 }
1290
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001291 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001292 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001293 return -1;
1294
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001295 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001296 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1297 output->base.make = "unknown";
1298 output->base.model = "unknown";
1299 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001300
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001301 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1302 type_name = connector_type_names[connector->connector_type];
1303 else
1304 type_name = "UNKNOWN";
1305 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1306 output->name = strdup(name);
1307
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001308 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001309 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001310 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001311 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001312 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001313
Matt Roper361d2ad2011-08-29 13:52:23 -07001314 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1315
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001316 /* Get the current mode on the crtc that's currently driving
1317 * this connector. */
1318 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001319 memset(&crtc_mode, 0, sizeof crtc_mode);
1320 if (encoder != NULL) {
1321 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1322 drmModeFreeEncoder(encoder);
1323 if (crtc == NULL)
1324 goto err_free;
1325 if (crtc->mode_valid)
1326 crtc_mode = crtc->mode;
1327 drmModeFreeCrtc(crtc);
1328 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001329
David Herrmann0f0d54e2011-12-08 17:05:45 +01001330 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001331 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1332 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001333 goto err_free;
1334 }
1335
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001336 preferred = NULL;
1337 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001338 configured = NULL;
1339
1340 wl_list_for_each(temp, &configured_output_list, link) {
1341 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001342 if (temp->mode)
1343 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001344 temp->name, temp->mode);
1345 o = temp;
1346 break;
1347 }
1348 }
1349
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001350 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001351 weston_log("Disabling output %s\n", o->name);
1352
1353 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1354 0, 0, 0, 0, 0, NULL);
1355 goto err_free;
1356 }
1357
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001358 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001359 if (o && o->config == OUTPUT_CONFIG_MODE &&
1360 o->width == drm_mode->base.width &&
1361 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001362 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001363 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001364 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001365 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001366 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001367 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001368
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001369 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001370 configured = drm_output_add_mode(output, &o->crtc_mode);
1371 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001372 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001373 current = configured;
1374 }
1375
Wang Quanxianacb805a2012-07-30 18:09:46 -04001376 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001377 current = drm_output_add_mode(output, &crtc_mode);
1378 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001379 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001380 }
1381
Scott Moreau8ab5d452012-07-30 19:51:08 -06001382 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1383 configured = current;
1384
Wang Quanxianacb805a2012-07-30 18:09:46 -04001385 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001386 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001387 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001388 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001389 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001390 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001391 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001392 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001393
1394 if (output->base.current == NULL) {
1395 weston_log("no available modes for %s\n", output->name);
1396 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001397 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001398
Wang Quanxianacb805a2012-07-30 18:09:46 -04001399 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1400
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001401 output->surface = gbm_surface_create(ec->gbm,
1402 output->base.current->width,
1403 output->base.current->height,
1404 GBM_FORMAT_XRGB8888,
1405 GBM_BO_USE_SCANOUT |
1406 GBM_BO_USE_RENDERING);
1407 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001408 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001409 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001410 }
1411
John Kåre Alsaker94659272012-11-13 19:10:18 +01001412 weston_output_init(&output->base, &ec->base, x, y,
1413 connector->mmWidth, connector->mmHeight,
1414 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1415
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001416 if (gl_renderer_output_create(&output->base, output->surface) < 0)
John Kåre Alsaker94659272012-11-13 19:10:18 +01001417 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001418
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001419 output->cursor_bo[0] =
1420 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1421 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1422 output->cursor_bo[1] =
1423 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1424 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001425 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1426 weston_log("cursor buffers unavailable, using gl cursors\n");
1427 ec->cursors_are_broken = 1;
1428 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001429
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001430 output->backlight = backlight_init(drm_device,
1431 connector->connector_type);
1432 if (output->backlight) {
1433 output->base.set_backlight = drm_set_backlight;
1434 output->base.backlight_current = drm_get_backlight(output);
1435 }
1436
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001437 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1438
Alex Wubd3354b2012-04-17 17:20:49 +08001439 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001440 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001441 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001442 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001443 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001444 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001445
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001446 weston_plane_init(&output->cursor_plane, 0, 0);
1447 weston_plane_init(&output->fb_plane, 0, 0);
1448
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001449 weston_log("Output %s, (connector %d, crtc %d)\n",
1450 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001451 wl_list_for_each(m, &output->base.mode_list, link)
1452 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1453 m->width, m->height, m->refresh / 1000.0,
1454 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1455 ", preferred" : "",
1456 m->flags & WL_OUTPUT_MODE_CURRENT ?
1457 ", current" : "",
1458 connector->count_modes == 0 ?
1459 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001460
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001461 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001462
John Kåre Alsaker94659272012-11-13 19:10:18 +01001463err_output:
1464 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001465 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001466err_free:
1467 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1468 base.link) {
1469 wl_list_remove(&drm_mode->base.link);
1470 free(drm_mode);
1471 }
1472
1473 drmModeFreeCrtc(output->original_crtc);
1474 ec->crtc_allocator &= ~(1 << output->crtc_id);
1475 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001476 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001477 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001478
David Herrmann0f0d54e2011-12-08 17:05:45 +01001479 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001480}
1481
Jesse Barnes58ef3792012-02-23 09:45:49 -05001482static void
1483create_sprites(struct drm_compositor *ec)
1484{
1485 struct drm_sprite *sprite;
1486 drmModePlaneRes *plane_res;
1487 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001488 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001489
1490 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1491 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001492 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001493 strerror(errno));
1494 return;
1495 }
1496
1497 for (i = 0; i < plane_res->count_planes; i++) {
1498 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1499 if (!plane)
1500 continue;
1501
1502 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1503 plane->count_formats));
1504 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001505 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001506 __func__);
1507 free(plane);
1508 continue;
1509 }
1510
1511 memset(sprite, 0, sizeof *sprite);
1512
1513 sprite->possible_crtcs = plane->possible_crtcs;
1514 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001515 sprite->current = NULL;
1516 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001517 sprite->compositor = ec;
1518 sprite->count_formats = plane->count_formats;
1519 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001520 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001521 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001522 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001523
1524 wl_list_insert(&ec->sprite_list, &sprite->link);
1525 }
1526
1527 free(plane_res->planes);
1528 free(plane_res);
1529}
1530
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001531static void
1532destroy_sprites(struct drm_compositor *compositor)
1533{
1534 struct drm_sprite *sprite, *next;
1535 struct drm_output *output;
1536
1537 output = container_of(compositor->base.output_list.next,
1538 struct drm_output, base.link);
1539
1540 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1541 drmModeSetPlane(compositor->drm.fd,
1542 sprite->plane_id,
1543 output->crtc_id, 0, 0,
1544 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001545 if (sprite->current)
1546 gbm_bo_destroy(sprite->current->bo);
1547 if (sprite->next)
1548 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001549 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001550 free(sprite);
1551 }
1552}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001553
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001554static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001555create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001556 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001557{
1558 drmModeConnector *connector;
1559 drmModeRes *resources;
1560 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001561 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001562
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001563 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001564 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001565 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001566 return -1;
1567 }
1568
Jesse Barnes58ef3792012-02-23 09:45:49 -05001569 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001570 if (!ec->crtcs) {
1571 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001572 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001573 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001574
Rob Clark4339add2012-08-09 14:18:28 -05001575 ec->min_width = resources->min_width;
1576 ec->max_width = resources->max_width;
1577 ec->min_height = resources->min_height;
1578 ec->max_height = resources->max_height;
1579
Jesse Barnes58ef3792012-02-23 09:45:49 -05001580 ec->num_crtcs = resources->count_crtcs;
1581 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1582
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001583 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001584 connector = drmModeGetConnector(ec->drm.fd,
1585 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001586 if (connector == NULL)
1587 continue;
1588
1589 if (connector->connection == DRM_MODE_CONNECTED &&
1590 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001591 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001592 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001593 connector, x, y,
1594 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001595 drmModeFreeConnector(connector);
1596 continue;
1597 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001598
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001599 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001600 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001601 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001602 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001603
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001604 drmModeFreeConnector(connector);
1605 }
1606
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001607 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001608 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001609 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001610 return -1;
1611 }
1612
1613 drmModeFreeResources(resources);
1614
1615 return 0;
1616}
1617
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001618static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001619update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001620{
1621 drmModeConnector *connector;
1622 drmModeRes *resources;
1623 struct drm_output *output, *next;
1624 int x = 0, y = 0;
1625 int x_offset = 0, y_offset = 0;
1626 uint32_t connected = 0, disconnects = 0;
1627 int i;
1628
1629 resources = drmModeGetResources(ec->drm.fd);
1630 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001631 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001632 return;
1633 }
1634
1635 /* collect new connects */
1636 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001637 int connector_id = resources->connectors[i];
1638
1639 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001640 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001641 continue;
1642
David Herrmann7551cff2011-12-08 17:05:43 +01001643 if (connector->connection != DRM_MODE_CONNECTED) {
1644 drmModeFreeConnector(connector);
1645 continue;
1646 }
1647
Benjamin Franzke117483d2011-08-30 11:38:26 +02001648 connected |= (1 << connector_id);
1649
1650 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001651 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001652 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001653 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001654
1655 /* XXX: not yet needed, we die with 0 outputs */
1656 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001657 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001658 else
1659 x = 0;
1660 y = 0;
1661 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001662 connector, x, y,
1663 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001664 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001665
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001666 }
1667 drmModeFreeConnector(connector);
1668 }
1669 drmModeFreeResources(resources);
1670
1671 disconnects = ec->connector_allocator & ~connected;
1672 if (disconnects) {
1673 wl_list_for_each_safe(output, next, &ec->base.output_list,
1674 base.link) {
1675 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001676 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001677 output->base.x - x_offset,
1678 output->base.y - y_offset);
1679 }
1680
1681 if (disconnects & (1 << output->connector_id)) {
1682 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001683 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001684 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001685 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001686 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001687 }
1688 }
1689 }
1690
1691 /* FIXME: handle zero outputs, without terminating */
1692 if (ec->connector_allocator == 0)
1693 wl_display_terminate(ec->base.wl_display);
1694}
1695
1696static int
David Herrmannd7488c22012-03-11 20:05:21 +01001697udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001698{
David Herrmannd7488c22012-03-11 20:05:21 +01001699 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001700 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001701
1702 sysnum = udev_device_get_sysnum(device);
1703 if (!sysnum || atoi(sysnum) != ec->drm.id)
1704 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001705
David Herrmann6ac52db2012-03-11 20:05:22 +01001706 val = udev_device_get_property_value(device, "HOTPLUG");
1707 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001708 return 0;
1709
David Herrmann6ac52db2012-03-11 20:05:22 +01001710 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001711}
1712
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001713static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001714udev_drm_event(int fd, uint32_t mask, void *data)
1715{
1716 struct drm_compositor *ec = data;
1717 struct udev_device *event;
1718
1719 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001720
David Herrmannd7488c22012-03-11 20:05:21 +01001721 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001722 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001723
1724 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001725
1726 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001727}
1728
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001729static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001730drm_restore(struct weston_compositor *ec)
1731{
1732 struct drm_compositor *d = (struct drm_compositor *) ec;
1733
1734 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1735 weston_log("failed to drop master: %m\n");
1736 tty_reset(d->tty);
1737}
1738
Pekka Paalanen33156972012-08-03 13:30:30 -04001739static const char default_seat[] = "seat0";
1740
1741static void
1742device_added(struct udev_device *udev_device, struct drm_seat *master)
1743{
1744 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001745 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001746 const char *devnode;
1747 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001748 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001749 int fd;
1750
1751 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1752 if (!device_seat)
1753 device_seat = default_seat;
1754
1755 if (strcmp(device_seat, master->seat_id))
1756 return;
1757
1758 c = master->base.compositor;
1759 devnode = udev_device_get_devnode(udev_device);
1760
1761 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001762 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001763 * read. mtdev_get() also expects this. */
1764 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1765 if (fd < 0) {
1766 weston_log("opening input device '%s' failed.\n", devnode);
1767 return;
1768 }
1769
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001770 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001771 if (!device) {
1772 close(fd);
1773 weston_log("not using input device '%s'.\n", devnode);
1774 return;
1775 }
1776
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001777 calibration_values =
1778 udev_device_get_property_value(udev_device,
1779 "WL_CALIBRATION");
1780
1781 if (calibration_values && sscanf(calibration_values,
1782 "%f %f %f %f %f %f",
1783 &device->abs.calibration[0],
1784 &device->abs.calibration[1],
1785 &device->abs.calibration[2],
1786 &device->abs.calibration[3],
1787 &device->abs.calibration[4],
1788 &device->abs.calibration[5]) == 6) {
1789 device->abs.apply_calibration = 1;
1790 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1791 device->abs.calibration[0],
1792 device->abs.calibration[1],
1793 device->abs.calibration[2],
1794 device->abs.calibration[3],
1795 device->abs.calibration[4],
1796 device->abs.calibration[5]);
1797 }
1798
Pekka Paalanen33156972012-08-03 13:30:30 -04001799 wl_list_insert(master->devices_list.prev, &device->link);
1800}
1801
1802static void
1803evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1804{
1805 struct drm_seat *seat = (struct drm_seat *) seat_base;
1806 struct udev_enumerate *e;
1807 struct udev_list_entry *entry;
1808 struct udev_device *device;
1809 const char *path, *sysname;
1810
1811 e = udev_enumerate_new(udev);
1812 udev_enumerate_add_match_subsystem(e, "input");
1813 udev_enumerate_scan_devices(e);
1814 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1815 path = udev_list_entry_get_name(entry);
1816 device = udev_device_new_from_syspath(udev, path);
1817
1818 sysname = udev_device_get_sysname(device);
1819 if (strncmp("event", sysname, 5) != 0) {
1820 udev_device_unref(device);
1821 continue;
1822 }
1823
1824 device_added(device, seat);
1825
1826 udev_device_unref(device);
1827 }
1828 udev_enumerate_unref(e);
1829
1830 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1831
1832 if (wl_list_empty(&seat->devices_list)) {
1833 weston_log(
1834 "warning: no input devices on entering Weston. "
1835 "Possible causes:\n"
1836 "\t- no permissions to read /dev/input/event*\n"
1837 "\t- seats misconfigured "
1838 "(Weston backend option 'seat', "
1839 "udev device property ID_SEAT)\n");
1840 }
1841}
1842
1843static int
1844evdev_udev_handler(int fd, uint32_t mask, void *data)
1845{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001846 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001847 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001848 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001849 const char *action;
1850 const char *devnode;
1851
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001852 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001853 if (!udev_device)
1854 return 1;
1855
1856 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001857 if (!action)
1858 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001859
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001860 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1861 goto out;
1862
1863 if (!strcmp(action, "add")) {
1864 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001865 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001866 else if (!strcmp(action, "remove")) {
1867 devnode = udev_device_get_devnode(udev_device);
1868 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1869 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001870 weston_log("input device %s, %s removed\n",
1871 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001872 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001873 break;
1874 }
1875 }
1876
1877out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001878 udev_device_unref(udev_device);
1879
1880 return 0;
1881}
1882
1883static int
1884evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1885{
1886 struct drm_seat *master = (struct drm_seat *) seat_base;
1887 struct wl_event_loop *loop;
1888 struct weston_compositor *c = master->base.compositor;
1889 int fd;
1890
1891 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1892 if (!master->udev_monitor) {
1893 weston_log("udev: failed to create the udev monitor\n");
1894 return 0;
1895 }
1896
1897 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1898 "input", NULL);
1899
1900 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1901 weston_log("udev: failed to bind the udev monitor\n");
1902 udev_monitor_unref(master->udev_monitor);
1903 return 0;
1904 }
1905
1906 loop = wl_display_get_event_loop(c->wl_display);
1907 fd = udev_monitor_get_fd(master->udev_monitor);
1908 master->udev_monitor_source =
1909 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1910 evdev_udev_handler, master);
1911 if (!master->udev_monitor_source) {
1912 udev_monitor_unref(master->udev_monitor);
1913 return 0;
1914 }
1915
1916 return 1;
1917}
1918
1919static void
1920evdev_disable_udev_monitor(struct weston_seat *seat_base)
1921{
1922 struct drm_seat *seat = (struct drm_seat *) seat_base;
1923
1924 if (!seat->udev_monitor)
1925 return;
1926
1927 udev_monitor_unref(seat->udev_monitor);
1928 seat->udev_monitor = NULL;
1929 wl_event_source_remove(seat->udev_monitor_source);
1930 seat->udev_monitor_source = NULL;
1931}
1932
1933static void
1934drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1935{
1936 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001937 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001938
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001939 wl_list_for_each(device, &seat->devices_list, link)
1940 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001941}
1942
1943static void
1944evdev_input_create(struct weston_compositor *c, struct udev *udev,
1945 const char *seat_id)
1946{
1947 struct drm_seat *seat;
1948
1949 seat = malloc(sizeof *seat);
1950 if (seat == NULL)
1951 return;
1952
1953 memset(seat, 0, sizeof *seat);
1954 weston_seat_init(&seat->base, c);
1955 seat->base.led_update = drm_led_update;
1956
1957 wl_list_init(&seat->devices_list);
1958 seat->seat_id = strdup(seat_id);
1959 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1960 free(seat->seat_id);
1961 free(seat);
1962 return;
1963 }
1964
1965 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001966}
1967
1968static void
1969evdev_remove_devices(struct weston_seat *seat_base)
1970{
1971 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001972 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001973
1974 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001975 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001976
Pekka Paalanend8583512012-08-03 14:39:11 +03001977 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001978 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001979}
1980
1981static void
1982evdev_input_destroy(struct weston_seat *seat_base)
1983{
1984 struct drm_seat *seat = (struct drm_seat *) seat_base;
1985
1986 evdev_remove_devices(seat_base);
1987 evdev_disable_udev_monitor(&seat->base);
1988
1989 weston_seat_release(seat_base);
1990 free(seat->seat_id);
1991 free(seat);
1992}
1993
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001994static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001995drm_free_configured_output(struct drm_configured_output *output)
1996{
1997 free(output->name);
1998 free(output->mode);
1999 free(output);
2000}
2001
2002static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002003drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002004{
2005 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002006 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002007 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002008
Daniel Stone37816df2012-05-16 18:45:18 +01002009 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2010 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002011 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002012 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002013
2014 wl_event_source_remove(d->udev_drm_source);
2015 wl_event_source_remove(d->drm_source);
2016
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002017 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002018
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002019 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002020
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002021 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002022 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002023 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002024 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002025 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002026
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002027 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002028}
2029
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002030static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002031drm_compositor_set_modes(struct drm_compositor *compositor)
2032{
2033 struct drm_output *output;
2034 struct drm_mode *drm_mode;
2035 int ret;
2036
2037 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2038 drm_mode = (struct drm_mode *) output->base.current;
2039 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002040 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002041 &output->connector_id, 1,
2042 &drm_mode->mode_info);
2043 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002044 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002045 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002046 drm_mode->base.width, drm_mode->base.height,
2047 output->base.x, output->base.y);
2048 }
2049 }
2050}
2051
2052static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002053vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002054{
2055 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002056 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002057 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002058 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002059
2060 switch (event) {
2061 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002062 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002063 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002064 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002065 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002066 wl_display_terminate(compositor->wl_display);
2067 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002068 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002069 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002070 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002071 wl_list_for_each(seat, &compositor->seat_list, link) {
2072 evdev_add_devices(ec->udev, seat);
2073 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002074 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002075 break;
2076 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002077 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002078 wl_list_for_each(seat, &compositor->seat_list, link) {
2079 evdev_disable_udev_monitor(seat);
2080 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002081 }
2082
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002083 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002084 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002085 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002086
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002087 /* If we have a repaint scheduled (either from a
2088 * pending pageflip or the idle handler), make sure we
2089 * cancel that so we don't try to pageflip when we're
2090 * vt switched away. The SLEEPING state will prevent
2091 * further attemps at repainting. When we switch
2092 * back, we schedule a repaint, which will process
2093 * pending frame callbacks. */
2094
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002095 wl_list_for_each(output, &ec->base.output_list, base.link) {
2096 output->base.repaint_needed = 0;
2097 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002098 }
2099
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002100 output = container_of(ec->base.output_list.next,
2101 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002102
2103 wl_list_for_each(sprite, &ec->sprite_list, link)
2104 drmModeSetPlane(ec->drm.fd,
2105 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002106 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002107 0, 0, 0, 0, 0, 0, 0, 0);
2108
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002109 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002110 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002111
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002112 break;
2113 };
2114}
2115
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002116static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002117switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002118{
2119 struct drm_compositor *ec = data;
2120
Daniel Stone325fc2d2012-05-30 16:31:58 +01002121 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002122}
2123
David Herrmann0af066f2012-10-29 19:21:16 +01002124/*
2125 * Find primary GPU
2126 * Some systems may have multiple DRM devices attached to a single seat. This
2127 * function loops over all devices and tries to find a PCI device with the
2128 * boot_vga sysfs attribute set to 1.
2129 * If no such device is found, the first DRM device reported by udev is used.
2130 */
2131static struct udev_device*
2132find_primary_gpu(struct drm_compositor *ec, const char *seat)
2133{
2134 struct udev_enumerate *e;
2135 struct udev_list_entry *entry;
2136 const char *path, *device_seat, *id;
2137 struct udev_device *device, *drm_device, *pci;
2138
2139 e = udev_enumerate_new(ec->udev);
2140 udev_enumerate_add_match_subsystem(e, "drm");
2141 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2142
2143 udev_enumerate_scan_devices(e);
2144 drm_device = NULL;
2145 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2146 path = udev_list_entry_get_name(entry);
2147 device = udev_device_new_from_syspath(ec->udev, path);
2148 if (!device)
2149 continue;
2150 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2151 if (!device_seat)
2152 device_seat = default_seat;
2153 if (strcmp(device_seat, seat)) {
2154 udev_device_unref(device);
2155 continue;
2156 }
2157
2158 pci = udev_device_get_parent_with_subsystem_devtype(device,
2159 "pci", NULL);
2160 if (pci) {
2161 id = udev_device_get_sysattr_value(pci, "boot_vga");
2162 if (id && !strcmp(id, "1")) {
2163 if (drm_device)
2164 udev_device_unref(drm_device);
2165 drm_device = device;
2166 break;
2167 }
2168 }
2169
2170 if (!drm_device)
2171 drm_device = device;
2172 else
2173 udev_device_unref(device);
2174 }
2175
2176 udev_enumerate_unref(e);
2177 return drm_device;
2178}
2179
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002180static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002181planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002182{
2183 struct drm_compositor *c = data;
2184
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002185 switch (key) {
2186 case KEY_C:
2187 c->cursors_are_broken ^= 1;
2188 break;
2189 case KEY_V:
2190 c->sprites_are_broken ^= 1;
2191 break;
2192 case KEY_O:
2193 c->sprites_hidden ^= 1;
2194 break;
2195 default:
2196 break;
2197 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002198}
2199
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002200static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002201drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002202 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002203 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002205 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002206 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002207 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002208 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002209 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002210 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002211
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002212 weston_log("initializing drm backend\n");
2213
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002214 ec = malloc(sizeof *ec);
2215 if (ec == NULL)
2216 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002217 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002218
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002219 /* KMS support for sprites is not complete yet, so disable the
2220 * functionality for now. */
2221 ec->sprites_are_broken = 1;
2222
Daniel Stone725c2c32012-06-22 14:04:36 +01002223 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002224 config_file) < 0) {
2225 weston_log("weston_compositor_init failed\n");
2226 goto err_base;
2227 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002228
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002229 ec->udev = udev_new();
2230 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002231 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002232 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002233 }
2234
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002235 ec->base.wl_display = display;
2236 ec->tty = tty_create(&ec->base, vt_func, tty);
2237 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002238 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002239 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002240 }
2241
David Herrmann0af066f2012-10-29 19:21:16 +01002242 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002243 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002244 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002245 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002246 }
David Herrmann0af066f2012-10-29 19:21:16 +01002247 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002248
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002249 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002250 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002251 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002252 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002253
2254 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002255 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002256
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002257 ec->base.focus = 1;
2258
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002259 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002260
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002261 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002262 weston_compositor_add_key_binding(&ec->base, key,
2263 MODIFIER_CTRL | MODIFIER_ALT,
2264 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002265
Jesse Barnes58ef3792012-02-23 09:45:49 -05002266 wl_list_init(&ec->sprite_list);
2267 create_sprites(ec);
2268
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002269 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002270 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002271 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002272 }
2273
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002274 path = NULL;
2275
Tiago Vignattice03ec32011-12-19 01:14:03 +02002276 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002277
2278 loop = wl_display_get_event_loop(ec->base.wl_display);
2279 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002280 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002281 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002282
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002283 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2284 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002285 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002286 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002287 }
2288 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2289 "drm", NULL);
2290 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002291 wl_event_loop_add_fd(loop,
2292 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002293 WL_EVENT_READABLE, udev_drm_event, ec);
2294
2295 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002296 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002297 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002298 }
2299
Daniel Stonea96b93c2012-06-22 14:04:37 +01002300 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002301
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002302 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002303 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002304 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002305 planes_binding, ec);
2306 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2307 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002308
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002309 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002310
2311err_udev_monitor:
2312 wl_event_source_remove(ec->udev_drm_source);
2313 udev_monitor_unref(ec->udev_monitor);
2314err_drm_source:
2315 wl_event_source_remove(ec->drm_source);
2316 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2317 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002318err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002319 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002320 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002321 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002322err_udev_dev:
2323 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002324err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002325 tty_destroy(ec->tty);
2326err_udev:
2327 udev_unref(ec->udev);
2328err_compositor:
2329 weston_compositor_shutdown(&ec->base);
2330err_base:
2331 free(ec);
2332 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002333}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002334
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002335static int
2336set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2337{
2338 mode->flags = 0;
2339
2340 if (strcmp(hsync, "+hsync") == 0)
2341 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2342 else if (strcmp(hsync, "-hsync") == 0)
2343 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2344 else
2345 return -1;
2346
2347 if (strcmp(vsync, "+vsync") == 0)
2348 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2349 else if (strcmp(vsync, "-vsync") == 0)
2350 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2351 else
2352 return -1;
2353
2354 return 0;
2355}
2356
2357static int
2358check_for_modeline(struct drm_configured_output *output)
2359{
2360 drmModeModeInfo mode;
2361 char hsync[16];
2362 char vsync[16];
2363 char mode_name[16];
2364 float fclock;
2365
2366 mode.type = DRM_MODE_TYPE_USERDEF;
2367 mode.hskew = 0;
2368 mode.vscan = 0;
2369 mode.vrefresh = 0;
2370
2371 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2372 &fclock, &mode.hdisplay,
2373 &mode.hsync_start,
2374 &mode.hsync_end, &mode.htotal,
2375 &mode.vdisplay,
2376 &mode.vsync_start,
2377 &mode.vsync_end, &mode.vtotal,
2378 hsync, vsync) == 11) {
2379 if (set_sync_flags(&mode, hsync, vsync))
2380 return -1;
2381
2382 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2383 strcpy(mode.name, mode_name);
2384
2385 mode.clock = fclock * 1000;
2386 } else
2387 return -1;
2388
2389 output->crtc_mode = mode;
2390
2391 return 0;
2392}
2393
Scott Moreau8ab5d452012-07-30 19:51:08 -06002394static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002395drm_output_set_transform(struct drm_configured_output *output)
2396{
2397 if (!output_transform) {
2398 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2399 return;
2400 }
2401
2402 if (!strcmp(output_transform, "normal"))
2403 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2404 else if (!strcmp(output_transform, "90"))
2405 output->transform = WL_OUTPUT_TRANSFORM_90;
2406 else if (!strcmp(output_transform, "180"))
2407 output->transform = WL_OUTPUT_TRANSFORM_180;
2408 else if (!strcmp(output_transform, "270"))
2409 output->transform = WL_OUTPUT_TRANSFORM_270;
2410 else if (!strcmp(output_transform, "flipped"))
2411 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2412 else if (!strcmp(output_transform, "flipped-90"))
2413 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2414 else if (!strcmp(output_transform, "flipped-180"))
2415 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2416 else if (!strcmp(output_transform, "flipped-270"))
2417 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2418 else {
2419 weston_log("Invalid transform \"%s\" for output %s\n",
2420 output_transform, output_name);
2421 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2422 }
2423
2424 free(output_transform);
2425 output_transform = NULL;
2426}
2427
2428static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002429output_section_done(void *data)
2430{
2431 struct drm_configured_output *output;
2432
2433 output = malloc(sizeof *output);
2434
Scott Moreau1bad5db2012-08-18 01:04:05 -06002435 if (!output || !output_name || (output_name[0] == 'X') ||
2436 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002437 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002438 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002439 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002440 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002441 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002442 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002443 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002444 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002445 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002446
2447 output->config = OUTPUT_CONFIG_INVALID;
2448 output->name = output_name;
2449 output->mode = output_mode;
2450
Scott Moreau1bad5db2012-08-18 01:04:05 -06002451 if (output_mode) {
2452 if (strcmp(output_mode, "off") == 0)
2453 output->config = OUTPUT_CONFIG_OFF;
2454 else if (strcmp(output_mode, "preferred") == 0)
2455 output->config = OUTPUT_CONFIG_PREFERRED;
2456 else if (strcmp(output_mode, "current") == 0)
2457 output->config = OUTPUT_CONFIG_CURRENT;
2458 else if (sscanf(output_mode, "%dx%d",
2459 &output->width, &output->height) == 2)
2460 output->config = OUTPUT_CONFIG_MODE;
2461 else if (check_for_modeline(output) == 0)
2462 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002463
Scott Moreau1bad5db2012-08-18 01:04:05 -06002464 if (output->config == OUTPUT_CONFIG_INVALID)
2465 weston_log("Invalid mode \"%s\" for output %s\n",
2466 output_mode, output_name);
2467 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002468 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002469
2470 drm_output_set_transform(output);
2471
2472 wl_list_insert(&configured_output_list, &output->link);
2473
2474 if (output_transform)
2475 free(output_transform);
2476 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002477}
2478
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002479WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002480backend_init(struct wl_display *display, int argc, char *argv[],
2481 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002482{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002483 int connector = 0, tty = 0;
2484 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002485
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002486 const struct weston_option drm_options[] = {
2487 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2488 { WESTON_OPTION_STRING, "seat", 0, &seat },
2489 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002490 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002491 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002492
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002493 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002494
Scott Moreau8ab5d452012-07-30 19:51:08 -06002495 wl_list_init(&configured_output_list);
2496
2497 const struct config_key drm_config_keys[] = {
2498 { "name", CONFIG_KEY_STRING, &output_name },
2499 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002500 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002501 };
2502
2503 const struct config_section config_section[] = {
2504 { "output", drm_config_keys,
2505 ARRAY_LENGTH(drm_config_keys), output_section_done },
2506 };
2507
2508 parse_config_file(config_file, config_section,
2509 ARRAY_LENGTH(config_section), NULL);
2510
Daniel Stonec1be8e52012-06-01 11:14:02 -04002511 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2512 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002513}