blob: 3e93162e395867991e2b269e2e244b608ad0bbac [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>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020033#include <sys/mman.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040034
Benjamin Franzkec649a922011-03-02 11:56:04 +010035#include <xf86drm.h>
36#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050037#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010038
Benjamin Franzke060cf802011-04-30 09:32:11 +020039#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020040#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040041#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020042
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040043#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010044#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020045#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050046#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010047#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040048
Kristian Høgsberg061c4252012-06-28 11:28:15 -040049static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060050static char *output_name;
51static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060052static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060053static struct wl_list configured_output_list;
54
55enum output_config {
56 OUTPUT_CONFIG_INVALID = 0,
57 OUTPUT_CONFIG_OFF,
58 OUTPUT_CONFIG_PREFERRED,
59 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060060 OUTPUT_CONFIG_MODE,
61 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060062};
63
64struct drm_configured_output {
65 char *name;
66 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060067 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060068 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060069 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060070 enum output_config config;
71 struct wl_list link;
72};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040073
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050075 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
77 struct udev *udev;
78 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040079
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010080 struct udev_monitor *udev_monitor;
81 struct wl_event_source *udev_drm_source;
82
Benjamin Franzke2af7f102011-03-02 11:14:59 +010083 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010084 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010085 int fd;
86 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020087 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050088 uint32_t *crtcs;
89 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050090 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010091 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050092 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020093
Rob Clark4339add2012-08-09 14:18:28 -050094 /* we need these parameters in order to not fail drmModeAddFB2()
95 * due to out of bounds dimensions, and then mistakenly set
96 * sprites_are_broken:
97 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020098 uint32_t min_width, max_width;
99 uint32_t min_height, max_height;
100 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500101
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500103 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200104 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500105
Rob Clarkab5b1e32012-08-09 13:24:45 -0500106 int cursors_are_broken;
107
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200108 int use_pixman;
109
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200110 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400111};
112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400113struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500114 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400115 drmModeModeInfo mode_info;
116};
117
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118struct drm_output;
119
120struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200122 uint32_t fb_id, stride, handle, size;
123 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300124 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200125 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200126
127 /* Used by gbm fbs */
128 struct gbm_bo *bo;
129
130 /* Used by dumb fbs */
131 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132};
133
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400134struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500135 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400136
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400137 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400138 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500139 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400140 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700141 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200142
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300143 int vblank_pending;
144 int page_flip_pending;
145
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400146 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400147 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400148 struct weston_plane cursor_plane;
149 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400150 struct weston_surface *cursor_surface;
151 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300152 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200153 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200154
155 struct drm_fb *dumb[2];
156 pixman_image_t *image[2];
157 int current_image;
158 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159};
160
Jesse Barnes58ef3792012-02-23 09:45:49 -0500161/*
162 * An output has a primary display plane plus zero or more sprites for
163 * blending display contents.
164 */
165struct drm_sprite {
166 struct wl_list link;
167
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400168 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500169
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200170 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300171 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500172 struct drm_compositor *compositor;
173
Jesse Barnes58ef3792012-02-23 09:45:49 -0500174 uint32_t possible_crtcs;
175 uint32_t plane_id;
176 uint32_t count_formats;
177
178 int32_t src_x, src_y;
179 uint32_t src_w, src_h;
180 uint32_t dest_x, dest_y;
181 uint32_t dest_w, dest_h;
182
183 uint32_t formats[];
184};
185
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500186static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400187
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400188static void
189drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400190
Jesse Barnes58ef3792012-02-23 09:45:49 -0500191static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500192drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
193{
194 struct weston_compositor *ec = output_base->compositor;
195 struct drm_compositor *c =(struct drm_compositor *) ec;
196 struct drm_output *output = (struct drm_output *) output_base;
197 int crtc;
198
199 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
200 if (c->crtcs[crtc] != output->crtc_id)
201 continue;
202
203 if (supported & (1 << crtc))
204 return -1;
205 }
206
207 return 0;
208}
209
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300210static void
211drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
212{
213 struct drm_fb *fb = data;
214 struct gbm_device *gbm = gbm_bo_get_device(bo);
215
216 if (fb->fb_id)
217 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
218
Pekka Paalanende685b82012-12-04 15:58:12 +0200219 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300220
221 free(data);
222}
223
224static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200225drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
226{
227 struct drm_fb *fb;
228 int ret;
229
230 struct drm_mode_create_dumb create_arg;
231 struct drm_mode_destroy_dumb destroy_arg;
232 struct drm_mode_map_dumb map_arg;
233
234 fb = calloc(1, sizeof *fb);
235 if (!fb)
236 return NULL;
237
238 create_arg.bpp = 32;
239 create_arg.width = width;
240 create_arg.height = height;
241
242 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
243 if (ret)
244 goto err_fb;
245
246 fb->handle = create_arg.handle;
247 fb->stride = create_arg.pitch;
248 fb->size = create_arg.size;
249 fb->fd = ec->drm.fd;
250
251 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
252 fb->stride, fb->handle, &fb->fb_id);
253 if (ret)
254 goto err_bo;
255
256 memset(&map_arg, 0, sizeof(map_arg));
257 map_arg.handle = fb->handle;
258 drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
259
260 if (ret)
261 goto err_add_fb;
262
263 fb->map = mmap(0, fb->size, PROT_WRITE,
264 MAP_SHARED, ec->drm.fd, map_arg.offset);
265 if (fb->map == MAP_FAILED)
266 goto err_add_fb;
267
268 return fb;
269
270err_add_fb:
271 drmModeRmFB(ec->drm.fd, fb->fb_id);
272err_bo:
273 memset(&destroy_arg, 0, sizeof(destroy_arg));
274 destroy_arg.handle = create_arg.handle;
275 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
276err_fb:
277 free(fb);
278 return NULL;
279}
280
281static void
282drm_fb_destroy_dumb(struct drm_fb *fb)
283{
284 struct drm_mode_destroy_dumb destroy_arg;
285
286 if (!fb->map)
287 return;
288
289 if (fb->fb_id)
290 drmModeRmFB(fb->fd, fb->fb_id);
291
292 weston_buffer_reference(&fb->buffer_ref, NULL);
293
294 munmap(fb->map, fb->size);
295
296 memset(&destroy_arg, 0, sizeof(destroy_arg));
297 destroy_arg.handle = fb->handle;
298 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
299
300 free(fb);
301}
302
303static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500304drm_fb_get_from_bo(struct gbm_bo *bo,
305 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300306{
307 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200308 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200309 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300310 int ret;
311
312 if (fb)
313 return fb;
314
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200315 fb = calloc(1, sizeof *fb);
316 if (!fb)
317 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300318
319 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300320
321 width = gbm_bo_get_width(bo);
322 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200323 fb->stride = gbm_bo_get_stride(bo);
324 fb->handle = gbm_bo_get_handle(bo).u32;
325 fb->size = fb->stride * height;
326 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200328 if (compositor->min_width > width || width > compositor->max_width ||
329 compositor->min_height > height ||
330 height > compositor->max_height) {
331 weston_log("bo geometry out of bounds\n");
332 goto err_free;
333 }
334
335 ret = -1;
336
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200337 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200338 handles[0] = fb->handle;
339 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200340 offsets[0] = 0;
341
342 ret = drmModeAddFB2(compositor->drm.fd, width, height,
343 format, handles, pitches, offsets,
344 &fb->fb_id, 0);
345 if (ret) {
346 weston_log("addfb2 failed: %m\n");
347 compositor->no_addfb2 = 1;
348 compositor->sprites_are_broken = 1;
349 }
350 }
351
352 if (ret)
353 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200354 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200355
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200357 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200358 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 }
360
361 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
362
363 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364
365err_free:
366 free(fb);
367 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368}
369
370static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200371drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
372{
Pekka Paalanende685b82012-12-04 15:58:12 +0200373 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200374
375 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376
Pekka Paalanende685b82012-12-04 15:58:12 +0200377 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200378}
379
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200380static void
381drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
382{
383 if (!fb)
384 return;
385
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200386 if (fb->map &&
387 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200388 drm_fb_destroy_dumb(fb);
389 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200390 if (fb->is_client_buffer)
391 gbm_bo_destroy(fb->bo);
392 else
393 gbm_surface_release_buffer(output->surface,
394 output->current->bo);
395 }
396}
397
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500398static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200399drm_output_check_scanout_format(struct drm_output *output,
400 struct weston_surface *es, struct gbm_bo *bo)
401{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200402 uint32_t format;
403 pixman_region32_t r;
404
405 format = gbm_bo_get_format(bo);
406
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500407 switch (format) {
408 case GBM_FORMAT_XRGB8888:
409 return format;
410 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200411 /* We can only scanout an ARGB buffer if the surface's
412 * opaque region covers the whole output */
413 pixman_region32_init(&r);
414 pixman_region32_subtract(&r, &output->base.region,
415 &es->opaque);
416
417 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500418 format = GBM_FORMAT_XRGB8888;
419 else
420 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200421
422 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200423
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500424 return format;
425 default:
426 return 0;
427 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200428}
429
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400430static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400431drm_output_prepare_scanout_surface(struct weston_output *_output,
432 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500433{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400434 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500435 struct drm_compositor *c =
436 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200437 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300438 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500439 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500440
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500441 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200442 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200443 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200444 buffer->width != output->base.current->width ||
445 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200446 output->base.transform != es->buffer_transform ||
447 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400448 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500449
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400450 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200451 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500452
Rob Bradford9b101872012-09-14 23:25:41 +0100453 /* Unable to use the buffer for scanout */
454 if (!bo)
455 return NULL;
456
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500457 format = drm_output_check_scanout_format(output, es, bo);
458 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300459 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400460 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300461 }
462
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500463 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300464 if (!output->next) {
465 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400466 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300467 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500468
Pekka Paalanende685b82012-12-04 15:58:12 +0200469 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500470
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400471 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500472}
473
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500474static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200475drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400476{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200477 struct drm_compositor *c =
478 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300479 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400480
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200481 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400482
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300483 bo = gbm_surface_lock_front_buffer(output->surface);
484 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200485 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400486 return;
487 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300488
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500489 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300490 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200491 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300492 gbm_surface_release_buffer(output->surface, bo);
493 return;
494 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400495}
496
497static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200498drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
499{
500 struct weston_compositor *ec = output->base.compositor;
501 pixman_region32_t total_damage, previous_damage;
502
503 pixman_region32_init(&total_damage);
504 pixman_region32_init(&previous_damage);
505
506 pixman_region32_copy(&previous_damage, damage);
507
508 pixman_region32_union(&total_damage, damage, &output->previous_damage);
509 pixman_region32_copy(&output->previous_damage, &previous_damage);
510
511 output->current_image ^= 1;
512
513 output->next = output->dumb[output->current_image];
514 pixman_renderer_output_set_buffer(&output->base,
515 output->image[output->current_image]);
516
517 ec->renderer->repaint_output(&output->base, &total_damage);
518
519 pixman_region32_fini(&total_damage);
520 pixman_region32_fini(&previous_damage);
521}
522
523static void
524drm_output_render(struct drm_output *output, pixman_region32_t *damage)
525{
526 struct drm_compositor *c =
527 (struct drm_compositor *) output->base.compositor;
528
529 if (c->use_pixman)
530 drm_output_render_pixman(output, damage);
531 else
532 drm_output_render_gl(output, damage);
533
534 pixman_region32_subtract(&c->base.primary_plane.damage,
535 &c->base.primary_plane.damage, damage);
536}
537
538static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500539drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400540 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100541{
542 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500543 struct drm_compositor *compositor =
544 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500545 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400546 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500547 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100548
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300549 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400550 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300551 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400552 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100553
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400554 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300555 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400556 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300557 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400558 &output->connector_id, 1,
559 &mode->mode_info);
560 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200561 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400562 return;
563 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200564 }
565
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500566 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300567 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500568 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200569 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500570 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500571 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100572
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300573 output->page_flip_pending = 1;
574
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400575 drm_output_set_cursor(output);
576
Jesse Barnes58ef3792012-02-23 09:45:49 -0500577 /*
578 * Now, update all the sprite surfaces
579 */
580 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200581 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500582 drmVBlank vbl = {
583 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
584 .request.sequence = 1,
585 };
586
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200587 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200588 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589 continue;
590
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200591 if (s->next && !compositor->sprites_hidden)
592 fb_id = s->next->fb_id;
593
Jesse Barnes58ef3792012-02-23 09:45:49 -0500594 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200595 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500596 s->dest_x, s->dest_y,
597 s->dest_w, s->dest_h,
598 s->src_x, s->src_y,
599 s->src_w, s->src_h);
600 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200601 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602 ret, strerror(errno));
603
Rob Clark5ca1a472012-08-08 20:27:37 -0500604 if (output->pipe > 0)
605 vbl.request.type |= DRM_VBLANK_SECONDARY;
606
Jesse Barnes58ef3792012-02-23 09:45:49 -0500607 /*
608 * Queue a vblank signal so we know when the surface
609 * becomes active on the display or has been replaced.
610 */
611 vbl.request.signal = (unsigned long)s;
612 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
613 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200614 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500615 ret, strerror(errno));
616 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300617
618 s->output = output;
619 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620 }
621
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500622 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400623}
624
625static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
627 void *data)
628{
629 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300630 struct drm_output *output = s->output;
631 uint32_t msecs;
632
633 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200635 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200636 s->current = s->next;
637 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300638
639 if (!output->page_flip_pending) {
640 msecs = sec * 1000 + usec / 1000;
641 weston_output_finish_frame(&output->base, msecs);
642 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643}
644
645static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400646page_flip_handler(int fd, unsigned int frame,
647 unsigned int sec, unsigned int usec, void *data)
648{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200649 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400650 uint32_t msecs;
651
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300652 output->page_flip_pending = 0;
653
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200654 drm_output_release_fb(output, output->current);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300655 output->current = output->next;
656 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400657
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300658 if (!output->vblank_pending) {
659 msecs = sec * 1000 + usec / 1000;
660 weston_output_finish_frame(&output->base, msecs);
661 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200662}
663
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500664static uint32_t
665drm_output_check_sprite_format(struct drm_sprite *s,
666 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500667{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500668 uint32_t i, format;
669
670 format = gbm_bo_get_format(bo);
671
672 if (format == GBM_FORMAT_ARGB8888) {
673 pixman_region32_t r;
674
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500675 pixman_region32_init_rect(&r, 0, 0,
676 es->geometry.width,
677 es->geometry.height);
678 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500679
680 if (!pixman_region32_not_empty(&r))
681 format = GBM_FORMAT_XRGB8888;
682
683 pixman_region32_fini(&r);
684 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500685
686 for (i = 0; i < s->count_formats; i++)
687 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500688 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500689
690 return 0;
691}
692
693static int
694drm_surface_transform_supported(struct weston_surface *es)
695{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500696 return !es->transform.enabled ||
697 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500698}
699
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400700static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500701drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400702 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500703{
704 struct weston_compositor *ec = output_base->compositor;
705 struct drm_compositor *c =(struct drm_compositor *) ec;
706 struct drm_sprite *s;
707 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500708 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500709 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200710 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500711 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400712 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500713
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200714 if (c->gbm == NULL)
715 return NULL;
716
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200717 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200718 return NULL;
719
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500720 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400721 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500722
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300723 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400724 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300725
Pekka Paalanende685b82012-12-04 15:58:12 +0200726 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400727 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500728
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200729 if (es->alpha != 1.0f)
730 return NULL;
731
Pekka Paalanende685b82012-12-04 15:58:12 +0200732 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500733 return NULL;
734
Jesse Barnes58ef3792012-02-23 09:45:49 -0500735 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400736 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500737
Jesse Barnes58ef3792012-02-23 09:45:49 -0500738 wl_list_for_each(s, &c->sprite_list, link) {
739 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
740 continue;
741
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200742 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500743 found = 1;
744 break;
745 }
746 }
747
748 /* No sprites available */
749 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400750 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500751
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400752 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200753 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400754 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400755 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400756
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500757 format = drm_output_check_sprite_format(s, es, bo);
758 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200759 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400760 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500761 }
762
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200763 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200764 if (!s->next) {
765 gbm_bo_destroy(bo);
766 return NULL;
767 }
768
Pekka Paalanende685b82012-12-04 15:58:12 +0200769 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400771 box = pixman_region32_extents(&es->transform.boundingbox);
772 s->plane.x = box->x1;
773 s->plane.y = box->y1;
774
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775 /*
776 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200777 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500778 * for us already).
779 */
780 pixman_region32_init(&dest_rect);
781 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
782 &output_base->region);
783 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
784 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200785 tbox = weston_transformed_rect(output_base->width,
786 output_base->height,
787 output_base->transform, *box);
788 s->dest_x = tbox.x1;
789 s->dest_y = tbox.y1;
790 s->dest_w = tbox.x2 - tbox.x1;
791 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792 pixman_region32_fini(&dest_rect);
793
794 pixman_region32_init(&src_rect);
795 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
796 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500797 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400798
799 weston_surface_from_global_fixed(es,
800 wl_fixed_from_int(box->x1),
801 wl_fixed_from_int(box->y1),
802 &sx1, &sy1);
803 weston_surface_from_global_fixed(es,
804 wl_fixed_from_int(box->x2),
805 wl_fixed_from_int(box->y2),
806 &sx2, &sy2);
807
808 if (sx1 < 0)
809 sx1 = 0;
810 if (sy1 < 0)
811 sy1 = 0;
812 if (sx2 > wl_fixed_from_int(es->geometry.width))
813 sx2 = wl_fixed_from_int(es->geometry.width);
814 if (sy2 > wl_fixed_from_int(es->geometry.height))
815 sy2 = wl_fixed_from_int(es->geometry.height);
816
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200817 tbox.x1 = sx1;
818 tbox.y1 = sy1;
819 tbox.x2 = sx2;
820 tbox.y2 = sy2;
821
822 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
823 wl_fixed_from_int(es->geometry.height),
824 es->buffer_transform, tbox);
825
826 s->src_x = tbox.x1 << 8;
827 s->src_y = tbox.y1 << 8;
828 s->src_w = (tbox.x2 - tbox.x1) << 8;
829 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500830 pixman_region32_fini(&src_rect);
831
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400832 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833}
834
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400835static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400836drm_output_prepare_cursor_surface(struct weston_output *output_base,
837 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500838{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400839 struct drm_compositor *c =
840 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400841 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400842
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200843 if (c->gbm == NULL)
844 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200845 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
846 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400847 if (output->cursor_surface)
848 return NULL;
849 if (es->output_mask != (1u << output_base->id))
850 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500851 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400852 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200853 if (es->buffer_ref.buffer == NULL ||
854 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400855 es->geometry.width > 64 || es->geometry.height > 64)
856 return NULL;
857
858 output->cursor_surface = es;
859
860 return &output->cursor_plane;
861}
862
863static void
864drm_output_set_cursor(struct drm_output *output)
865{
866 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400867 struct drm_compositor *c =
868 (struct drm_compositor *) output->base.compositor;
869 EGLint handle, stride;
870 struct gbm_bo *bo;
871 uint32_t buf[64 * 64];
872 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400873 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500874
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400875 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400876 if (es == NULL) {
877 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
878 return;
879 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500880
Pekka Paalanende685b82012-12-04 15:58:12 +0200881 if (es->buffer_ref.buffer &&
882 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400883 pixman_region32_fini(&output->cursor_plane.damage);
884 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400885 output->current_cursor ^= 1;
886 bo = output->cursor_bo[output->current_cursor];
887 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200888 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
889 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400890 for (i = 0; i < es->geometry.height; i++)
891 memcpy(buf + i * 64, s + i * stride,
892 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500893
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400894 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300895 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400896
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400897 handle = gbm_bo_get_handle(bo).s32;
898 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500899 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300900 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500901 c->cursors_are_broken = 1;
902 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400903 }
904
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400905 x = es->geometry.x - output->base.x;
906 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400907 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500908 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400909 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500910 c->cursors_are_broken = 1;
911 }
912
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400913 output->cursor_plane.x = x;
914 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400915 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500916}
917
Jesse Barnes58ef3792012-02-23 09:45:49 -0500918static void
919drm_assign_planes(struct weston_output *output)
920{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400921 struct drm_compositor *c =
922 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200923 struct drm_output *drm_output = (struct drm_output *) output;
924 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400925 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500926 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400927 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500928
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200929 /* Reset the opaque region of the planes */
930 pixman_region32_fini(&drm_output->cursor_plane.opaque);
931 pixman_region32_init(&drm_output->cursor_plane.opaque);
932 pixman_region32_fini(&drm_output->fb_plane.opaque);
933 pixman_region32_init(&drm_output->fb_plane.opaque);
934
935 wl_list_for_each (s, &c->sprite_list, link) {
936 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
937 continue;
938
939 pixman_region32_fini(&s->plane.opaque);
940 pixman_region32_init(&s->plane.opaque);
941 }
942
Jesse Barnes58ef3792012-02-23 09:45:49 -0500943 /*
944 * Find a surface for each sprite in the output using some heuristics:
945 * 1) size
946 * 2) frequency of update
947 * 3) opacity (though some hw might support alpha blending)
948 * 4) clipping (this can be fixed with color keys)
949 *
950 * The idea is to save on blitting since this should save power.
951 * If we can get a large video surface on the sprite for example,
952 * the main display surface may not need to update at all, and
953 * the client buffer can be used directly for the sprite surface
954 * as we do for flipping full screen surfaces.
955 */
956 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400957 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400958 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200959 /* test whether this buffer can ever go into a plane:
960 * non-shm, or small enough to be a cursor
961 */
962 if ((es->buffer_ref.buffer &&
963 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
964 (es->geometry.width <= 64 && es->geometry.height <= 64))
965 es->keep_buffer = 1;
966 else
967 es->keep_buffer = 0;
968
Jesse Barnes58ef3792012-02-23 09:45:49 -0500969 pixman_region32_init(&surface_overlap);
970 pixman_region32_intersect(&surface_overlap, &overlap,
971 &es->transform.boundingbox);
972
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400973 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400974 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400975 next_plane = primary;
976 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400977 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400978 if (next_plane == NULL)
979 next_plane = drm_output_prepare_scanout_surface(output, es);
980 if (next_plane == NULL)
981 next_plane = drm_output_prepare_overlay_surface(output, es);
982 if (next_plane == NULL)
983 next_plane = primary;
984 weston_surface_move_to_plane(es, next_plane);
985 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500986 pixman_region32_union(&overlap, &overlap,
987 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400988
Jesse Barnes58ef3792012-02-23 09:45:49 -0500989 pixman_region32_fini(&surface_overlap);
990 }
991 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500992}
993
Matt Roper361d2ad2011-08-29 13:52:23 -0700994static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200995drm_output_fini_pixman(struct drm_output *output);
996
997static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500998drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700999{
1000 struct drm_output *output = (struct drm_output *) output_base;
1001 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001002 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001003 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001004
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001005 if (output->backlight)
1006 backlight_destroy(output->backlight);
1007
Matt Roper361d2ad2011-08-29 13:52:23 -07001008 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001009 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001010
1011 /* Restore original CRTC state */
1012 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001013 origcrtc->x, origcrtc->y,
1014 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001015 drmModeFreeCrtc(origcrtc);
1016
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001017 c->crtc_allocator &= ~(1 << output->crtc_id);
1018 c->connector_allocator &= ~(1 << output->connector_id);
1019
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001020 if (c->use_pixman) {
1021 drm_output_fini_pixman(output);
1022 } else {
1023 gl_renderer_output_destroy(output_base);
1024 gbm_surface_destroy(output->surface);
1025 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001026
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001027 weston_plane_release(&output->fb_plane);
1028 weston_plane_release(&output->cursor_plane);
1029
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001030 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001031 wl_list_remove(&output->base.link);
1032
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001033 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001034 free(output);
1035}
1036
Alex Wub7b8bda2012-04-17 17:20:48 +08001037static struct drm_mode *
1038choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1039{
1040 struct drm_mode *tmp_mode = NULL, *mode;
1041
1042 if (output->base.current->width == target_mode->width &&
1043 output->base.current->height == target_mode->height &&
1044 (output->base.current->refresh == target_mode->refresh ||
1045 target_mode->refresh == 0))
1046 return (struct drm_mode *)output->base.current;
1047
1048 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1049 if (mode->mode_info.hdisplay == target_mode->width &&
1050 mode->mode_info.vdisplay == target_mode->height) {
1051 if (mode->mode_info.vrefresh == target_mode->refresh ||
1052 target_mode->refresh == 0) {
1053 return mode;
1054 } else if (!tmp_mode)
1055 tmp_mode = mode;
1056 }
1057 }
1058
1059 return tmp_mode;
1060}
1061
1062static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001063drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001064static int
1065drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001066
1067static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001068drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1069{
1070 struct drm_output *output;
1071 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001072 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001073
1074 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001075 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001076 return -1;
1077 }
1078
1079 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001080 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001081 return -1;
1082 }
1083
1084 ec = (struct drm_compositor *)output_base->compositor;
1085 output = (struct drm_output *)output_base;
1086 drm_mode = choose_mode (output, mode);
1087
1088 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001089 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001090 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001091 }
1092
1093 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001094 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001095
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001096 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001097
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001098 output->base.current = &drm_mode->base;
1099 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001100 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1101
Alex Wub7b8bda2012-04-17 17:20:48 +08001102 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001103 drm_output_release_fb(output, output->current);
1104 drm_output_release_fb(output, output->next);
1105 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001106
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001107 if (ec->use_pixman) {
1108 drm_output_fini_pixman(output);
1109 if (drm_output_init_pixman(output, ec) < 0) {
1110 weston_log("failed to init output pixman state with "
1111 "new mode\n");
1112 return -1;
1113 }
1114 } else {
1115 gl_renderer_output_destroy(&output->base);
1116 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001117
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001118 if (drm_output_init_egl(output, ec) < 0) {
1119 weston_log("failed to init output egl state with "
1120 "new mode");
1121 return -1;
1122 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001123 }
1124
Alex Wub7b8bda2012-04-17 17:20:48 +08001125 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001126}
1127
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001128static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001129on_drm_input(int fd, uint32_t mask, void *data)
1130{
1131 drmEventContext evctx;
1132
1133 memset(&evctx, 0, sizeof evctx);
1134 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1135 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001136 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001137 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001138
1139 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001140}
1141
1142static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001143init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001144{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001145 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001146 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001147
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001148 sysnum = udev_device_get_sysnum(device);
1149 if (sysnum)
1150 ec->drm.id = atoi(sysnum);
1151 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001152 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001153 return -1;
1154 }
1155
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001156 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001157 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001158 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001159 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001160 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001161 udev_device_get_devnode(device));
1162 return -1;
1163 }
1164
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001165 weston_log("using %s\n", filename);
1166
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001167 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001168
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001169
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001170 return 0;
1171}
1172
1173static int
1174init_egl(struct drm_compositor *ec)
1175{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001176 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001177
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001178 if (!ec->gbm)
1179 return -1;
1180
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001181 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001182 NULL) < 0) {
1183 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001184 return -1;
1185 }
1186
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001187 return 0;
1188}
1189
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001190static int
1191init_pixman(struct drm_compositor *ec)
1192{
1193 return pixman_renderer_init(&ec->base);
1194}
1195
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001196static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001197drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1198{
1199 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001200 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001201
1202 mode = malloc(sizeof *mode);
1203 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001204 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001205
1206 mode->base.flags = 0;
1207 mode->base.width = info->hdisplay;
1208 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001209
1210 /* Calculate higher precision (mHz) refresh rate */
1211 refresh = (info->clock * 1000000LL / info->htotal +
1212 info->vtotal / 2) / info->vtotal;
1213
1214 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1215 refresh *= 2;
1216 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1217 refresh /= 2;
1218 if (info->vscan > 1)
1219 refresh /= info->vscan;
1220
1221 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001222 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001223
1224 if (info->type & DRM_MODE_TYPE_PREFERRED)
1225 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1226
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001227 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1228
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001229 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001230}
1231
1232static int
1233drm_subpixel_to_wayland(int drm_value)
1234{
1235 switch (drm_value) {
1236 default:
1237 case DRM_MODE_SUBPIXEL_UNKNOWN:
1238 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1239 case DRM_MODE_SUBPIXEL_NONE:
1240 return WL_OUTPUT_SUBPIXEL_NONE;
1241 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1242 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1243 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1244 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1245 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1246 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1247 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1248 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1249 }
1250}
1251
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001252/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001253static uint32_t
1254drm_get_backlight(struct drm_output *output)
1255{
1256 long brightness, max_brightness, norm;
1257
1258 brightness = backlight_get_brightness(output->backlight);
1259 max_brightness = backlight_get_max_brightness(output->backlight);
1260
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001261 /* convert it on a scale of 0 to 255 */
1262 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001263
1264 return (uint32_t) norm;
1265}
1266
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001267/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001268static void
1269drm_set_backlight(struct weston_output *output_base, uint32_t value)
1270{
1271 struct drm_output *output = (struct drm_output *) output_base;
1272 long max_brightness, new_brightness;
1273
1274 if (!output->backlight)
1275 return;
1276
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001277 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001278 return;
1279
1280 max_brightness = backlight_get_max_brightness(output->backlight);
1281
1282 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001283 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001284
1285 backlight_set_brightness(output->backlight, new_brightness);
1286}
1287
1288static drmModePropertyPtr
1289drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1290{
1291 drmModePropertyPtr props;
1292 int i;
1293
1294 for (i = 0; i < connector->count_props; i++) {
1295 props = drmModeGetProperty(fd, connector->props[i]);
1296 if (!props)
1297 continue;
1298
1299 if (!strcmp(props->name, name))
1300 return props;
1301
1302 drmModeFreeProperty(props);
1303 }
1304
1305 return NULL;
1306}
1307
1308static void
1309drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1310{
1311 struct drm_output *output = (struct drm_output *) output_base;
1312 struct weston_compositor *ec = output_base->compositor;
1313 struct drm_compositor *c = (struct drm_compositor *) ec;
1314 drmModeConnectorPtr connector;
1315 drmModePropertyPtr prop;
1316
1317 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1318 if (!connector)
1319 return;
1320
1321 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1322 if (!prop) {
1323 drmModeFreeConnector(connector);
1324 return;
1325 }
1326
1327 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1328 prop->prop_id, level);
1329 drmModeFreeProperty(prop);
1330 drmModeFreeConnector(connector);
1331}
1332
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001333static const char *connector_type_names[] = {
1334 "None",
1335 "VGA",
1336 "DVI",
1337 "DVI",
1338 "DVI",
1339 "Composite",
1340 "TV",
1341 "LVDS",
1342 "CTV",
1343 "DIN",
1344 "DP",
1345 "HDMI",
1346 "HDMI",
1347 "TV",
1348 "eDP",
1349};
1350
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001351static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001352find_crtc_for_connector(struct drm_compositor *ec,
1353 drmModeRes *resources, drmModeConnector *connector)
1354{
1355 drmModeEncoder *encoder;
1356 uint32_t possible_crtcs;
1357 int i, j;
1358
1359 for (j = 0; j < connector->count_encoders; j++) {
1360 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1361 if (encoder == NULL) {
1362 weston_log("Failed to get encoder.\n");
1363 return -1;
1364 }
1365 possible_crtcs = encoder->possible_crtcs;
1366 drmModeFreeEncoder(encoder);
1367
1368 for (i = 0; i < resources->count_crtcs; i++) {
1369 if (possible_crtcs & (1 << i) &&
1370 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1371 return i;
1372 }
1373 }
1374
1375 return -1;
1376}
1377
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001378/* Init output state that depends on gl or gbm */
1379static int
1380drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1381{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001382 int i, flags;
1383
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001384 output->surface = gbm_surface_create(ec->gbm,
1385 output->base.current->width,
1386 output->base.current->height,
1387 GBM_FORMAT_XRGB8888,
1388 GBM_BO_USE_SCANOUT |
1389 GBM_BO_USE_RENDERING);
1390 if (!output->surface) {
1391 weston_log("failed to create gbm surface\n");
1392 return -1;
1393 }
1394
1395 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001396 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001397 gbm_surface_destroy(output->surface);
1398 return -1;
1399 }
1400
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001401 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1402
1403 for (i = 0; i < 2; i++) {
1404 if (output->cursor_bo[i])
1405 continue;
1406
1407 output->cursor_bo[i] =
1408 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1409 flags);
1410 }
1411
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001412 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1413 weston_log("cursor buffers unavailable, using gl cursors\n");
1414 ec->cursors_are_broken = 1;
1415 }
1416
1417 return 0;
1418}
1419
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001420static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001421drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1422{
1423 int w = output->base.current->width;
1424 int h = output->base.current->height;
1425 unsigned int i;
1426
1427 /* FIXME error checking */
1428
1429 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1430 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1431 if (!output->dumb[i])
1432 goto err;
1433
1434 output->image[i] =
1435 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1436 output->dumb[i]->map,
1437 output->dumb[i]->stride);
1438 if (!output->image[i])
1439 goto err;
1440 }
1441
1442 if (pixman_renderer_output_create(&output->base) < 0)
1443 goto err;
1444
1445 pixman_region32_init_rect(&output->previous_damage,
1446 output->base.x, output->base.y, w, h);
1447
1448 return 0;
1449
1450err:
1451 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1452 if (output->dumb[i])
1453 drm_fb_destroy_dumb(output->dumb[i]);
1454 if (output->image[i])
1455 pixman_image_unref(output->image[i]);
1456
1457 output->dumb[i] = NULL;
1458 output->image[i] = NULL;
1459 }
1460
1461 return -1;
1462}
1463
1464static void
1465drm_output_fini_pixman(struct drm_output *output)
1466{
1467 unsigned int i;
1468
1469 pixman_renderer_output_destroy(&output->base);
1470 pixman_region32_fini(&output->previous_damage);
1471
1472 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1473 drm_fb_destroy_dumb(output->dumb[i]);
1474 pixman_image_unref(output->image[i]);
1475 output->dumb[i] = NULL;
1476 output->image[i] = NULL;
1477 }
1478}
1479
1480static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001481create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001482 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001483 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001484 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001485{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001486 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001487 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1488 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001489 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001490 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001491 drmModeModeInfo crtc_mode;
1492 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001493 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001494 char name[32];
1495 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001496
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001497 i = find_crtc_for_connector(ec, resources, connector);
1498 if (i < 0) {
1499 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001500 return -1;
1501 }
1502
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001503 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001504 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001505 return -1;
1506
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001507 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001508 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1509 output->base.make = "unknown";
1510 output->base.model = "unknown";
1511 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001512
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001513 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1514 type_name = connector_type_names[connector->connector_type];
1515 else
1516 type_name = "UNKNOWN";
1517 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1518 output->name = strdup(name);
1519
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001520 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001521 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001522 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001523 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001524 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001525
Matt Roper361d2ad2011-08-29 13:52:23 -07001526 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1527
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001528 /* Get the current mode on the crtc that's currently driving
1529 * this connector. */
1530 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001531 memset(&crtc_mode, 0, sizeof crtc_mode);
1532 if (encoder != NULL) {
1533 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1534 drmModeFreeEncoder(encoder);
1535 if (crtc == NULL)
1536 goto err_free;
1537 if (crtc->mode_valid)
1538 crtc_mode = crtc->mode;
1539 drmModeFreeCrtc(crtc);
1540 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001541
David Herrmann0f0d54e2011-12-08 17:05:45 +01001542 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001543 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1544 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001545 goto err_free;
1546 }
1547
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001548 preferred = NULL;
1549 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001550 configured = NULL;
1551
1552 wl_list_for_each(temp, &configured_output_list, link) {
1553 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001554 if (temp->mode)
1555 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001556 temp->name, temp->mode);
1557 o = temp;
1558 break;
1559 }
1560 }
1561
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001562 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001563 weston_log("Disabling output %s\n", o->name);
1564
1565 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1566 0, 0, 0, 0, 0, NULL);
1567 goto err_free;
1568 }
1569
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001570 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001571 if (o && o->config == OUTPUT_CONFIG_MODE &&
1572 o->width == drm_mode->base.width &&
1573 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001574 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001575 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001576 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001577 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001578 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001579 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001580
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001581 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001582 configured = drm_output_add_mode(output, &o->crtc_mode);
1583 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001584 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001585 current = configured;
1586 }
1587
Wang Quanxianacb805a2012-07-30 18:09:46 -04001588 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001589 current = drm_output_add_mode(output, &crtc_mode);
1590 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001591 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001592 }
1593
Scott Moreau8ab5d452012-07-30 19:51:08 -06001594 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1595 configured = current;
1596
Wang Quanxianacb805a2012-07-30 18:09:46 -04001597 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001598 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001599 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001600 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001601 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001602 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001603 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001604 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001605
1606 if (output->base.current == NULL) {
1607 weston_log("no available modes for %s\n", output->name);
1608 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001609 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001610
Wang Quanxianacb805a2012-07-30 18:09:46 -04001611 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1612
John Kåre Alsaker94659272012-11-13 19:10:18 +01001613 weston_output_init(&output->base, &ec->base, x, y,
1614 connector->mmWidth, connector->mmHeight,
1615 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1616
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001617 if (ec->use_pixman) {
1618 if (drm_output_init_pixman(output, ec) < 0) {
1619 weston_log("Failed to init output pixman state\n");
1620 goto err_output;
1621 }
1622 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001623 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001624 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001625 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001626
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001627 output->backlight = backlight_init(drm_device,
1628 connector->connector_type);
1629 if (output->backlight) {
1630 output->base.set_backlight = drm_set_backlight;
1631 output->base.backlight_current = drm_get_backlight(output);
1632 }
1633
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001634 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1635
Alex Wubd3354b2012-04-17 17:20:49 +08001636 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001637 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001638 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001639 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001640 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001641 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001642
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001643 weston_plane_init(&output->cursor_plane, 0, 0);
1644 weston_plane_init(&output->fb_plane, 0, 0);
1645
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001646 weston_log("Output %s, (connector %d, crtc %d)\n",
1647 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001648 wl_list_for_each(m, &output->base.mode_list, link)
1649 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1650 m->width, m->height, m->refresh / 1000.0,
1651 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1652 ", preferred" : "",
1653 m->flags & WL_OUTPUT_MODE_CURRENT ?
1654 ", current" : "",
1655 connector->count_modes == 0 ?
1656 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001657
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001658 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001659
John Kåre Alsaker94659272012-11-13 19:10:18 +01001660err_output:
1661 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001662err_free:
1663 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1664 base.link) {
1665 wl_list_remove(&drm_mode->base.link);
1666 free(drm_mode);
1667 }
1668
1669 drmModeFreeCrtc(output->original_crtc);
1670 ec->crtc_allocator &= ~(1 << output->crtc_id);
1671 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001672 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001673 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001674
David Herrmann0f0d54e2011-12-08 17:05:45 +01001675 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001676}
1677
Jesse Barnes58ef3792012-02-23 09:45:49 -05001678static void
1679create_sprites(struct drm_compositor *ec)
1680{
1681 struct drm_sprite *sprite;
1682 drmModePlaneRes *plane_res;
1683 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001684 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001685
1686 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1687 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001688 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001689 strerror(errno));
1690 return;
1691 }
1692
1693 for (i = 0; i < plane_res->count_planes; i++) {
1694 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1695 if (!plane)
1696 continue;
1697
1698 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1699 plane->count_formats));
1700 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001701 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001702 __func__);
1703 free(plane);
1704 continue;
1705 }
1706
1707 memset(sprite, 0, sizeof *sprite);
1708
1709 sprite->possible_crtcs = plane->possible_crtcs;
1710 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001711 sprite->current = NULL;
1712 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001713 sprite->compositor = ec;
1714 sprite->count_formats = plane->count_formats;
1715 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001716 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001717 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001718 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001719
1720 wl_list_insert(&ec->sprite_list, &sprite->link);
1721 }
1722
1723 free(plane_res->planes);
1724 free(plane_res);
1725}
1726
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001727static void
1728destroy_sprites(struct drm_compositor *compositor)
1729{
1730 struct drm_sprite *sprite, *next;
1731 struct drm_output *output;
1732
1733 output = container_of(compositor->base.output_list.next,
1734 struct drm_output, base.link);
1735
1736 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1737 drmModeSetPlane(compositor->drm.fd,
1738 sprite->plane_id,
1739 output->crtc_id, 0, 0,
1740 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001741 drm_output_release_fb(output, sprite->current);
1742 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001743 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001744 free(sprite);
1745 }
1746}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001747
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001748static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001749create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001750 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001751{
1752 drmModeConnector *connector;
1753 drmModeRes *resources;
1754 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001755 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001756
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001757 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001758 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001759 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001760 return -1;
1761 }
1762
Jesse Barnes58ef3792012-02-23 09:45:49 -05001763 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001764 if (!ec->crtcs) {
1765 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001766 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001767 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001768
Rob Clark4339add2012-08-09 14:18:28 -05001769 ec->min_width = resources->min_width;
1770 ec->max_width = resources->max_width;
1771 ec->min_height = resources->min_height;
1772 ec->max_height = resources->max_height;
1773
Jesse Barnes58ef3792012-02-23 09:45:49 -05001774 ec->num_crtcs = resources->count_crtcs;
1775 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1776
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001777 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001778 connector = drmModeGetConnector(ec->drm.fd,
1779 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001780 if (connector == NULL)
1781 continue;
1782
1783 if (connector->connection == DRM_MODE_CONNECTED &&
1784 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001785 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001786 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001787 connector, x, y,
1788 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001789 drmModeFreeConnector(connector);
1790 continue;
1791 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001792
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001793 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001794 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001795 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001796 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001797
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001798 drmModeFreeConnector(connector);
1799 }
1800
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001801 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001802 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001803 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001804 return -1;
1805 }
1806
1807 drmModeFreeResources(resources);
1808
1809 return 0;
1810}
1811
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001812static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001813update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001814{
1815 drmModeConnector *connector;
1816 drmModeRes *resources;
1817 struct drm_output *output, *next;
1818 int x = 0, y = 0;
1819 int x_offset = 0, y_offset = 0;
1820 uint32_t connected = 0, disconnects = 0;
1821 int i;
1822
1823 resources = drmModeGetResources(ec->drm.fd);
1824 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001825 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001826 return;
1827 }
1828
1829 /* collect new connects */
1830 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001831 int connector_id = resources->connectors[i];
1832
1833 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001834 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001835 continue;
1836
David Herrmann7551cff2011-12-08 17:05:43 +01001837 if (connector->connection != DRM_MODE_CONNECTED) {
1838 drmModeFreeConnector(connector);
1839 continue;
1840 }
1841
Benjamin Franzke117483d2011-08-30 11:38:26 +02001842 connected |= (1 << connector_id);
1843
1844 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001845 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001846 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001847 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001848
1849 /* XXX: not yet needed, we die with 0 outputs */
1850 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001851 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001852 else
1853 x = 0;
1854 y = 0;
1855 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001856 connector, x, y,
1857 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001858 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001859
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001860 }
1861 drmModeFreeConnector(connector);
1862 }
1863 drmModeFreeResources(resources);
1864
1865 disconnects = ec->connector_allocator & ~connected;
1866 if (disconnects) {
1867 wl_list_for_each_safe(output, next, &ec->base.output_list,
1868 base.link) {
1869 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001870 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001871 output->base.x - x_offset,
1872 output->base.y - y_offset);
1873 }
1874
1875 if (disconnects & (1 << output->connector_id)) {
1876 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001877 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001878 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001879 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001880 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001881 }
1882 }
1883 }
1884
1885 /* FIXME: handle zero outputs, without terminating */
1886 if (ec->connector_allocator == 0)
1887 wl_display_terminate(ec->base.wl_display);
1888}
1889
1890static int
David Herrmannd7488c22012-03-11 20:05:21 +01001891udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001892{
David Herrmannd7488c22012-03-11 20:05:21 +01001893 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001894 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001895
1896 sysnum = udev_device_get_sysnum(device);
1897 if (!sysnum || atoi(sysnum) != ec->drm.id)
1898 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001899
David Herrmann6ac52db2012-03-11 20:05:22 +01001900 val = udev_device_get_property_value(device, "HOTPLUG");
1901 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001902 return 0;
1903
David Herrmann6ac52db2012-03-11 20:05:22 +01001904 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001905}
1906
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001907static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001908udev_drm_event(int fd, uint32_t mask, void *data)
1909{
1910 struct drm_compositor *ec = data;
1911 struct udev_device *event;
1912
1913 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001914
David Herrmannd7488c22012-03-11 20:05:21 +01001915 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001916 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001917
1918 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001919
1920 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001921}
1922
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001923static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001924drm_restore(struct weston_compositor *ec)
1925{
1926 struct drm_compositor *d = (struct drm_compositor *) ec;
1927
1928 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1929 weston_log("failed to drop master: %m\n");
1930 tty_reset(d->tty);
1931}
1932
1933static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001934drm_free_configured_output(struct drm_configured_output *output)
1935{
1936 free(output->name);
1937 free(output->mode);
1938 free(output);
1939}
1940
1941static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001942drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001943{
1944 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05001945 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001946 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001947
Kristian Høgsberge8091032013-02-18 15:43:29 -05001948 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
1949 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001950 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001951 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001952
1953 wl_event_source_remove(d->udev_drm_source);
1954 wl_event_source_remove(d->drm_source);
1955
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001956 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001957
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03001958 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001959
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001960 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001961
1962 if (d->gbm)
1963 gbm_device_destroy(d->gbm);
1964
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001965 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001966 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001967 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001968
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001969 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001970}
1971
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001972static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001973drm_compositor_set_modes(struct drm_compositor *compositor)
1974{
1975 struct drm_output *output;
1976 struct drm_mode *drm_mode;
1977 int ret;
1978
1979 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02001980 if (!output->current) {
1981 /* If something that would cause the output to
1982 * switch mode happened while in another vt, we
1983 * might not have a current drm_fb. In that case,
1984 * schedule a repaint and let drm_output_repaint
1985 * handle setting the mode. */
1986 weston_output_schedule_repaint(&output->base);
1987 continue;
1988 }
1989
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001990 drm_mode = (struct drm_mode *) output->base.current;
1991 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001992 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001993 &output->connector_id, 1,
1994 &drm_mode->mode_info);
1995 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001996 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001997 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001998 drm_mode->base.width, drm_mode->base.height,
1999 output->base.x, output->base.y);
2000 }
2001 }
2002}
2003
2004static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002005vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002006{
2007 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002008 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002009 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002010 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002011
2012 switch (event) {
2013 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002014 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002015 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002016 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002017 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002018 wl_display_terminate(compositor->wl_display);
2019 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002020 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002021 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002022 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002023 wl_list_for_each(seat, &compositor->seat_list, base.link)
2024 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002025 break;
2026 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002027 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002028 wl_list_for_each(seat, &compositor->seat_list, base.link)
2029 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002030
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002031 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002032 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002033 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002034
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002035 /* If we have a repaint scheduled (either from a
2036 * pending pageflip or the idle handler), make sure we
2037 * cancel that so we don't try to pageflip when we're
2038 * vt switched away. The SLEEPING state will prevent
2039 * further attemps at repainting. When we switch
2040 * back, we schedule a repaint, which will process
2041 * pending frame callbacks. */
2042
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002043 wl_list_for_each(output, &ec->base.output_list, base.link) {
2044 output->base.repaint_needed = 0;
2045 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002046 }
2047
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002048 output = container_of(ec->base.output_list.next,
2049 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002050
2051 wl_list_for_each(sprite, &ec->sprite_list, link)
2052 drmModeSetPlane(ec->drm.fd,
2053 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002054 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002055 0, 0, 0, 0, 0, 0, 0, 0);
2056
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002057 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002058 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002059
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002060 break;
2061 };
2062}
2063
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002064static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002065switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002066{
2067 struct drm_compositor *ec = data;
2068
Daniel Stone325fc2d2012-05-30 16:31:58 +01002069 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002070}
2071
David Herrmann0af066f2012-10-29 19:21:16 +01002072/*
2073 * Find primary GPU
2074 * Some systems may have multiple DRM devices attached to a single seat. This
2075 * function loops over all devices and tries to find a PCI device with the
2076 * boot_vga sysfs attribute set to 1.
2077 * If no such device is found, the first DRM device reported by udev is used.
2078 */
2079static struct udev_device*
2080find_primary_gpu(struct drm_compositor *ec, const char *seat)
2081{
2082 struct udev_enumerate *e;
2083 struct udev_list_entry *entry;
2084 const char *path, *device_seat, *id;
2085 struct udev_device *device, *drm_device, *pci;
2086
2087 e = udev_enumerate_new(ec->udev);
2088 udev_enumerate_add_match_subsystem(e, "drm");
2089 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2090
2091 udev_enumerate_scan_devices(e);
2092 drm_device = NULL;
2093 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2094 path = udev_list_entry_get_name(entry);
2095 device = udev_device_new_from_syspath(ec->udev, path);
2096 if (!device)
2097 continue;
2098 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2099 if (!device_seat)
2100 device_seat = default_seat;
2101 if (strcmp(device_seat, seat)) {
2102 udev_device_unref(device);
2103 continue;
2104 }
2105
2106 pci = udev_device_get_parent_with_subsystem_devtype(device,
2107 "pci", NULL);
2108 if (pci) {
2109 id = udev_device_get_sysattr_value(pci, "boot_vga");
2110 if (id && !strcmp(id, "1")) {
2111 if (drm_device)
2112 udev_device_unref(drm_device);
2113 drm_device = device;
2114 break;
2115 }
2116 }
2117
2118 if (!drm_device)
2119 drm_device = device;
2120 else
2121 udev_device_unref(device);
2122 }
2123
2124 udev_enumerate_unref(e);
2125 return drm_device;
2126}
2127
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002128static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002129planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002130{
2131 struct drm_compositor *c = data;
2132
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002133 switch (key) {
2134 case KEY_C:
2135 c->cursors_are_broken ^= 1;
2136 break;
2137 case KEY_V:
2138 c->sprites_are_broken ^= 1;
2139 break;
2140 case KEY_O:
2141 c->sprites_hidden ^= 1;
2142 break;
2143 default:
2144 break;
2145 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002146}
2147
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002148static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002149drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002150 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002151 int *argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002152{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002153 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002154 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002155 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002156 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002157 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002158 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002159
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002160 weston_log("initializing drm backend\n");
2161
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002162 ec = malloc(sizeof *ec);
2163 if (ec == NULL)
2164 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002165 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002166
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002167 /* KMS support for sprites is not complete yet, so disable the
2168 * functionality for now. */
2169 ec->sprites_are_broken = 1;
2170
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002171 ec->use_pixman = pixman;
2172
Daniel Stone725c2c32012-06-22 14:04:36 +01002173 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002174 config_file) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002175 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002176 goto err_base;
2177 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002178
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002179 ec->udev = udev_new();
2180 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002181 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002182 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002183 }
2184
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002185 ec->base.wl_display = display;
2186 ec->tty = tty_create(&ec->base, vt_func, tty);
2187 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002188 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002189 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002190 }
2191
David Herrmann0af066f2012-10-29 19:21:16 +01002192 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002193 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002194 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002195 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002196 }
David Herrmann0af066f2012-10-29 19:21:16 +01002197 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002198
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002199 if (init_drm(ec, drm_device) < 0) {
2200 weston_log("failed to initialize kms\n");
2201 goto err_udev_dev;
2202 }
2203
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002204 if (ec->use_pixman) {
2205 if (init_pixman(ec) < 0) {
2206 weston_log("failed to initialize pixman renderer\n");
2207 goto err_udev_dev;
2208 }
2209 } else {
2210 if (init_egl(ec) < 0) {
2211 weston_log("failed to initialize egl\n");
2212 goto err_udev_dev;
2213 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002214 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002215
2216 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002217 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002218
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002219 ec->base.focus = 1;
2220
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002221 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002222
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002223 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002224 weston_compositor_add_key_binding(&ec->base, key,
2225 MODIFIER_CTRL | MODIFIER_ALT,
2226 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002227
Jesse Barnes58ef3792012-02-23 09:45:49 -05002228 wl_list_init(&ec->sprite_list);
2229 create_sprites(ec);
2230
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002231 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002232 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002233 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002234 }
2235
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002236 path = NULL;
2237
Kristian Høgsberge8091032013-02-18 15:43:29 -05002238 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002239 weston_log("failed to create input devices\n");
2240 goto err_sprite;
2241 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002242
2243 loop = wl_display_get_event_loop(ec->base.wl_display);
2244 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002245 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002246 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002247
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002248 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2249 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002250 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002251 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002252 }
2253 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2254 "drm", NULL);
2255 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002256 wl_event_loop_add_fd(loop,
2257 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002258 WL_EVENT_READABLE, udev_drm_event, ec);
2259
2260 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002261 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002262 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002263 }
2264
Daniel Stonea96b93c2012-06-22 14:04:37 +01002265 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002266
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002267 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002268 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002269 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002270 planes_binding, ec);
2271 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2272 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002273
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002274 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002275
2276err_udev_monitor:
2277 wl_event_source_remove(ec->udev_drm_source);
2278 udev_monitor_unref(ec->udev_monitor);
2279err_drm_source:
2280 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002281 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2282 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002283err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002284 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002285 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002286 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002287err_udev_dev:
2288 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002289err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002290 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2291 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002292 tty_destroy(ec->tty);
2293err_udev:
2294 udev_unref(ec->udev);
2295err_compositor:
2296 weston_compositor_shutdown(&ec->base);
2297err_base:
2298 free(ec);
2299 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002300}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002301
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002302static int
2303set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2304{
2305 mode->flags = 0;
2306
2307 if (strcmp(hsync, "+hsync") == 0)
2308 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2309 else if (strcmp(hsync, "-hsync") == 0)
2310 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2311 else
2312 return -1;
2313
2314 if (strcmp(vsync, "+vsync") == 0)
2315 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2316 else if (strcmp(vsync, "-vsync") == 0)
2317 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2318 else
2319 return -1;
2320
2321 return 0;
2322}
2323
2324static int
2325check_for_modeline(struct drm_configured_output *output)
2326{
2327 drmModeModeInfo mode;
2328 char hsync[16];
2329 char vsync[16];
2330 char mode_name[16];
2331 float fclock;
2332
2333 mode.type = DRM_MODE_TYPE_USERDEF;
2334 mode.hskew = 0;
2335 mode.vscan = 0;
2336 mode.vrefresh = 0;
2337
2338 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2339 &fclock, &mode.hdisplay,
2340 &mode.hsync_start,
2341 &mode.hsync_end, &mode.htotal,
2342 &mode.vdisplay,
2343 &mode.vsync_start,
2344 &mode.vsync_end, &mode.vtotal,
2345 hsync, vsync) == 11) {
2346 if (set_sync_flags(&mode, hsync, vsync))
2347 return -1;
2348
2349 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2350 strcpy(mode.name, mode_name);
2351
2352 mode.clock = fclock * 1000;
2353 } else
2354 return -1;
2355
2356 output->crtc_mode = mode;
2357
2358 return 0;
2359}
2360
Scott Moreau8ab5d452012-07-30 19:51:08 -06002361static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002362drm_output_set_transform(struct drm_configured_output *output)
2363{
2364 if (!output_transform) {
2365 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2366 return;
2367 }
2368
2369 if (!strcmp(output_transform, "normal"))
2370 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2371 else if (!strcmp(output_transform, "90"))
2372 output->transform = WL_OUTPUT_TRANSFORM_90;
2373 else if (!strcmp(output_transform, "180"))
2374 output->transform = WL_OUTPUT_TRANSFORM_180;
2375 else if (!strcmp(output_transform, "270"))
2376 output->transform = WL_OUTPUT_TRANSFORM_270;
2377 else if (!strcmp(output_transform, "flipped"))
2378 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2379 else if (!strcmp(output_transform, "flipped-90"))
2380 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2381 else if (!strcmp(output_transform, "flipped-180"))
2382 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2383 else if (!strcmp(output_transform, "flipped-270"))
2384 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2385 else {
2386 weston_log("Invalid transform \"%s\" for output %s\n",
2387 output_transform, output_name);
2388 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2389 }
2390
2391 free(output_transform);
2392 output_transform = NULL;
2393}
2394
2395static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002396output_section_done(void *data)
2397{
2398 struct drm_configured_output *output;
2399
2400 output = malloc(sizeof *output);
2401
Scott Moreau1bad5db2012-08-18 01:04:05 -06002402 if (!output || !output_name || (output_name[0] == 'X') ||
2403 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002404 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002405 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002406 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002407 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002408 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002409 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002410 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002411 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002412 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002413
2414 output->config = OUTPUT_CONFIG_INVALID;
2415 output->name = output_name;
2416 output->mode = output_mode;
2417
Scott Moreau1bad5db2012-08-18 01:04:05 -06002418 if (output_mode) {
2419 if (strcmp(output_mode, "off") == 0)
2420 output->config = OUTPUT_CONFIG_OFF;
2421 else if (strcmp(output_mode, "preferred") == 0)
2422 output->config = OUTPUT_CONFIG_PREFERRED;
2423 else if (strcmp(output_mode, "current") == 0)
2424 output->config = OUTPUT_CONFIG_CURRENT;
2425 else if (sscanf(output_mode, "%dx%d",
2426 &output->width, &output->height) == 2)
2427 output->config = OUTPUT_CONFIG_MODE;
2428 else if (check_for_modeline(output) == 0)
2429 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002430
Scott Moreau1bad5db2012-08-18 01:04:05 -06002431 if (output->config == OUTPUT_CONFIG_INVALID)
2432 weston_log("Invalid mode \"%s\" for output %s\n",
2433 output_mode, output_name);
2434 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002435 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002436
2437 drm_output_set_transform(output);
2438
2439 wl_list_insert(&configured_output_list, &output->link);
2440
2441 if (output_transform)
2442 free(output_transform);
2443 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002444}
2445
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002446WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002447backend_init(struct wl_display *display, int *argc, char *argv[],
Daniel Stonec1be8e52012-06-01 11:14:02 -04002448 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002449{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002450 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002451 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002452
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002453 const struct weston_option drm_options[] = {
2454 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2455 { WESTON_OPTION_STRING, "seat", 0, &seat },
2456 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002457 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002458 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002459 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002460
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002461 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002462
Scott Moreau8ab5d452012-07-30 19:51:08 -06002463 wl_list_init(&configured_output_list);
2464
2465 const struct config_key drm_config_keys[] = {
2466 { "name", CONFIG_KEY_STRING, &output_name },
2467 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002468 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002469 };
2470
2471 const struct config_section config_section[] = {
2472 { "output", drm_config_keys,
2473 ARRAY_LENGTH(drm_config_keys), output_section_done },
2474 };
2475
2476 parse_config_file(config_file, config_section,
2477 ARRAY_LENGTH(config_section), NULL);
2478
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002479 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2480 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002481}