blob: 3c44f7aa1042119b08b006699e719d4b5fc76b4e [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
675 pixman_region32_init(&r);
676 pixman_region32_subtract(&r, &es->transform.boundingbox,
677 &es->transform.opaque);
678
679 if (!pixman_region32_not_empty(&r))
680 format = GBM_FORMAT_XRGB8888;
681
682 pixman_region32_fini(&r);
683 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500684
685 for (i = 0; i < s->count_formats; i++)
686 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500687 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500688
689 return 0;
690}
691
692static int
693drm_surface_transform_supported(struct weston_surface *es)
694{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500695 return !es->transform.enabled ||
696 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500697}
698
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400699static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500700drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400701 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500702{
703 struct weston_compositor *ec = output_base->compositor;
704 struct drm_compositor *c =(struct drm_compositor *) ec;
705 struct drm_sprite *s;
706 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500707 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500708 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200709 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500710 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400711 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500712
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200713 if (c->gbm == NULL)
714 return NULL;
715
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200716 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200717 return NULL;
718
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500719 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400720 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500721
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300722 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400723 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300724
Pekka Paalanende685b82012-12-04 15:58:12 +0200725 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400726 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500727
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200728 if (es->alpha != 1.0f)
729 return NULL;
730
Pekka Paalanende685b82012-12-04 15:58:12 +0200731 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500732 return NULL;
733
Jesse Barnes58ef3792012-02-23 09:45:49 -0500734 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400735 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500736
Jesse Barnes58ef3792012-02-23 09:45:49 -0500737 wl_list_for_each(s, &c->sprite_list, link) {
738 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
739 continue;
740
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200741 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500742 found = 1;
743 break;
744 }
745 }
746
747 /* No sprites available */
748 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400749 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500750
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400751 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200752 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400753 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400754 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400755
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500756 format = drm_output_check_sprite_format(s, es, bo);
757 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200758 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400759 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500760 }
761
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200762 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200763 if (!s->next) {
764 gbm_bo_destroy(bo);
765 return NULL;
766 }
767
Pekka Paalanende685b82012-12-04 15:58:12 +0200768 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400770 box = pixman_region32_extents(&es->transform.boundingbox);
771 s->plane.x = box->x1;
772 s->plane.y = box->y1;
773
Jesse Barnes58ef3792012-02-23 09:45:49 -0500774 /*
775 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200776 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500777 * for us already).
778 */
779 pixman_region32_init(&dest_rect);
780 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
781 &output_base->region);
782 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
783 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200784 tbox = weston_transformed_rect(output_base->width,
785 output_base->height,
786 output_base->transform, *box);
787 s->dest_x = tbox.x1;
788 s->dest_y = tbox.y1;
789 s->dest_w = tbox.x2 - tbox.x1;
790 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500791 pixman_region32_fini(&dest_rect);
792
793 pixman_region32_init(&src_rect);
794 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
795 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500796 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400797
798 weston_surface_from_global_fixed(es,
799 wl_fixed_from_int(box->x1),
800 wl_fixed_from_int(box->y1),
801 &sx1, &sy1);
802 weston_surface_from_global_fixed(es,
803 wl_fixed_from_int(box->x2),
804 wl_fixed_from_int(box->y2),
805 &sx2, &sy2);
806
807 if (sx1 < 0)
808 sx1 = 0;
809 if (sy1 < 0)
810 sy1 = 0;
811 if (sx2 > wl_fixed_from_int(es->geometry.width))
812 sx2 = wl_fixed_from_int(es->geometry.width);
813 if (sy2 > wl_fixed_from_int(es->geometry.height))
814 sy2 = wl_fixed_from_int(es->geometry.height);
815
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200816 tbox.x1 = sx1;
817 tbox.y1 = sy1;
818 tbox.x2 = sx2;
819 tbox.y2 = sy2;
820
821 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
822 wl_fixed_from_int(es->geometry.height),
823 es->buffer_transform, tbox);
824
825 s->src_x = tbox.x1 << 8;
826 s->src_y = tbox.y1 << 8;
827 s->src_w = (tbox.x2 - tbox.x1) << 8;
828 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500829 pixman_region32_fini(&src_rect);
830
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400831 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500832}
833
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400835drm_output_prepare_cursor_surface(struct weston_output *output_base,
836 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500837{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400838 struct drm_compositor *c =
839 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400840 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400841
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200842 if (c->gbm == NULL)
843 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200844 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
845 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400846 if (output->cursor_surface)
847 return NULL;
848 if (es->output_mask != (1u << output_base->id))
849 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500850 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400851 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200852 if (es->buffer_ref.buffer == NULL ||
853 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400854 es->geometry.width > 64 || es->geometry.height > 64)
855 return NULL;
856
857 output->cursor_surface = es;
858
859 return &output->cursor_plane;
860}
861
862static void
863drm_output_set_cursor(struct drm_output *output)
864{
865 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400866 struct drm_compositor *c =
867 (struct drm_compositor *) output->base.compositor;
868 EGLint handle, stride;
869 struct gbm_bo *bo;
870 uint32_t buf[64 * 64];
871 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400872 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500873
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400874 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400875 if (es == NULL) {
876 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
877 return;
878 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500879
Pekka Paalanende685b82012-12-04 15:58:12 +0200880 if (es->buffer_ref.buffer &&
881 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400882 pixman_region32_fini(&output->cursor_plane.damage);
883 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400884 output->current_cursor ^= 1;
885 bo = output->cursor_bo[output->current_cursor];
886 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200887 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
888 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400889 for (i = 0; i < es->geometry.height; i++)
890 memcpy(buf + i * 64, s + i * stride,
891 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500892
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400893 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300894 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400895
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400896 handle = gbm_bo_get_handle(bo).s32;
897 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500898 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300899 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500900 c->cursors_are_broken = 1;
901 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400902 }
903
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400904 x = es->geometry.x - output->base.x;
905 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400906 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500907 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400908 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500909 c->cursors_are_broken = 1;
910 }
911
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400912 output->cursor_plane.x = x;
913 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400914 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500915}
916
Jesse Barnes58ef3792012-02-23 09:45:49 -0500917static void
918drm_assign_planes(struct weston_output *output)
919{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400920 struct drm_compositor *c =
921 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200922 struct drm_output *drm_output = (struct drm_output *) output;
923 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400924 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400926 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500927
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200928 /* Reset the opaque region of the planes */
929 pixman_region32_fini(&drm_output->cursor_plane.opaque);
930 pixman_region32_init(&drm_output->cursor_plane.opaque);
931 pixman_region32_fini(&drm_output->fb_plane.opaque);
932 pixman_region32_init(&drm_output->fb_plane.opaque);
933
934 wl_list_for_each (s, &c->sprite_list, link) {
935 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
936 continue;
937
938 pixman_region32_fini(&s->plane.opaque);
939 pixman_region32_init(&s->plane.opaque);
940 }
941
Jesse Barnes58ef3792012-02-23 09:45:49 -0500942 /*
943 * Find a surface for each sprite in the output using some heuristics:
944 * 1) size
945 * 2) frequency of update
946 * 3) opacity (though some hw might support alpha blending)
947 * 4) clipping (this can be fixed with color keys)
948 *
949 * The idea is to save on blitting since this should save power.
950 * If we can get a large video surface on the sprite for example,
951 * the main display surface may not need to update at all, and
952 * the client buffer can be used directly for the sprite surface
953 * as we do for flipping full screen surfaces.
954 */
955 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400956 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400957 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200958 /* test whether this buffer can ever go into a plane:
959 * non-shm, or small enough to be a cursor
960 */
961 if ((es->buffer_ref.buffer &&
962 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
963 (es->geometry.width <= 64 && es->geometry.height <= 64))
964 es->keep_buffer = 1;
965 else
966 es->keep_buffer = 0;
967
Jesse Barnes58ef3792012-02-23 09:45:49 -0500968 pixman_region32_init(&surface_overlap);
969 pixman_region32_intersect(&surface_overlap, &overlap,
970 &es->transform.boundingbox);
971
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400972 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400973 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400974 next_plane = primary;
975 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400976 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400977 if (next_plane == NULL)
978 next_plane = drm_output_prepare_scanout_surface(output, es);
979 if (next_plane == NULL)
980 next_plane = drm_output_prepare_overlay_surface(output, es);
981 if (next_plane == NULL)
982 next_plane = primary;
983 weston_surface_move_to_plane(es, next_plane);
984 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500985 pixman_region32_union(&overlap, &overlap,
986 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400987
Jesse Barnes58ef3792012-02-23 09:45:49 -0500988 pixman_region32_fini(&surface_overlap);
989 }
990 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500991}
992
Matt Roper361d2ad2011-08-29 13:52:23 -0700993static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200994drm_output_fini_pixman(struct drm_output *output);
995
996static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500997drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700998{
999 struct drm_output *output = (struct drm_output *) output_base;
1000 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001001 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001002 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001003
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001004 if (output->backlight)
1005 backlight_destroy(output->backlight);
1006
Matt Roper361d2ad2011-08-29 13:52:23 -07001007 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001008 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001009
1010 /* Restore original CRTC state */
1011 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001012 origcrtc->x, origcrtc->y,
1013 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001014 drmModeFreeCrtc(origcrtc);
1015
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001016 c->crtc_allocator &= ~(1 << output->crtc_id);
1017 c->connector_allocator &= ~(1 << output->connector_id);
1018
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001019 if (c->use_pixman) {
1020 drm_output_fini_pixman(output);
1021 } else {
1022 gl_renderer_output_destroy(output_base);
1023 gbm_surface_destroy(output->surface);
1024 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001025
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001026 weston_plane_release(&output->fb_plane);
1027 weston_plane_release(&output->cursor_plane);
1028
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001029 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001030 wl_list_remove(&output->base.link);
1031
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001032 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001033 free(output);
1034}
1035
Alex Wub7b8bda2012-04-17 17:20:48 +08001036static struct drm_mode *
1037choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1038{
1039 struct drm_mode *tmp_mode = NULL, *mode;
1040
1041 if (output->base.current->width == target_mode->width &&
1042 output->base.current->height == target_mode->height &&
1043 (output->base.current->refresh == target_mode->refresh ||
1044 target_mode->refresh == 0))
1045 return (struct drm_mode *)output->base.current;
1046
1047 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1048 if (mode->mode_info.hdisplay == target_mode->width &&
1049 mode->mode_info.vdisplay == target_mode->height) {
1050 if (mode->mode_info.vrefresh == target_mode->refresh ||
1051 target_mode->refresh == 0) {
1052 return mode;
1053 } else if (!tmp_mode)
1054 tmp_mode = mode;
1055 }
1056 }
1057
1058 return tmp_mode;
1059}
1060
1061static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001062drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001063static int
1064drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001065
1066static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001067drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1068{
1069 struct drm_output *output;
1070 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001071 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001072
1073 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001074 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001075 return -1;
1076 }
1077
1078 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001079 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001080 return -1;
1081 }
1082
1083 ec = (struct drm_compositor *)output_base->compositor;
1084 output = (struct drm_output *)output_base;
1085 drm_mode = choose_mode (output, mode);
1086
1087 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001088 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001089 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001090 }
1091
1092 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001093 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001094
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001095 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001096
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001097 output->base.current = &drm_mode->base;
1098 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001099 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1100
Alex Wub7b8bda2012-04-17 17:20:48 +08001101 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001102 drm_output_release_fb(output, output->current);
1103 drm_output_release_fb(output, output->next);
1104 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001105
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001106 if (ec->use_pixman) {
1107 drm_output_fini_pixman(output);
1108 if (drm_output_init_pixman(output, ec) < 0) {
1109 weston_log("failed to init output pixman state with "
1110 "new mode\n");
1111 return -1;
1112 }
1113 } else {
1114 gl_renderer_output_destroy(&output->base);
1115 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001116
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001117 if (drm_output_init_egl(output, ec) < 0) {
1118 weston_log("failed to init output egl state with "
1119 "new mode");
1120 return -1;
1121 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001122 }
1123
Alex Wub7b8bda2012-04-17 17:20:48 +08001124 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001125}
1126
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001127static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001128on_drm_input(int fd, uint32_t mask, void *data)
1129{
1130 drmEventContext evctx;
1131
1132 memset(&evctx, 0, sizeof evctx);
1133 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1134 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001135 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001136 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001137
1138 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001139}
1140
1141static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001142init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001143{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001144 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001145 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001146
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001147 sysnum = udev_device_get_sysnum(device);
1148 if (sysnum)
1149 ec->drm.id = atoi(sysnum);
1150 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001151 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001152 return -1;
1153 }
1154
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001155 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001156 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001157 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001158 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001159 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001160 udev_device_get_devnode(device));
1161 return -1;
1162 }
1163
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001164 weston_log("using %s\n", filename);
1165
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001166 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001167
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001168
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001169 return 0;
1170}
1171
1172static int
1173init_egl(struct drm_compositor *ec)
1174{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001175 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001176
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001177 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001178 NULL) < 0) {
1179 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001180 return -1;
1181 }
1182
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001183 return 0;
1184}
1185
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001186static int
1187init_pixman(struct drm_compositor *ec)
1188{
1189 return pixman_renderer_init(&ec->base);
1190}
1191
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001192static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001193drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1194{
1195 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001196 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001197
1198 mode = malloc(sizeof *mode);
1199 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001200 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001201
1202 mode->base.flags = 0;
1203 mode->base.width = info->hdisplay;
1204 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001205
1206 /* Calculate higher precision (mHz) refresh rate */
1207 refresh = (info->clock * 1000000LL / info->htotal +
1208 info->vtotal / 2) / info->vtotal;
1209
1210 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1211 refresh *= 2;
1212 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1213 refresh /= 2;
1214 if (info->vscan > 1)
1215 refresh /= info->vscan;
1216
1217 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001218 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001219
1220 if (info->type & DRM_MODE_TYPE_PREFERRED)
1221 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1222
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001223 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1224
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001225 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001226}
1227
1228static int
1229drm_subpixel_to_wayland(int drm_value)
1230{
1231 switch (drm_value) {
1232 default:
1233 case DRM_MODE_SUBPIXEL_UNKNOWN:
1234 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1235 case DRM_MODE_SUBPIXEL_NONE:
1236 return WL_OUTPUT_SUBPIXEL_NONE;
1237 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1238 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1239 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1240 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1241 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1242 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1243 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1244 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1245 }
1246}
1247
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001248/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001249static uint32_t
1250drm_get_backlight(struct drm_output *output)
1251{
1252 long brightness, max_brightness, norm;
1253
1254 brightness = backlight_get_brightness(output->backlight);
1255 max_brightness = backlight_get_max_brightness(output->backlight);
1256
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001257 /* convert it on a scale of 0 to 255 */
1258 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001259
1260 return (uint32_t) norm;
1261}
1262
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001263/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001264static void
1265drm_set_backlight(struct weston_output *output_base, uint32_t value)
1266{
1267 struct drm_output *output = (struct drm_output *) output_base;
1268 long max_brightness, new_brightness;
1269
1270 if (!output->backlight)
1271 return;
1272
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001273 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001274 return;
1275
1276 max_brightness = backlight_get_max_brightness(output->backlight);
1277
1278 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001279 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001280
1281 backlight_set_brightness(output->backlight, new_brightness);
1282}
1283
1284static drmModePropertyPtr
1285drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1286{
1287 drmModePropertyPtr props;
1288 int i;
1289
1290 for (i = 0; i < connector->count_props; i++) {
1291 props = drmModeGetProperty(fd, connector->props[i]);
1292 if (!props)
1293 continue;
1294
1295 if (!strcmp(props->name, name))
1296 return props;
1297
1298 drmModeFreeProperty(props);
1299 }
1300
1301 return NULL;
1302}
1303
1304static void
1305drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1306{
1307 struct drm_output *output = (struct drm_output *) output_base;
1308 struct weston_compositor *ec = output_base->compositor;
1309 struct drm_compositor *c = (struct drm_compositor *) ec;
1310 drmModeConnectorPtr connector;
1311 drmModePropertyPtr prop;
1312
1313 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1314 if (!connector)
1315 return;
1316
1317 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1318 if (!prop) {
1319 drmModeFreeConnector(connector);
1320 return;
1321 }
1322
1323 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1324 prop->prop_id, level);
1325 drmModeFreeProperty(prop);
1326 drmModeFreeConnector(connector);
1327}
1328
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001329static const char *connector_type_names[] = {
1330 "None",
1331 "VGA",
1332 "DVI",
1333 "DVI",
1334 "DVI",
1335 "Composite",
1336 "TV",
1337 "LVDS",
1338 "CTV",
1339 "DIN",
1340 "DP",
1341 "HDMI",
1342 "HDMI",
1343 "TV",
1344 "eDP",
1345};
1346
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001347static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001348find_crtc_for_connector(struct drm_compositor *ec,
1349 drmModeRes *resources, drmModeConnector *connector)
1350{
1351 drmModeEncoder *encoder;
1352 uint32_t possible_crtcs;
1353 int i, j;
1354
1355 for (j = 0; j < connector->count_encoders; j++) {
1356 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1357 if (encoder == NULL) {
1358 weston_log("Failed to get encoder.\n");
1359 return -1;
1360 }
1361 possible_crtcs = encoder->possible_crtcs;
1362 drmModeFreeEncoder(encoder);
1363
1364 for (i = 0; i < resources->count_crtcs; i++) {
1365 if (possible_crtcs & (1 << i) &&
1366 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1367 return i;
1368 }
1369 }
1370
1371 return -1;
1372}
1373
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001374/* Init output state that depends on gl or gbm */
1375static int
1376drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1377{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001378 int i, flags;
1379
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001380 output->surface = gbm_surface_create(ec->gbm,
1381 output->base.current->width,
1382 output->base.current->height,
1383 GBM_FORMAT_XRGB8888,
1384 GBM_BO_USE_SCANOUT |
1385 GBM_BO_USE_RENDERING);
1386 if (!output->surface) {
1387 weston_log("failed to create gbm surface\n");
1388 return -1;
1389 }
1390
1391 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001392 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001393 gbm_surface_destroy(output->surface);
1394 return -1;
1395 }
1396
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001397 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1398
1399 for (i = 0; i < 2; i++) {
1400 if (output->cursor_bo[i])
1401 continue;
1402
1403 output->cursor_bo[i] =
1404 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1405 flags);
1406 }
1407
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001408 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1409 weston_log("cursor buffers unavailable, using gl cursors\n");
1410 ec->cursors_are_broken = 1;
1411 }
1412
1413 return 0;
1414}
1415
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001416static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001417drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1418{
1419 int w = output->base.current->width;
1420 int h = output->base.current->height;
1421 unsigned int i;
1422
1423 /* FIXME error checking */
1424
1425 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1426 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1427 if (!output->dumb[i])
1428 goto err;
1429
1430 output->image[i] =
1431 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1432 output->dumb[i]->map,
1433 output->dumb[i]->stride);
1434 if (!output->image[i])
1435 goto err;
1436 }
1437
1438 if (pixman_renderer_output_create(&output->base) < 0)
1439 goto err;
1440
1441 pixman_region32_init_rect(&output->previous_damage,
1442 output->base.x, output->base.y, w, h);
1443
1444 return 0;
1445
1446err:
1447 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1448 if (output->dumb[i])
1449 drm_fb_destroy_dumb(output->dumb[i]);
1450 if (output->image[i])
1451 pixman_image_unref(output->image[i]);
1452
1453 output->dumb[i] = NULL;
1454 output->image[i] = NULL;
1455 }
1456
1457 return -1;
1458}
1459
1460static void
1461drm_output_fini_pixman(struct drm_output *output)
1462{
1463 unsigned int i;
1464
1465 pixman_renderer_output_destroy(&output->base);
1466 pixman_region32_fini(&output->previous_damage);
1467
1468 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1469 drm_fb_destroy_dumb(output->dumb[i]);
1470 pixman_image_unref(output->image[i]);
1471 output->dumb[i] = NULL;
1472 output->image[i] = NULL;
1473 }
1474}
1475
1476static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001477create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001478 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001479 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001480 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001481{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001482 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001483 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1484 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001485 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001486 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001487 drmModeModeInfo crtc_mode;
1488 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001489 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001490 char name[32];
1491 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001492
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001493 i = find_crtc_for_connector(ec, resources, connector);
1494 if (i < 0) {
1495 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001496 return -1;
1497 }
1498
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001499 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001500 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001501 return -1;
1502
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001503 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001504 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1505 output->base.make = "unknown";
1506 output->base.model = "unknown";
1507 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001508
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001509 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1510 type_name = connector_type_names[connector->connector_type];
1511 else
1512 type_name = "UNKNOWN";
1513 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1514 output->name = strdup(name);
1515
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001516 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001517 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001518 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001519 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001520 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001521
Matt Roper361d2ad2011-08-29 13:52:23 -07001522 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1523
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001524 /* Get the current mode on the crtc that's currently driving
1525 * this connector. */
1526 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001527 memset(&crtc_mode, 0, sizeof crtc_mode);
1528 if (encoder != NULL) {
1529 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1530 drmModeFreeEncoder(encoder);
1531 if (crtc == NULL)
1532 goto err_free;
1533 if (crtc->mode_valid)
1534 crtc_mode = crtc->mode;
1535 drmModeFreeCrtc(crtc);
1536 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001537
David Herrmann0f0d54e2011-12-08 17:05:45 +01001538 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001539 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1540 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001541 goto err_free;
1542 }
1543
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001544 preferred = NULL;
1545 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001546 configured = NULL;
1547
1548 wl_list_for_each(temp, &configured_output_list, link) {
1549 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001550 if (temp->mode)
1551 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001552 temp->name, temp->mode);
1553 o = temp;
1554 break;
1555 }
1556 }
1557
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001558 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001559 weston_log("Disabling output %s\n", o->name);
1560
1561 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1562 0, 0, 0, 0, 0, NULL);
1563 goto err_free;
1564 }
1565
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001566 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001567 if (o && o->config == OUTPUT_CONFIG_MODE &&
1568 o->width == drm_mode->base.width &&
1569 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001570 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001571 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001572 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001573 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001574 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001575 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001576
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001577 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001578 configured = drm_output_add_mode(output, &o->crtc_mode);
1579 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001580 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001581 current = configured;
1582 }
1583
Wang Quanxianacb805a2012-07-30 18:09:46 -04001584 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001585 current = drm_output_add_mode(output, &crtc_mode);
1586 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001587 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001588 }
1589
Scott Moreau8ab5d452012-07-30 19:51:08 -06001590 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1591 configured = current;
1592
Wang Quanxianacb805a2012-07-30 18:09:46 -04001593 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001594 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001595 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001596 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001597 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001598 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001599 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001600 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001601
1602 if (output->base.current == NULL) {
1603 weston_log("no available modes for %s\n", output->name);
1604 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001605 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001606
Wang Quanxianacb805a2012-07-30 18:09:46 -04001607 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1608
John Kåre Alsaker94659272012-11-13 19:10:18 +01001609 weston_output_init(&output->base, &ec->base, x, y,
1610 connector->mmWidth, connector->mmHeight,
1611 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1612
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001613 if (ec->use_pixman) {
1614 if (drm_output_init_pixman(output, ec) < 0) {
1615 weston_log("Failed to init output pixman state\n");
1616 goto err_output;
1617 }
1618 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001619 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001620 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001621 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001622
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001623 output->backlight = backlight_init(drm_device,
1624 connector->connector_type);
1625 if (output->backlight) {
1626 output->base.set_backlight = drm_set_backlight;
1627 output->base.backlight_current = drm_get_backlight(output);
1628 }
1629
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001630 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1631
Alex Wubd3354b2012-04-17 17:20:49 +08001632 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001633 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001634 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001635 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001636 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001637 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001638
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001639 weston_plane_init(&output->cursor_plane, 0, 0);
1640 weston_plane_init(&output->fb_plane, 0, 0);
1641
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001642 weston_log("Output %s, (connector %d, crtc %d)\n",
1643 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001644 wl_list_for_each(m, &output->base.mode_list, link)
1645 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1646 m->width, m->height, m->refresh / 1000.0,
1647 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1648 ", preferred" : "",
1649 m->flags & WL_OUTPUT_MODE_CURRENT ?
1650 ", current" : "",
1651 connector->count_modes == 0 ?
1652 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001653
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001654 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001655
John Kåre Alsaker94659272012-11-13 19:10:18 +01001656err_output:
1657 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001658err_free:
1659 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1660 base.link) {
1661 wl_list_remove(&drm_mode->base.link);
1662 free(drm_mode);
1663 }
1664
1665 drmModeFreeCrtc(output->original_crtc);
1666 ec->crtc_allocator &= ~(1 << output->crtc_id);
1667 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001668 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001669 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001670
David Herrmann0f0d54e2011-12-08 17:05:45 +01001671 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001672}
1673
Jesse Barnes58ef3792012-02-23 09:45:49 -05001674static void
1675create_sprites(struct drm_compositor *ec)
1676{
1677 struct drm_sprite *sprite;
1678 drmModePlaneRes *plane_res;
1679 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001680 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001681
1682 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1683 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001684 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001685 strerror(errno));
1686 return;
1687 }
1688
1689 for (i = 0; i < plane_res->count_planes; i++) {
1690 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1691 if (!plane)
1692 continue;
1693
1694 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1695 plane->count_formats));
1696 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001697 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001698 __func__);
1699 free(plane);
1700 continue;
1701 }
1702
1703 memset(sprite, 0, sizeof *sprite);
1704
1705 sprite->possible_crtcs = plane->possible_crtcs;
1706 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001707 sprite->current = NULL;
1708 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001709 sprite->compositor = ec;
1710 sprite->count_formats = plane->count_formats;
1711 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001712 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001713 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001714 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001715
1716 wl_list_insert(&ec->sprite_list, &sprite->link);
1717 }
1718
1719 free(plane_res->planes);
1720 free(plane_res);
1721}
1722
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001723static void
1724destroy_sprites(struct drm_compositor *compositor)
1725{
1726 struct drm_sprite *sprite, *next;
1727 struct drm_output *output;
1728
1729 output = container_of(compositor->base.output_list.next,
1730 struct drm_output, base.link);
1731
1732 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1733 drmModeSetPlane(compositor->drm.fd,
1734 sprite->plane_id,
1735 output->crtc_id, 0, 0,
1736 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001737 drm_output_release_fb(output, sprite->current);
1738 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001739 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001740 free(sprite);
1741 }
1742}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001743
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001744static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001745create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001746 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001747{
1748 drmModeConnector *connector;
1749 drmModeRes *resources;
1750 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001751 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001752
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001753 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001754 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001755 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001756 return -1;
1757 }
1758
Jesse Barnes58ef3792012-02-23 09:45:49 -05001759 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001760 if (!ec->crtcs) {
1761 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001762 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001763 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001764
Rob Clark4339add2012-08-09 14:18:28 -05001765 ec->min_width = resources->min_width;
1766 ec->max_width = resources->max_width;
1767 ec->min_height = resources->min_height;
1768 ec->max_height = resources->max_height;
1769
Jesse Barnes58ef3792012-02-23 09:45:49 -05001770 ec->num_crtcs = resources->count_crtcs;
1771 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1772
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001773 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001774 connector = drmModeGetConnector(ec->drm.fd,
1775 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001776 if (connector == NULL)
1777 continue;
1778
1779 if (connector->connection == DRM_MODE_CONNECTED &&
1780 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001781 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001782 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001783 connector, x, y,
1784 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001785 drmModeFreeConnector(connector);
1786 continue;
1787 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001788
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001789 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001790 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001791 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001792 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001793
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001794 drmModeFreeConnector(connector);
1795 }
1796
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001797 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001798 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001799 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001800 return -1;
1801 }
1802
1803 drmModeFreeResources(resources);
1804
1805 return 0;
1806}
1807
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001808static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001809update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001810{
1811 drmModeConnector *connector;
1812 drmModeRes *resources;
1813 struct drm_output *output, *next;
1814 int x = 0, y = 0;
1815 int x_offset = 0, y_offset = 0;
1816 uint32_t connected = 0, disconnects = 0;
1817 int i;
1818
1819 resources = drmModeGetResources(ec->drm.fd);
1820 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001821 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001822 return;
1823 }
1824
1825 /* collect new connects */
1826 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001827 int connector_id = resources->connectors[i];
1828
1829 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001830 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001831 continue;
1832
David Herrmann7551cff2011-12-08 17:05:43 +01001833 if (connector->connection != DRM_MODE_CONNECTED) {
1834 drmModeFreeConnector(connector);
1835 continue;
1836 }
1837
Benjamin Franzke117483d2011-08-30 11:38:26 +02001838 connected |= (1 << connector_id);
1839
1840 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001841 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001842 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001843 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001844
1845 /* XXX: not yet needed, we die with 0 outputs */
1846 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001847 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001848 else
1849 x = 0;
1850 y = 0;
1851 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001852 connector, x, y,
1853 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001854 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001855
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001856 }
1857 drmModeFreeConnector(connector);
1858 }
1859 drmModeFreeResources(resources);
1860
1861 disconnects = ec->connector_allocator & ~connected;
1862 if (disconnects) {
1863 wl_list_for_each_safe(output, next, &ec->base.output_list,
1864 base.link) {
1865 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001866 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001867 output->base.x - x_offset,
1868 output->base.y - y_offset);
1869 }
1870
1871 if (disconnects & (1 << output->connector_id)) {
1872 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001873 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001874 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001875 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001876 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001877 }
1878 }
1879 }
1880
1881 /* FIXME: handle zero outputs, without terminating */
1882 if (ec->connector_allocator == 0)
1883 wl_display_terminate(ec->base.wl_display);
1884}
1885
1886static int
David Herrmannd7488c22012-03-11 20:05:21 +01001887udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001888{
David Herrmannd7488c22012-03-11 20:05:21 +01001889 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001890 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001891
1892 sysnum = udev_device_get_sysnum(device);
1893 if (!sysnum || atoi(sysnum) != ec->drm.id)
1894 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001895
David Herrmann6ac52db2012-03-11 20:05:22 +01001896 val = udev_device_get_property_value(device, "HOTPLUG");
1897 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001898 return 0;
1899
David Herrmann6ac52db2012-03-11 20:05:22 +01001900 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001901}
1902
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001903static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001904udev_drm_event(int fd, uint32_t mask, void *data)
1905{
1906 struct drm_compositor *ec = data;
1907 struct udev_device *event;
1908
1909 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001910
David Herrmannd7488c22012-03-11 20:05:21 +01001911 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001912 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001913
1914 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001915
1916 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001917}
1918
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001919static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001920drm_restore(struct weston_compositor *ec)
1921{
1922 struct drm_compositor *d = (struct drm_compositor *) ec;
1923
1924 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1925 weston_log("failed to drop master: %m\n");
1926 tty_reset(d->tty);
1927}
1928
1929static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001930drm_free_configured_output(struct drm_configured_output *output)
1931{
1932 free(output->name);
1933 free(output->mode);
1934 free(output);
1935}
1936
1937static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001938drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001939{
1940 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05001941 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001942 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001943
Kristian Høgsberge8091032013-02-18 15:43:29 -05001944 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
1945 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001946 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001947 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001948
1949 wl_event_source_remove(d->udev_drm_source);
1950 wl_event_source_remove(d->drm_source);
1951
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001952 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001953
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03001954 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001955
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001956 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001957
1958 if (d->gbm)
1959 gbm_device_destroy(d->gbm);
1960
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001961 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001962 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001963 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001964
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001965 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001966}
1967
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001968static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001969drm_compositor_set_modes(struct drm_compositor *compositor)
1970{
1971 struct drm_output *output;
1972 struct drm_mode *drm_mode;
1973 int ret;
1974
1975 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02001976 if (!output->current) {
1977 /* If something that would cause the output to
1978 * switch mode happened while in another vt, we
1979 * might not have a current drm_fb. In that case,
1980 * schedule a repaint and let drm_output_repaint
1981 * handle setting the mode. */
1982 weston_output_schedule_repaint(&output->base);
1983 continue;
1984 }
1985
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001986 drm_mode = (struct drm_mode *) output->base.current;
1987 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001988 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001989 &output->connector_id, 1,
1990 &drm_mode->mode_info);
1991 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001992 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001993 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001994 drm_mode->base.width, drm_mode->base.height,
1995 output->base.x, output->base.y);
1996 }
1997 }
1998}
1999
2000static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002001vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002002{
2003 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002004 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002005 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002006 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002007
2008 switch (event) {
2009 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002010 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002011 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002012 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002013 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002014 wl_display_terminate(compositor->wl_display);
2015 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002016 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002017 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002018 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002019 wl_list_for_each(seat, &compositor->seat_list, base.link)
2020 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002021 break;
2022 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002023 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002024 wl_list_for_each(seat, &compositor->seat_list, base.link)
2025 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002026
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002027 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002028 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002029 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002030
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002031 /* If we have a repaint scheduled (either from a
2032 * pending pageflip or the idle handler), make sure we
2033 * cancel that so we don't try to pageflip when we're
2034 * vt switched away. The SLEEPING state will prevent
2035 * further attemps at repainting. When we switch
2036 * back, we schedule a repaint, which will process
2037 * pending frame callbacks. */
2038
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002039 wl_list_for_each(output, &ec->base.output_list, base.link) {
2040 output->base.repaint_needed = 0;
2041 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002042 }
2043
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002044 output = container_of(ec->base.output_list.next,
2045 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002046
2047 wl_list_for_each(sprite, &ec->sprite_list, link)
2048 drmModeSetPlane(ec->drm.fd,
2049 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002050 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002051 0, 0, 0, 0, 0, 0, 0, 0);
2052
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002053 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002054 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002055
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002056 break;
2057 };
2058}
2059
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002060static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002061switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002062{
2063 struct drm_compositor *ec = data;
2064
Daniel Stone325fc2d2012-05-30 16:31:58 +01002065 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002066}
2067
David Herrmann0af066f2012-10-29 19:21:16 +01002068/*
2069 * Find primary GPU
2070 * Some systems may have multiple DRM devices attached to a single seat. This
2071 * function loops over all devices and tries to find a PCI device with the
2072 * boot_vga sysfs attribute set to 1.
2073 * If no such device is found, the first DRM device reported by udev is used.
2074 */
2075static struct udev_device*
2076find_primary_gpu(struct drm_compositor *ec, const char *seat)
2077{
2078 struct udev_enumerate *e;
2079 struct udev_list_entry *entry;
2080 const char *path, *device_seat, *id;
2081 struct udev_device *device, *drm_device, *pci;
2082
2083 e = udev_enumerate_new(ec->udev);
2084 udev_enumerate_add_match_subsystem(e, "drm");
2085 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2086
2087 udev_enumerate_scan_devices(e);
2088 drm_device = NULL;
2089 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2090 path = udev_list_entry_get_name(entry);
2091 device = udev_device_new_from_syspath(ec->udev, path);
2092 if (!device)
2093 continue;
2094 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2095 if (!device_seat)
2096 device_seat = default_seat;
2097 if (strcmp(device_seat, seat)) {
2098 udev_device_unref(device);
2099 continue;
2100 }
2101
2102 pci = udev_device_get_parent_with_subsystem_devtype(device,
2103 "pci", NULL);
2104 if (pci) {
2105 id = udev_device_get_sysattr_value(pci, "boot_vga");
2106 if (id && !strcmp(id, "1")) {
2107 if (drm_device)
2108 udev_device_unref(drm_device);
2109 drm_device = device;
2110 break;
2111 }
2112 }
2113
2114 if (!drm_device)
2115 drm_device = device;
2116 else
2117 udev_device_unref(device);
2118 }
2119
2120 udev_enumerate_unref(e);
2121 return drm_device;
2122}
2123
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002124static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002125planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002126{
2127 struct drm_compositor *c = data;
2128
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002129 switch (key) {
2130 case KEY_C:
2131 c->cursors_are_broken ^= 1;
2132 break;
2133 case KEY_V:
2134 c->sprites_are_broken ^= 1;
2135 break;
2136 case KEY_O:
2137 c->sprites_hidden ^= 1;
2138 break;
2139 default:
2140 break;
2141 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002142}
2143
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002144static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002145drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002146 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002147 int *argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002148{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002149 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002150 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002151 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002152 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002153 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002154 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002155
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002156 weston_log("initializing drm backend\n");
2157
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002158 ec = malloc(sizeof *ec);
2159 if (ec == NULL)
2160 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002161 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002162
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002163 /* KMS support for sprites is not complete yet, so disable the
2164 * functionality for now. */
2165 ec->sprites_are_broken = 1;
2166
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002167 ec->use_pixman = pixman;
2168
Daniel Stone725c2c32012-06-22 14:04:36 +01002169 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002170 config_file) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002171 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002172 goto err_base;
2173 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002174
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002175 ec->udev = udev_new();
2176 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002177 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002178 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002179 }
2180
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002181 ec->base.wl_display = display;
2182 ec->tty = tty_create(&ec->base, vt_func, tty);
2183 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002184 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002185 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002186 }
2187
David Herrmann0af066f2012-10-29 19:21:16 +01002188 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002189 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002190 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002191 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002192 }
David Herrmann0af066f2012-10-29 19:21:16 +01002193 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002194
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002195 if (init_drm(ec, drm_device) < 0) {
2196 weston_log("failed to initialize kms\n");
2197 goto err_udev_dev;
2198 }
2199
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002200 if (ec->use_pixman) {
2201 if (init_pixman(ec) < 0) {
2202 weston_log("failed to initialize pixman renderer\n");
2203 goto err_udev_dev;
2204 }
2205 } else {
2206 if (init_egl(ec) < 0) {
2207 weston_log("failed to initialize egl\n");
2208 goto err_udev_dev;
2209 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002210 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002211
2212 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002213 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002214
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002215 ec->base.focus = 1;
2216
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002217 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002218
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002219 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002220 weston_compositor_add_key_binding(&ec->base, key,
2221 MODIFIER_CTRL | MODIFIER_ALT,
2222 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002223
Jesse Barnes58ef3792012-02-23 09:45:49 -05002224 wl_list_init(&ec->sprite_list);
2225 create_sprites(ec);
2226
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002227 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002228 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002229 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002230 }
2231
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002232 path = NULL;
2233
Kristian Høgsberge8091032013-02-18 15:43:29 -05002234 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002235 weston_log("failed to create input devices\n");
2236 goto err_sprite;
2237 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002238
2239 loop = wl_display_get_event_loop(ec->base.wl_display);
2240 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002241 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002242 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002243
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002244 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2245 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002246 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002247 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002248 }
2249 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2250 "drm", NULL);
2251 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002252 wl_event_loop_add_fd(loop,
2253 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002254 WL_EVENT_READABLE, udev_drm_event, ec);
2255
2256 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002257 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002258 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002259 }
2260
Daniel Stonea96b93c2012-06-22 14:04:37 +01002261 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002262
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002263 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002264 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002265 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002266 planes_binding, ec);
2267 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2268 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002269
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002270 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002271
2272err_udev_monitor:
2273 wl_event_source_remove(ec->udev_drm_source);
2274 udev_monitor_unref(ec->udev_monitor);
2275err_drm_source:
2276 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002277 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2278 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002279err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002280 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002281 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002282 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002283err_udev_dev:
2284 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002285err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002286 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2287 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002288 tty_destroy(ec->tty);
2289err_udev:
2290 udev_unref(ec->udev);
2291err_compositor:
2292 weston_compositor_shutdown(&ec->base);
2293err_base:
2294 free(ec);
2295 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002296}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002297
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002298static int
2299set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2300{
2301 mode->flags = 0;
2302
2303 if (strcmp(hsync, "+hsync") == 0)
2304 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2305 else if (strcmp(hsync, "-hsync") == 0)
2306 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2307 else
2308 return -1;
2309
2310 if (strcmp(vsync, "+vsync") == 0)
2311 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2312 else if (strcmp(vsync, "-vsync") == 0)
2313 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2314 else
2315 return -1;
2316
2317 return 0;
2318}
2319
2320static int
2321check_for_modeline(struct drm_configured_output *output)
2322{
2323 drmModeModeInfo mode;
2324 char hsync[16];
2325 char vsync[16];
2326 char mode_name[16];
2327 float fclock;
2328
2329 mode.type = DRM_MODE_TYPE_USERDEF;
2330 mode.hskew = 0;
2331 mode.vscan = 0;
2332 mode.vrefresh = 0;
2333
2334 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2335 &fclock, &mode.hdisplay,
2336 &mode.hsync_start,
2337 &mode.hsync_end, &mode.htotal,
2338 &mode.vdisplay,
2339 &mode.vsync_start,
2340 &mode.vsync_end, &mode.vtotal,
2341 hsync, vsync) == 11) {
2342 if (set_sync_flags(&mode, hsync, vsync))
2343 return -1;
2344
2345 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2346 strcpy(mode.name, mode_name);
2347
2348 mode.clock = fclock * 1000;
2349 } else
2350 return -1;
2351
2352 output->crtc_mode = mode;
2353
2354 return 0;
2355}
2356
Scott Moreau8ab5d452012-07-30 19:51:08 -06002357static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002358drm_output_set_transform(struct drm_configured_output *output)
2359{
2360 if (!output_transform) {
2361 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2362 return;
2363 }
2364
2365 if (!strcmp(output_transform, "normal"))
2366 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2367 else if (!strcmp(output_transform, "90"))
2368 output->transform = WL_OUTPUT_TRANSFORM_90;
2369 else if (!strcmp(output_transform, "180"))
2370 output->transform = WL_OUTPUT_TRANSFORM_180;
2371 else if (!strcmp(output_transform, "270"))
2372 output->transform = WL_OUTPUT_TRANSFORM_270;
2373 else if (!strcmp(output_transform, "flipped"))
2374 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2375 else if (!strcmp(output_transform, "flipped-90"))
2376 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2377 else if (!strcmp(output_transform, "flipped-180"))
2378 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2379 else if (!strcmp(output_transform, "flipped-270"))
2380 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2381 else {
2382 weston_log("Invalid transform \"%s\" for output %s\n",
2383 output_transform, output_name);
2384 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2385 }
2386
2387 free(output_transform);
2388 output_transform = NULL;
2389}
2390
2391static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002392output_section_done(void *data)
2393{
2394 struct drm_configured_output *output;
2395
2396 output = malloc(sizeof *output);
2397
Scott Moreau1bad5db2012-08-18 01:04:05 -06002398 if (!output || !output_name || (output_name[0] == 'X') ||
2399 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002400 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002401 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002402 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002403 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002404 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002405 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002406 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002407 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002408 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002409
2410 output->config = OUTPUT_CONFIG_INVALID;
2411 output->name = output_name;
2412 output->mode = output_mode;
2413
Scott Moreau1bad5db2012-08-18 01:04:05 -06002414 if (output_mode) {
2415 if (strcmp(output_mode, "off") == 0)
2416 output->config = OUTPUT_CONFIG_OFF;
2417 else if (strcmp(output_mode, "preferred") == 0)
2418 output->config = OUTPUT_CONFIG_PREFERRED;
2419 else if (strcmp(output_mode, "current") == 0)
2420 output->config = OUTPUT_CONFIG_CURRENT;
2421 else if (sscanf(output_mode, "%dx%d",
2422 &output->width, &output->height) == 2)
2423 output->config = OUTPUT_CONFIG_MODE;
2424 else if (check_for_modeline(output) == 0)
2425 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002426
Scott Moreau1bad5db2012-08-18 01:04:05 -06002427 if (output->config == OUTPUT_CONFIG_INVALID)
2428 weston_log("Invalid mode \"%s\" for output %s\n",
2429 output_mode, output_name);
2430 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002431 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002432
2433 drm_output_set_transform(output);
2434
2435 wl_list_insert(&configured_output_list, &output->link);
2436
2437 if (output_transform)
2438 free(output_transform);
2439 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002440}
2441
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002442WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002443backend_init(struct wl_display *display, int *argc, char *argv[],
Daniel Stonec1be8e52012-06-01 11:14:02 -04002444 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002445{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002446 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002447 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002448
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002449 const struct weston_option drm_options[] = {
2450 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2451 { WESTON_OPTION_STRING, "seat", 0, &seat },
2452 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002453 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002454 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002455 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002456
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002457 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002458
Scott Moreau8ab5d452012-07-30 19:51:08 -06002459 wl_list_init(&configured_output_list);
2460
2461 const struct config_key drm_config_keys[] = {
2462 { "name", CONFIG_KEY_STRING, &output_name },
2463 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002464 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002465 };
2466
2467 const struct config_section config_section[] = {
2468 { "output", drm_config_keys,
2469 ARRAY_LENGTH(drm_config_keys), output_section_done },
2470 };
2471
2472 parse_config_file(config_file, config_section,
2473 ARRAY_LENGTH(config_section), NULL);
2474
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002475 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2476 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002477}