blob: da1ba79e849dc3b72118363a27a6e6ae851f1e0a [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
Jonas Ådahle5a12252013-04-05 23:07:11 +0200626drm_output_start_repaint_loop(struct weston_output *output_base)
627{
628 struct drm_output *output = (struct drm_output *) output_base;
629 struct drm_compositor *compositor = (struct drm_compositor *)
630 output_base->compositor;
631 uint32_t fb_id;
632
633 if (output->current)
634 fb_id = output->current->fb_id;
635 else
636 fb_id = output->original_crtc->buffer_id;
637
638 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
639 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
640 weston_log("queueing pageflip failed: %m\n");
641 return;
642 }
643}
644
645static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500646vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
647 void *data)
648{
649 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300650 struct drm_output *output = s->output;
651 uint32_t msecs;
652
653 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200655 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200656 s->current = s->next;
657 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300658
659 if (!output->page_flip_pending) {
660 msecs = sec * 1000 + usec / 1000;
661 weston_output_finish_frame(&output->base, msecs);
662 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500663}
664
665static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400666page_flip_handler(int fd, unsigned int frame,
667 unsigned int sec, unsigned int usec, void *data)
668{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200669 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400670 uint32_t msecs;
671
Jonas Ådahle5a12252013-04-05 23:07:11 +0200672 /* We don't set page_flip_pending on start_repaint_loop, in that case
673 * we just want to page flip to the current buffer to get an accurate
674 * timestamp */
675 if (output->page_flip_pending) {
676 drm_output_release_fb(output, output->current);
677 output->current = output->next;
678 output->next = NULL;
679 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300680
Jonas Ådahle5a12252013-04-05 23:07:11 +0200681 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400682
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300683 if (!output->vblank_pending) {
684 msecs = sec * 1000 + usec / 1000;
685 weston_output_finish_frame(&output->base, msecs);
686 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200687}
688
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500689static uint32_t
690drm_output_check_sprite_format(struct drm_sprite *s,
691 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500692{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500693 uint32_t i, format;
694
695 format = gbm_bo_get_format(bo);
696
697 if (format == GBM_FORMAT_ARGB8888) {
698 pixman_region32_t r;
699
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500700 pixman_region32_init_rect(&r, 0, 0,
701 es->geometry.width,
702 es->geometry.height);
703 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500704
705 if (!pixman_region32_not_empty(&r))
706 format = GBM_FORMAT_XRGB8888;
707
708 pixman_region32_fini(&r);
709 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500710
711 for (i = 0; i < s->count_formats; i++)
712 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500713 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500714
715 return 0;
716}
717
718static int
719drm_surface_transform_supported(struct weston_surface *es)
720{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500721 return !es->transform.enabled ||
722 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500723}
724
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400725static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500726drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400727 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500728{
729 struct weston_compositor *ec = output_base->compositor;
730 struct drm_compositor *c =(struct drm_compositor *) ec;
731 struct drm_sprite *s;
732 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500733 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500734 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200735 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500736 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400737 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500738
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200739 if (c->gbm == NULL)
740 return NULL;
741
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200742 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200743 return NULL;
744
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500745 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400746 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500747
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300748 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400749 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300750
Pekka Paalanende685b82012-12-04 15:58:12 +0200751 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400752 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500753
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200754 if (es->alpha != 1.0f)
755 return NULL;
756
Pekka Paalanende685b82012-12-04 15:58:12 +0200757 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500758 return NULL;
759
Jesse Barnes58ef3792012-02-23 09:45:49 -0500760 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400761 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500762
Jesse Barnes58ef3792012-02-23 09:45:49 -0500763 wl_list_for_each(s, &c->sprite_list, link) {
764 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
765 continue;
766
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200767 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768 found = 1;
769 break;
770 }
771 }
772
773 /* No sprites available */
774 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400775 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500776
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400777 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200778 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400779 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400780 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400781
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500782 format = drm_output_check_sprite_format(s, es, bo);
783 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200784 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400785 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500786 }
787
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200788 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200789 if (!s->next) {
790 gbm_bo_destroy(bo);
791 return NULL;
792 }
793
Pekka Paalanende685b82012-12-04 15:58:12 +0200794 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500795
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400796 box = pixman_region32_extents(&es->transform.boundingbox);
797 s->plane.x = box->x1;
798 s->plane.y = box->y1;
799
Jesse Barnes58ef3792012-02-23 09:45:49 -0500800 /*
801 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200802 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500803 * for us already).
804 */
805 pixman_region32_init(&dest_rect);
806 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
807 &output_base->region);
808 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
809 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200810 tbox = weston_transformed_rect(output_base->width,
811 output_base->height,
812 output_base->transform, *box);
813 s->dest_x = tbox.x1;
814 s->dest_y = tbox.y1;
815 s->dest_w = tbox.x2 - tbox.x1;
816 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817 pixman_region32_fini(&dest_rect);
818
819 pixman_region32_init(&src_rect);
820 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
821 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500822 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400823
824 weston_surface_from_global_fixed(es,
825 wl_fixed_from_int(box->x1),
826 wl_fixed_from_int(box->y1),
827 &sx1, &sy1);
828 weston_surface_from_global_fixed(es,
829 wl_fixed_from_int(box->x2),
830 wl_fixed_from_int(box->y2),
831 &sx2, &sy2);
832
833 if (sx1 < 0)
834 sx1 = 0;
835 if (sy1 < 0)
836 sy1 = 0;
837 if (sx2 > wl_fixed_from_int(es->geometry.width))
838 sx2 = wl_fixed_from_int(es->geometry.width);
839 if (sy2 > wl_fixed_from_int(es->geometry.height))
840 sy2 = wl_fixed_from_int(es->geometry.height);
841
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200842 tbox.x1 = sx1;
843 tbox.y1 = sy1;
844 tbox.x2 = sx2;
845 tbox.y2 = sy2;
846
847 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
848 wl_fixed_from_int(es->geometry.height),
849 es->buffer_transform, tbox);
850
851 s->src_x = tbox.x1 << 8;
852 s->src_y = tbox.y1 << 8;
853 s->src_w = (tbox.x2 - tbox.x1) << 8;
854 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500855 pixman_region32_fini(&src_rect);
856
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400857 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500858}
859
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400860static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400861drm_output_prepare_cursor_surface(struct weston_output *output_base,
862 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500863{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400864 struct drm_compositor *c =
865 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400866 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400867
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200868 if (c->gbm == NULL)
869 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200870 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
871 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400872 if (output->cursor_surface)
873 return NULL;
874 if (es->output_mask != (1u << output_base->id))
875 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500876 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400877 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200878 if (es->buffer_ref.buffer == NULL ||
879 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400880 es->geometry.width > 64 || es->geometry.height > 64)
881 return NULL;
882
883 output->cursor_surface = es;
884
885 return &output->cursor_plane;
886}
887
888static void
889drm_output_set_cursor(struct drm_output *output)
890{
891 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400892 struct drm_compositor *c =
893 (struct drm_compositor *) output->base.compositor;
894 EGLint handle, stride;
895 struct gbm_bo *bo;
896 uint32_t buf[64 * 64];
897 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400898 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500899
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400900 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400901 if (es == NULL) {
902 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
903 return;
904 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500905
Pekka Paalanende685b82012-12-04 15:58:12 +0200906 if (es->buffer_ref.buffer &&
907 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400908 pixman_region32_fini(&output->cursor_plane.damage);
909 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400910 output->current_cursor ^= 1;
911 bo = output->cursor_bo[output->current_cursor];
912 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200913 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
914 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400915 for (i = 0; i < es->geometry.height; i++)
916 memcpy(buf + i * 64, s + i * stride,
917 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500918
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400919 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300920 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400921
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400922 handle = gbm_bo_get_handle(bo).s32;
923 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500924 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300925 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500926 c->cursors_are_broken = 1;
927 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400928 }
929
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400930 x = es->geometry.x - output->base.x;
931 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400932 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500933 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400934 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500935 c->cursors_are_broken = 1;
936 }
937
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400938 output->cursor_plane.x = x;
939 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400940 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500941}
942
Jesse Barnes58ef3792012-02-23 09:45:49 -0500943static void
944drm_assign_planes(struct weston_output *output)
945{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400946 struct drm_compositor *c =
947 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400948 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500949 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400950 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500951
952 /*
953 * Find a surface for each sprite in the output using some heuristics:
954 * 1) size
955 * 2) frequency of update
956 * 3) opacity (though some hw might support alpha blending)
957 * 4) clipping (this can be fixed with color keys)
958 *
959 * The idea is to save on blitting since this should save power.
960 * If we can get a large video surface on the sprite for example,
961 * the main display surface may not need to update at all, and
962 * the client buffer can be used directly for the sprite surface
963 * as we do for flipping full screen surfaces.
964 */
965 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400966 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400967 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200968 /* test whether this buffer can ever go into a plane:
969 * non-shm, or small enough to be a cursor
970 */
971 if ((es->buffer_ref.buffer &&
972 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
973 (es->geometry.width <= 64 && es->geometry.height <= 64))
974 es->keep_buffer = 1;
975 else
976 es->keep_buffer = 0;
977
Jesse Barnes58ef3792012-02-23 09:45:49 -0500978 pixman_region32_init(&surface_overlap);
979 pixman_region32_intersect(&surface_overlap, &overlap,
980 &es->transform.boundingbox);
981
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400982 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400983 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400984 next_plane = primary;
985 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400986 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400987 if (next_plane == NULL)
988 next_plane = drm_output_prepare_scanout_surface(output, es);
989 if (next_plane == NULL)
990 next_plane = drm_output_prepare_overlay_surface(output, es);
991 if (next_plane == NULL)
992 next_plane = primary;
993 weston_surface_move_to_plane(es, next_plane);
994 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500995 pixman_region32_union(&overlap, &overlap,
996 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400997
Jesse Barnes58ef3792012-02-23 09:45:49 -0500998 pixman_region32_fini(&surface_overlap);
999 }
1000 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001001}
1002
Matt Roper361d2ad2011-08-29 13:52:23 -07001003static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001004drm_output_fini_pixman(struct drm_output *output);
1005
1006static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001007drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001008{
1009 struct drm_output *output = (struct drm_output *) output_base;
1010 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001011 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001012 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001013
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001014 if (output->backlight)
1015 backlight_destroy(output->backlight);
1016
Matt Roper361d2ad2011-08-29 13:52:23 -07001017 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001018 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001019
1020 /* Restore original CRTC state */
1021 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001022 origcrtc->x, origcrtc->y,
1023 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001024 drmModeFreeCrtc(origcrtc);
1025
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001026 c->crtc_allocator &= ~(1 << output->crtc_id);
1027 c->connector_allocator &= ~(1 << output->connector_id);
1028
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001029 if (c->use_pixman) {
1030 drm_output_fini_pixman(output);
1031 } else {
1032 gl_renderer_output_destroy(output_base);
1033 gbm_surface_destroy(output->surface);
1034 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001035
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001036 weston_plane_release(&output->fb_plane);
1037 weston_plane_release(&output->cursor_plane);
1038
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001039 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001040 wl_list_remove(&output->base.link);
1041
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001042 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001043 free(output);
1044}
1045
Alex Wub7b8bda2012-04-17 17:20:48 +08001046static struct drm_mode *
1047choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1048{
1049 struct drm_mode *tmp_mode = NULL, *mode;
1050
1051 if (output->base.current->width == target_mode->width &&
1052 output->base.current->height == target_mode->height &&
1053 (output->base.current->refresh == target_mode->refresh ||
1054 target_mode->refresh == 0))
1055 return (struct drm_mode *)output->base.current;
1056
1057 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1058 if (mode->mode_info.hdisplay == target_mode->width &&
1059 mode->mode_info.vdisplay == target_mode->height) {
1060 if (mode->mode_info.vrefresh == target_mode->refresh ||
1061 target_mode->refresh == 0) {
1062 return mode;
1063 } else if (!tmp_mode)
1064 tmp_mode = mode;
1065 }
1066 }
1067
1068 return tmp_mode;
1069}
1070
1071static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001072drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001073static int
1074drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001075
1076static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001077drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1078{
1079 struct drm_output *output;
1080 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001081 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001082
1083 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001084 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001085 return -1;
1086 }
1087
1088 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001089 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001090 return -1;
1091 }
1092
1093 ec = (struct drm_compositor *)output_base->compositor;
1094 output = (struct drm_output *)output_base;
1095 drm_mode = choose_mode (output, mode);
1096
1097 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001098 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001099 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001100 }
1101
1102 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001103 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001104
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001105 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001106
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001107 output->base.current = &drm_mode->base;
1108 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001109 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1110
Alex Wub7b8bda2012-04-17 17:20:48 +08001111 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001112 drm_output_release_fb(output, output->current);
1113 drm_output_release_fb(output, output->next);
1114 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001115
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001116 if (ec->use_pixman) {
1117 drm_output_fini_pixman(output);
1118 if (drm_output_init_pixman(output, ec) < 0) {
1119 weston_log("failed to init output pixman state with "
1120 "new mode\n");
1121 return -1;
1122 }
1123 } else {
1124 gl_renderer_output_destroy(&output->base);
1125 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001126
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001127 if (drm_output_init_egl(output, ec) < 0) {
1128 weston_log("failed to init output egl state with "
1129 "new mode");
1130 return -1;
1131 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001132 }
1133
Alex Wub7b8bda2012-04-17 17:20:48 +08001134 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001135}
1136
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001137static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001138on_drm_input(int fd, uint32_t mask, void *data)
1139{
1140 drmEventContext evctx;
1141
1142 memset(&evctx, 0, sizeof evctx);
1143 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1144 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001145 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001146 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001147
1148 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001149}
1150
1151static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001152init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001153{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001154 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001155 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001156
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001157 sysnum = udev_device_get_sysnum(device);
1158 if (sysnum)
1159 ec->drm.id = atoi(sysnum);
1160 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001161 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001162 return -1;
1163 }
1164
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001165 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001166 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001167 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001168 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001169 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001170 udev_device_get_devnode(device));
1171 return -1;
1172 }
1173
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001174 weston_log("using %s\n", filename);
1175
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001176 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001177
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001178
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001179 return 0;
1180}
1181
1182static int
1183init_egl(struct drm_compositor *ec)
1184{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001185 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001186
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001187 if (!ec->gbm)
1188 return -1;
1189
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001190 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001191 NULL) < 0) {
1192 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001193 return -1;
1194 }
1195
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001196 return 0;
1197}
1198
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001199static int
1200init_pixman(struct drm_compositor *ec)
1201{
1202 return pixman_renderer_init(&ec->base);
1203}
1204
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001205static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001206drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1207{
1208 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001209 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001210
1211 mode = malloc(sizeof *mode);
1212 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001213 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001214
1215 mode->base.flags = 0;
1216 mode->base.width = info->hdisplay;
1217 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001218
1219 /* Calculate higher precision (mHz) refresh rate */
1220 refresh = (info->clock * 1000000LL / info->htotal +
1221 info->vtotal / 2) / info->vtotal;
1222
1223 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1224 refresh *= 2;
1225 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1226 refresh /= 2;
1227 if (info->vscan > 1)
1228 refresh /= info->vscan;
1229
1230 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001231 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001232
1233 if (info->type & DRM_MODE_TYPE_PREFERRED)
1234 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1235
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001236 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1237
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001238 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001239}
1240
1241static int
1242drm_subpixel_to_wayland(int drm_value)
1243{
1244 switch (drm_value) {
1245 default:
1246 case DRM_MODE_SUBPIXEL_UNKNOWN:
1247 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1248 case DRM_MODE_SUBPIXEL_NONE:
1249 return WL_OUTPUT_SUBPIXEL_NONE;
1250 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1251 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1252 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1253 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1254 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1255 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1256 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1257 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1258 }
1259}
1260
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001261/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001262static uint32_t
1263drm_get_backlight(struct drm_output *output)
1264{
1265 long brightness, max_brightness, norm;
1266
1267 brightness = backlight_get_brightness(output->backlight);
1268 max_brightness = backlight_get_max_brightness(output->backlight);
1269
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001270 /* convert it on a scale of 0 to 255 */
1271 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001272
1273 return (uint32_t) norm;
1274}
1275
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001276/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001277static void
1278drm_set_backlight(struct weston_output *output_base, uint32_t value)
1279{
1280 struct drm_output *output = (struct drm_output *) output_base;
1281 long max_brightness, new_brightness;
1282
1283 if (!output->backlight)
1284 return;
1285
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001286 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001287 return;
1288
1289 max_brightness = backlight_get_max_brightness(output->backlight);
1290
1291 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001292 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001293
1294 backlight_set_brightness(output->backlight, new_brightness);
1295}
1296
1297static drmModePropertyPtr
1298drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1299{
1300 drmModePropertyPtr props;
1301 int i;
1302
1303 for (i = 0; i < connector->count_props; i++) {
1304 props = drmModeGetProperty(fd, connector->props[i]);
1305 if (!props)
1306 continue;
1307
1308 if (!strcmp(props->name, name))
1309 return props;
1310
1311 drmModeFreeProperty(props);
1312 }
1313
1314 return NULL;
1315}
1316
1317static void
1318drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1319{
1320 struct drm_output *output = (struct drm_output *) output_base;
1321 struct weston_compositor *ec = output_base->compositor;
1322 struct drm_compositor *c = (struct drm_compositor *) ec;
1323 drmModeConnectorPtr connector;
1324 drmModePropertyPtr prop;
1325
1326 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1327 if (!connector)
1328 return;
1329
1330 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1331 if (!prop) {
1332 drmModeFreeConnector(connector);
1333 return;
1334 }
1335
1336 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1337 prop->prop_id, level);
1338 drmModeFreeProperty(prop);
1339 drmModeFreeConnector(connector);
1340}
1341
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001342static const char *connector_type_names[] = {
1343 "None",
1344 "VGA",
1345 "DVI",
1346 "DVI",
1347 "DVI",
1348 "Composite",
1349 "TV",
1350 "LVDS",
1351 "CTV",
1352 "DIN",
1353 "DP",
1354 "HDMI",
1355 "HDMI",
1356 "TV",
1357 "eDP",
1358};
1359
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001360static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001361find_crtc_for_connector(struct drm_compositor *ec,
1362 drmModeRes *resources, drmModeConnector *connector)
1363{
1364 drmModeEncoder *encoder;
1365 uint32_t possible_crtcs;
1366 int i, j;
1367
1368 for (j = 0; j < connector->count_encoders; j++) {
1369 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1370 if (encoder == NULL) {
1371 weston_log("Failed to get encoder.\n");
1372 return -1;
1373 }
1374 possible_crtcs = encoder->possible_crtcs;
1375 drmModeFreeEncoder(encoder);
1376
1377 for (i = 0; i < resources->count_crtcs; i++) {
1378 if (possible_crtcs & (1 << i) &&
1379 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1380 return i;
1381 }
1382 }
1383
1384 return -1;
1385}
1386
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001387/* Init output state that depends on gl or gbm */
1388static int
1389drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1390{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001391 int i, flags;
1392
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001393 output->surface = gbm_surface_create(ec->gbm,
1394 output->base.current->width,
1395 output->base.current->height,
1396 GBM_FORMAT_XRGB8888,
1397 GBM_BO_USE_SCANOUT |
1398 GBM_BO_USE_RENDERING);
1399 if (!output->surface) {
1400 weston_log("failed to create gbm surface\n");
1401 return -1;
1402 }
1403
1404 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001405 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001406 gbm_surface_destroy(output->surface);
1407 return -1;
1408 }
1409
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001410 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1411
1412 for (i = 0; i < 2; i++) {
1413 if (output->cursor_bo[i])
1414 continue;
1415
1416 output->cursor_bo[i] =
1417 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1418 flags);
1419 }
1420
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001421 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1422 weston_log("cursor buffers unavailable, using gl cursors\n");
1423 ec->cursors_are_broken = 1;
1424 }
1425
1426 return 0;
1427}
1428
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001429static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001430drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1431{
1432 int w = output->base.current->width;
1433 int h = output->base.current->height;
1434 unsigned int i;
1435
1436 /* FIXME error checking */
1437
1438 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1439 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1440 if (!output->dumb[i])
1441 goto err;
1442
1443 output->image[i] =
1444 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1445 output->dumb[i]->map,
1446 output->dumb[i]->stride);
1447 if (!output->image[i])
1448 goto err;
1449 }
1450
1451 if (pixman_renderer_output_create(&output->base) < 0)
1452 goto err;
1453
1454 pixman_region32_init_rect(&output->previous_damage,
1455 output->base.x, output->base.y, w, h);
1456
1457 return 0;
1458
1459err:
1460 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1461 if (output->dumb[i])
1462 drm_fb_destroy_dumb(output->dumb[i]);
1463 if (output->image[i])
1464 pixman_image_unref(output->image[i]);
1465
1466 output->dumb[i] = NULL;
1467 output->image[i] = NULL;
1468 }
1469
1470 return -1;
1471}
1472
1473static void
1474drm_output_fini_pixman(struct drm_output *output)
1475{
1476 unsigned int i;
1477
1478 pixman_renderer_output_destroy(&output->base);
1479 pixman_region32_fini(&output->previous_damage);
1480
1481 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1482 drm_fb_destroy_dumb(output->dumb[i]);
1483 pixman_image_unref(output->image[i]);
1484 output->dumb[i] = NULL;
1485 output->image[i] = NULL;
1486 }
1487}
1488
1489static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001490create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001491 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001492 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001493 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001494{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001495 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001496 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1497 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001498 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001499 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001500 drmModeModeInfo crtc_mode;
1501 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001502 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001503 char name[32];
1504 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001505
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001506 i = find_crtc_for_connector(ec, resources, connector);
1507 if (i < 0) {
1508 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001509 return -1;
1510 }
1511
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001512 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001513 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001514 return -1;
1515
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001516 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001517 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1518 output->base.make = "unknown";
1519 output->base.model = "unknown";
1520 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001521
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001522 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1523 type_name = connector_type_names[connector->connector_type];
1524 else
1525 type_name = "UNKNOWN";
1526 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1527 output->name = strdup(name);
1528
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001529 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001530 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001531 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001532 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001533 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001534
Matt Roper361d2ad2011-08-29 13:52:23 -07001535 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1536
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001537 /* Get the current mode on the crtc that's currently driving
1538 * this connector. */
1539 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001540 memset(&crtc_mode, 0, sizeof crtc_mode);
1541 if (encoder != NULL) {
1542 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1543 drmModeFreeEncoder(encoder);
1544 if (crtc == NULL)
1545 goto err_free;
1546 if (crtc->mode_valid)
1547 crtc_mode = crtc->mode;
1548 drmModeFreeCrtc(crtc);
1549 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001550
David Herrmann0f0d54e2011-12-08 17:05:45 +01001551 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001552 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1553 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001554 goto err_free;
1555 }
1556
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001557 preferred = NULL;
1558 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001559 configured = NULL;
1560
1561 wl_list_for_each(temp, &configured_output_list, link) {
1562 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001563 if (temp->mode)
1564 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001565 temp->name, temp->mode);
1566 o = temp;
1567 break;
1568 }
1569 }
1570
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001571 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001572 weston_log("Disabling output %s\n", o->name);
1573
1574 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1575 0, 0, 0, 0, 0, NULL);
1576 goto err_free;
1577 }
1578
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001579 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001580 if (o && o->config == OUTPUT_CONFIG_MODE &&
1581 o->width == drm_mode->base.width &&
1582 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001583 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001584 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001585 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001586 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001587 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001588 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001589
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001590 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001591 configured = drm_output_add_mode(output, &o->crtc_mode);
1592 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001593 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001594 current = configured;
1595 }
1596
Wang Quanxianacb805a2012-07-30 18:09:46 -04001597 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001598 current = drm_output_add_mode(output, &crtc_mode);
1599 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001600 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001601 }
1602
Scott Moreau8ab5d452012-07-30 19:51:08 -06001603 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1604 configured = current;
1605
Wang Quanxianacb805a2012-07-30 18:09:46 -04001606 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001607 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001608 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001609 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001610 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001611 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001612 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001613 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001614
1615 if (output->base.current == NULL) {
1616 weston_log("no available modes for %s\n", output->name);
1617 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001618 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001619
Wang Quanxianacb805a2012-07-30 18:09:46 -04001620 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1621
John Kåre Alsaker94659272012-11-13 19:10:18 +01001622 weston_output_init(&output->base, &ec->base, x, y,
1623 connector->mmWidth, connector->mmHeight,
1624 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1625
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001626 if (ec->use_pixman) {
1627 if (drm_output_init_pixman(output, ec) < 0) {
1628 weston_log("Failed to init output pixman state\n");
1629 goto err_output;
1630 }
1631 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001632 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001633 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001634 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001635
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001636 output->backlight = backlight_init(drm_device,
1637 connector->connector_type);
1638 if (output->backlight) {
1639 output->base.set_backlight = drm_set_backlight;
1640 output->base.backlight_current = drm_get_backlight(output);
1641 }
1642
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001643 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1644
Alex Wubd3354b2012-04-17 17:20:49 +08001645 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001646 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001647 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001648 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001649 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001650 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001651 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001652
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001653 weston_plane_init(&output->cursor_plane, 0, 0);
1654 weston_plane_init(&output->fb_plane, 0, 0);
1655
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001656 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1657 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1658 &ec->base.primary_plane);
1659
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001660 weston_log("Output %s, (connector %d, crtc %d)\n",
1661 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001662 wl_list_for_each(m, &output->base.mode_list, link)
1663 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1664 m->width, m->height, m->refresh / 1000.0,
1665 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1666 ", preferred" : "",
1667 m->flags & WL_OUTPUT_MODE_CURRENT ?
1668 ", current" : "",
1669 connector->count_modes == 0 ?
1670 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001671
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001672 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001673
John Kåre Alsaker94659272012-11-13 19:10:18 +01001674err_output:
1675 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001676err_free:
1677 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1678 base.link) {
1679 wl_list_remove(&drm_mode->base.link);
1680 free(drm_mode);
1681 }
1682
1683 drmModeFreeCrtc(output->original_crtc);
1684 ec->crtc_allocator &= ~(1 << output->crtc_id);
1685 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001686 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001687 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001688
David Herrmann0f0d54e2011-12-08 17:05:45 +01001689 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001690}
1691
Jesse Barnes58ef3792012-02-23 09:45:49 -05001692static void
1693create_sprites(struct drm_compositor *ec)
1694{
1695 struct drm_sprite *sprite;
1696 drmModePlaneRes *plane_res;
1697 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001698 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001699
1700 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1701 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001702 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001703 strerror(errno));
1704 return;
1705 }
1706
1707 for (i = 0; i < plane_res->count_planes; i++) {
1708 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1709 if (!plane)
1710 continue;
1711
1712 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1713 plane->count_formats));
1714 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001715 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001716 __func__);
1717 free(plane);
1718 continue;
1719 }
1720
1721 memset(sprite, 0, sizeof *sprite);
1722
1723 sprite->possible_crtcs = plane->possible_crtcs;
1724 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001725 sprite->current = NULL;
1726 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001727 sprite->compositor = ec;
1728 sprite->count_formats = plane->count_formats;
1729 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001730 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001731 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001732 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001733 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1734 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001735
1736 wl_list_insert(&ec->sprite_list, &sprite->link);
1737 }
1738
1739 free(plane_res->planes);
1740 free(plane_res);
1741}
1742
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001743static void
1744destroy_sprites(struct drm_compositor *compositor)
1745{
1746 struct drm_sprite *sprite, *next;
1747 struct drm_output *output;
1748
1749 output = container_of(compositor->base.output_list.next,
1750 struct drm_output, base.link);
1751
1752 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1753 drmModeSetPlane(compositor->drm.fd,
1754 sprite->plane_id,
1755 output->crtc_id, 0, 0,
1756 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001757 drm_output_release_fb(output, sprite->current);
1758 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001759 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001760 free(sprite);
1761 }
1762}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001763
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001764static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001765create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001766 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001767{
1768 drmModeConnector *connector;
1769 drmModeRes *resources;
1770 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001771 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001772
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001773 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001774 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001775 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001776 return -1;
1777 }
1778
Jesse Barnes58ef3792012-02-23 09:45:49 -05001779 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001780 if (!ec->crtcs) {
1781 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001782 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001783 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001784
Rob Clark4339add2012-08-09 14:18:28 -05001785 ec->min_width = resources->min_width;
1786 ec->max_width = resources->max_width;
1787 ec->min_height = resources->min_height;
1788 ec->max_height = resources->max_height;
1789
Jesse Barnes58ef3792012-02-23 09:45:49 -05001790 ec->num_crtcs = resources->count_crtcs;
1791 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1792
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001793 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001794 connector = drmModeGetConnector(ec->drm.fd,
1795 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001796 if (connector == NULL)
1797 continue;
1798
1799 if (connector->connection == DRM_MODE_CONNECTED &&
1800 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001801 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001802 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001803 connector, x, y,
1804 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001805 drmModeFreeConnector(connector);
1806 continue;
1807 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001808
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001809 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001810 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001811 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001812 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001813
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001814 drmModeFreeConnector(connector);
1815 }
1816
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001817 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001818 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001819 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001820 return -1;
1821 }
1822
1823 drmModeFreeResources(resources);
1824
1825 return 0;
1826}
1827
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001828static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001829update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001830{
1831 drmModeConnector *connector;
1832 drmModeRes *resources;
1833 struct drm_output *output, *next;
1834 int x = 0, y = 0;
1835 int x_offset = 0, y_offset = 0;
1836 uint32_t connected = 0, disconnects = 0;
1837 int i;
1838
1839 resources = drmModeGetResources(ec->drm.fd);
1840 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001841 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001842 return;
1843 }
1844
1845 /* collect new connects */
1846 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001847 int connector_id = resources->connectors[i];
1848
1849 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001850 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001851 continue;
1852
David Herrmann7551cff2011-12-08 17:05:43 +01001853 if (connector->connection != DRM_MODE_CONNECTED) {
1854 drmModeFreeConnector(connector);
1855 continue;
1856 }
1857
Benjamin Franzke117483d2011-08-30 11:38:26 +02001858 connected |= (1 << connector_id);
1859
1860 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001861 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001862 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001863 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001864
1865 /* XXX: not yet needed, we die with 0 outputs */
1866 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001867 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001868 else
1869 x = 0;
1870 y = 0;
1871 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001872 connector, x, y,
1873 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001874 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001875
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001876 }
1877 drmModeFreeConnector(connector);
1878 }
1879 drmModeFreeResources(resources);
1880
1881 disconnects = ec->connector_allocator & ~connected;
1882 if (disconnects) {
1883 wl_list_for_each_safe(output, next, &ec->base.output_list,
1884 base.link) {
1885 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001886 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001887 output->base.x - x_offset,
1888 output->base.y - y_offset);
1889 }
1890
1891 if (disconnects & (1 << output->connector_id)) {
1892 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001893 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001894 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001895 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001896 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001897 }
1898 }
1899 }
1900
1901 /* FIXME: handle zero outputs, without terminating */
1902 if (ec->connector_allocator == 0)
1903 wl_display_terminate(ec->base.wl_display);
1904}
1905
1906static int
David Herrmannd7488c22012-03-11 20:05:21 +01001907udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001908{
David Herrmannd7488c22012-03-11 20:05:21 +01001909 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001910 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001911
1912 sysnum = udev_device_get_sysnum(device);
1913 if (!sysnum || atoi(sysnum) != ec->drm.id)
1914 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001915
David Herrmann6ac52db2012-03-11 20:05:22 +01001916 val = udev_device_get_property_value(device, "HOTPLUG");
1917 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001918 return 0;
1919
David Herrmann6ac52db2012-03-11 20:05:22 +01001920 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001921}
1922
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001923static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001924udev_drm_event(int fd, uint32_t mask, void *data)
1925{
1926 struct drm_compositor *ec = data;
1927 struct udev_device *event;
1928
1929 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001930
David Herrmannd7488c22012-03-11 20:05:21 +01001931 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001932 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001933
1934 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001935
1936 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001937}
1938
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001939static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001940drm_restore(struct weston_compositor *ec)
1941{
1942 struct drm_compositor *d = (struct drm_compositor *) ec;
1943
1944 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1945 weston_log("failed to drop master: %m\n");
1946 tty_reset(d->tty);
1947}
1948
1949static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001950drm_free_configured_output(struct drm_configured_output *output)
1951{
1952 free(output->name);
1953 free(output->mode);
1954 free(output);
1955}
1956
1957static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001958drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001959{
1960 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05001961 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001962 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001963
Kristian Høgsberge8091032013-02-18 15:43:29 -05001964 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
1965 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001966 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001967 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001968
1969 wl_event_source_remove(d->udev_drm_source);
1970 wl_event_source_remove(d->drm_source);
1971
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001972 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001973
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03001974 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001975
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001976 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001977
1978 if (d->gbm)
1979 gbm_device_destroy(d->gbm);
1980
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001981 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001982 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001983 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001984
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001985 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001986}
1987
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001988static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001989drm_compositor_set_modes(struct drm_compositor *compositor)
1990{
1991 struct drm_output *output;
1992 struct drm_mode *drm_mode;
1993 int ret;
1994
1995 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02001996 if (!output->current) {
1997 /* If something that would cause the output to
1998 * switch mode happened while in another vt, we
1999 * might not have a current drm_fb. In that case,
2000 * schedule a repaint and let drm_output_repaint
2001 * handle setting the mode. */
2002 weston_output_schedule_repaint(&output->base);
2003 continue;
2004 }
2005
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002006 drm_mode = (struct drm_mode *) output->base.current;
2007 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002008 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002009 &output->connector_id, 1,
2010 &drm_mode->mode_info);
2011 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002012 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002013 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002014 drm_mode->base.width, drm_mode->base.height,
2015 output->base.x, output->base.y);
2016 }
2017 }
2018}
2019
2020static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002021vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002022{
2023 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002024 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002025 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002026 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002027
2028 switch (event) {
2029 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002030 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002031 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002032 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002033 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002034 wl_display_terminate(compositor->wl_display);
2035 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002036 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002037 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002038 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002039 wl_list_for_each(seat, &compositor->seat_list, base.link)
2040 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002041 break;
2042 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002043 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002044 wl_list_for_each(seat, &compositor->seat_list, base.link)
2045 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002046
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002047 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002048 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002049 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002050
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002051 /* If we have a repaint scheduled (either from a
2052 * pending pageflip or the idle handler), make sure we
2053 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002054 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002055 * further attemps at repainting. When we switch
2056 * back, we schedule a repaint, which will process
2057 * pending frame callbacks. */
2058
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002059 wl_list_for_each(output, &ec->base.output_list, base.link) {
2060 output->base.repaint_needed = 0;
2061 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002062 }
2063
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002064 output = container_of(ec->base.output_list.next,
2065 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002066
2067 wl_list_for_each(sprite, &ec->sprite_list, link)
2068 drmModeSetPlane(ec->drm.fd,
2069 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002070 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002071 0, 0, 0, 0, 0, 0, 0, 0);
2072
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002073 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002074 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002075
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002076 break;
2077 };
2078}
2079
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002080static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002081switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002082{
2083 struct drm_compositor *ec = data;
2084
Daniel Stone325fc2d2012-05-30 16:31:58 +01002085 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002086}
2087
David Herrmann0af066f2012-10-29 19:21:16 +01002088/*
2089 * Find primary GPU
2090 * Some systems may have multiple DRM devices attached to a single seat. This
2091 * function loops over all devices and tries to find a PCI device with the
2092 * boot_vga sysfs attribute set to 1.
2093 * If no such device is found, the first DRM device reported by udev is used.
2094 */
2095static struct udev_device*
2096find_primary_gpu(struct drm_compositor *ec, const char *seat)
2097{
2098 struct udev_enumerate *e;
2099 struct udev_list_entry *entry;
2100 const char *path, *device_seat, *id;
2101 struct udev_device *device, *drm_device, *pci;
2102
2103 e = udev_enumerate_new(ec->udev);
2104 udev_enumerate_add_match_subsystem(e, "drm");
2105 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2106
2107 udev_enumerate_scan_devices(e);
2108 drm_device = NULL;
2109 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2110 path = udev_list_entry_get_name(entry);
2111 device = udev_device_new_from_syspath(ec->udev, path);
2112 if (!device)
2113 continue;
2114 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2115 if (!device_seat)
2116 device_seat = default_seat;
2117 if (strcmp(device_seat, seat)) {
2118 udev_device_unref(device);
2119 continue;
2120 }
2121
2122 pci = udev_device_get_parent_with_subsystem_devtype(device,
2123 "pci", NULL);
2124 if (pci) {
2125 id = udev_device_get_sysattr_value(pci, "boot_vga");
2126 if (id && !strcmp(id, "1")) {
2127 if (drm_device)
2128 udev_device_unref(drm_device);
2129 drm_device = device;
2130 break;
2131 }
2132 }
2133
2134 if (!drm_device)
2135 drm_device = device;
2136 else
2137 udev_device_unref(device);
2138 }
2139
2140 udev_enumerate_unref(e);
2141 return drm_device;
2142}
2143
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002144static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002145planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002146{
2147 struct drm_compositor *c = data;
2148
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002149 switch (key) {
2150 case KEY_C:
2151 c->cursors_are_broken ^= 1;
2152 break;
2153 case KEY_V:
2154 c->sprites_are_broken ^= 1;
2155 break;
2156 case KEY_O:
2157 c->sprites_hidden ^= 1;
2158 break;
2159 default:
2160 break;
2161 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002162}
2163
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002164static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002165drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002166 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002167 int *argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002168{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002169 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002170 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002171 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002172 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002173 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002174 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002175
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002176 weston_log("initializing drm backend\n");
2177
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002178 ec = malloc(sizeof *ec);
2179 if (ec == NULL)
2180 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002181 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002182
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002183 /* KMS support for sprites is not complete yet, so disable the
2184 * functionality for now. */
2185 ec->sprites_are_broken = 1;
2186
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002187 ec->use_pixman = pixman;
2188
Daniel Stone725c2c32012-06-22 14:04:36 +01002189 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002190 config_file) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002191 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002192 goto err_base;
2193 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002194
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002195 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002196 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002197 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002198 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002199 goto err_compositor;
2200 }
2201
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002202 ec->udev = udev_new();
2203 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002204 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002205 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002206 }
2207
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002208 ec->base.wl_display = display;
2209 ec->tty = tty_create(&ec->base, vt_func, tty);
2210 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002211 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002212 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002213 }
2214
David Herrmann0af066f2012-10-29 19:21:16 +01002215 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002216 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002217 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002218 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002219 }
David Herrmann0af066f2012-10-29 19:21:16 +01002220 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002221
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002222 if (init_drm(ec, drm_device) < 0) {
2223 weston_log("failed to initialize kms\n");
2224 goto err_udev_dev;
2225 }
2226
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002227 if (ec->use_pixman) {
2228 if (init_pixman(ec) < 0) {
2229 weston_log("failed to initialize pixman renderer\n");
2230 goto err_udev_dev;
2231 }
2232 } else {
2233 if (init_egl(ec) < 0) {
2234 weston_log("failed to initialize egl\n");
2235 goto err_udev_dev;
2236 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002237 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002238
2239 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002240 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002241
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002242 ec->base.focus = 1;
2243
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002244 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002245
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002246 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002247 weston_compositor_add_key_binding(&ec->base, key,
2248 MODIFIER_CTRL | MODIFIER_ALT,
2249 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002250
Jesse Barnes58ef3792012-02-23 09:45:49 -05002251 wl_list_init(&ec->sprite_list);
2252 create_sprites(ec);
2253
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002254 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002255 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002256 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002257 }
2258
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002259 path = NULL;
2260
Kristian Høgsberge8091032013-02-18 15:43:29 -05002261 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002262 weston_log("failed to create input devices\n");
2263 goto err_sprite;
2264 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002265
2266 loop = wl_display_get_event_loop(ec->base.wl_display);
2267 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002268 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002269 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002270
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002271 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2272 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002273 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002274 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002275 }
2276 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2277 "drm", NULL);
2278 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002279 wl_event_loop_add_fd(loop,
2280 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002281 WL_EVENT_READABLE, udev_drm_event, ec);
2282
2283 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002284 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002285 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002286 }
2287
Daniel Stonea96b93c2012-06-22 14:04:37 +01002288 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002289
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002290 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002291 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002292 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002293 planes_binding, ec);
2294 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2295 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002296
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002297 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002298
2299err_udev_monitor:
2300 wl_event_source_remove(ec->udev_drm_source);
2301 udev_monitor_unref(ec->udev_monitor);
2302err_drm_source:
2303 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002304 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2305 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002306err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002307 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002308 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002309 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002310err_udev_dev:
2311 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002312err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002313 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2314 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002315 tty_destroy(ec->tty);
2316err_udev:
2317 udev_unref(ec->udev);
2318err_compositor:
2319 weston_compositor_shutdown(&ec->base);
2320err_base:
2321 free(ec);
2322 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002323}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002324
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002325static int
2326set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2327{
2328 mode->flags = 0;
2329
2330 if (strcmp(hsync, "+hsync") == 0)
2331 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2332 else if (strcmp(hsync, "-hsync") == 0)
2333 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2334 else
2335 return -1;
2336
2337 if (strcmp(vsync, "+vsync") == 0)
2338 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2339 else if (strcmp(vsync, "-vsync") == 0)
2340 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2341 else
2342 return -1;
2343
2344 return 0;
2345}
2346
2347static int
2348check_for_modeline(struct drm_configured_output *output)
2349{
2350 drmModeModeInfo mode;
2351 char hsync[16];
2352 char vsync[16];
2353 char mode_name[16];
2354 float fclock;
2355
2356 mode.type = DRM_MODE_TYPE_USERDEF;
2357 mode.hskew = 0;
2358 mode.vscan = 0;
2359 mode.vrefresh = 0;
2360
2361 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2362 &fclock, &mode.hdisplay,
2363 &mode.hsync_start,
2364 &mode.hsync_end, &mode.htotal,
2365 &mode.vdisplay,
2366 &mode.vsync_start,
2367 &mode.vsync_end, &mode.vtotal,
2368 hsync, vsync) == 11) {
2369 if (set_sync_flags(&mode, hsync, vsync))
2370 return -1;
2371
2372 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2373 strcpy(mode.name, mode_name);
2374
2375 mode.clock = fclock * 1000;
2376 } else
2377 return -1;
2378
2379 output->crtc_mode = mode;
2380
2381 return 0;
2382}
2383
Scott Moreau8ab5d452012-07-30 19:51:08 -06002384static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002385drm_output_set_transform(struct drm_configured_output *output)
2386{
2387 if (!output_transform) {
2388 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2389 return;
2390 }
2391
2392 if (!strcmp(output_transform, "normal"))
2393 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2394 else if (!strcmp(output_transform, "90"))
2395 output->transform = WL_OUTPUT_TRANSFORM_90;
2396 else if (!strcmp(output_transform, "180"))
2397 output->transform = WL_OUTPUT_TRANSFORM_180;
2398 else if (!strcmp(output_transform, "270"))
2399 output->transform = WL_OUTPUT_TRANSFORM_270;
2400 else if (!strcmp(output_transform, "flipped"))
2401 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2402 else if (!strcmp(output_transform, "flipped-90"))
2403 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2404 else if (!strcmp(output_transform, "flipped-180"))
2405 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2406 else if (!strcmp(output_transform, "flipped-270"))
2407 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2408 else {
2409 weston_log("Invalid transform \"%s\" for output %s\n",
2410 output_transform, output_name);
2411 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2412 }
2413
2414 free(output_transform);
2415 output_transform = NULL;
2416}
2417
2418static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002419output_section_done(void *data)
2420{
2421 struct drm_configured_output *output;
2422
2423 output = malloc(sizeof *output);
2424
Scott Moreau1bad5db2012-08-18 01:04:05 -06002425 if (!output || !output_name || (output_name[0] == 'X') ||
2426 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002427 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002428 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002429 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002430 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002431 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002432 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002433 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002434 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002435 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002436
2437 output->config = OUTPUT_CONFIG_INVALID;
2438 output->name = output_name;
2439 output->mode = output_mode;
2440
Scott Moreau1bad5db2012-08-18 01:04:05 -06002441 if (output_mode) {
2442 if (strcmp(output_mode, "off") == 0)
2443 output->config = OUTPUT_CONFIG_OFF;
2444 else if (strcmp(output_mode, "preferred") == 0)
2445 output->config = OUTPUT_CONFIG_PREFERRED;
2446 else if (strcmp(output_mode, "current") == 0)
2447 output->config = OUTPUT_CONFIG_CURRENT;
2448 else if (sscanf(output_mode, "%dx%d",
2449 &output->width, &output->height) == 2)
2450 output->config = OUTPUT_CONFIG_MODE;
2451 else if (check_for_modeline(output) == 0)
2452 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002453
Scott Moreau1bad5db2012-08-18 01:04:05 -06002454 if (output->config == OUTPUT_CONFIG_INVALID)
2455 weston_log("Invalid mode \"%s\" for output %s\n",
2456 output_mode, output_name);
2457 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002458 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002459
2460 drm_output_set_transform(output);
2461
2462 wl_list_insert(&configured_output_list, &output->link);
2463
2464 if (output_transform)
2465 free(output_transform);
2466 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002467}
2468
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002469WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002470backend_init(struct wl_display *display, int *argc, char *argv[],
Daniel Stonec1be8e52012-06-01 11:14:02 -04002471 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002472{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002473 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002474 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002475
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002476 const struct weston_option drm_options[] = {
2477 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2478 { WESTON_OPTION_STRING, "seat", 0, &seat },
2479 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002480 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002481 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002482 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002483
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002484 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002485
Scott Moreau8ab5d452012-07-30 19:51:08 -06002486 wl_list_init(&configured_output_list);
2487
2488 const struct config_key drm_config_keys[] = {
2489 { "name", CONFIG_KEY_STRING, &output_name },
2490 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002491 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002492 };
2493
2494 const struct config_section config_section[] = {
2495 { "output", drm_config_keys,
2496 ARRAY_LENGTH(drm_config_keys), output_section_done },
2497 };
2498
2499 parse_config_file(config_file, config_section,
2500 ARRAY_LENGTH(config_section), NULL);
2501
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002502 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2503 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002504}