blob: 8b3325694d66b141cf7e28ba7f876003b8f45894 [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
Richard Hughesab745622013-05-01 21:52:13 +010024#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040028#define _GNU_SOURCE
29
Jesse Barnes58ef3792012-02-23 09:45:49 -050030#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040031#include <stdlib.h>
Richard Hughesb24e48e2013-05-09 20:31:09 +010032#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010033#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040034#include <string.h>
35#include <fcntl.h>
36#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040037#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030038#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020039#include <sys/mman.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030040#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040041
Benjamin Franzkec649a922011-03-02 11:56:04 +010042#include <xf86drm.h>
43#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050044#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010045
Benjamin Franzke060cf802011-04-30 09:32:11 +020046#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020047#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040048#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020049
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040050#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010051#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020052#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050053#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010054#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040055
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030056#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
57#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
58#endif
59
Kristian Høgsberg061c4252012-06-28 11:28:15 -040060static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060061static char *output_name;
62static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060063static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060064static struct wl_list configured_output_list;
65
66enum output_config {
67 OUTPUT_CONFIG_INVALID = 0,
68 OUTPUT_CONFIG_OFF,
69 OUTPUT_CONFIG_PREFERRED,
70 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060071 OUTPUT_CONFIG_MODE,
72 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060073};
74
75struct drm_configured_output {
76 char *name;
77 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060078 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060079 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060080 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060081 enum output_config config;
82 struct wl_list link;
83};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040084
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040085struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050086 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040087
88 struct udev *udev;
89 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040090
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010091 struct udev_monitor *udev_monitor;
92 struct wl_event_source *udev_drm_source;
93
Benjamin Franzke2af7f102011-03-02 11:14:59 +010094 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010095 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010096 int fd;
97 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020098 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 uint32_t *crtcs;
100 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -0500101 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100102 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -0500103 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200104
Rob Clark4339add2012-08-09 14:18:28 -0500105 /* we need these parameters in order to not fail drmModeAddFB2()
106 * due to out of bounds dimensions, and then mistakenly set
107 * sprites_are_broken:
108 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200109 uint32_t min_width, max_width;
110 uint32_t min_height, max_height;
111 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500112
Jesse Barnes58ef3792012-02-23 09:45:49 -0500113 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500114 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200115 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500116
Rob Clarkab5b1e32012-08-09 13:24:45 -0500117 int cursors_are_broken;
118
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200119 int use_pixman;
120
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200121 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300122
123 clockid_t clock;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400124};
125
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400126struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500127 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400128 drmModeModeInfo mode_info;
129};
130
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300131struct drm_output;
132
133struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300134 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200135 uint32_t fb_id, stride, handle, size;
136 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300137 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200138 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200139
140 /* Used by gbm fbs */
141 struct gbm_bo *bo;
142
143 /* Used by dumb fbs */
144 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300145};
146
Richard Hughes2b2092a2013-04-24 14:58:02 +0100147struct drm_edid {
148 char eisa_id[13];
149 char monitor_name[13];
150 char pnp_id[5];
151 char serial_number[13];
152};
153
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400154struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500155 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400156
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400157 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500158 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700160 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100161 struct drm_edid edid;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200162
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300163 int vblank_pending;
164 int page_flip_pending;
165
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400166 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400167 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400168 struct weston_plane cursor_plane;
169 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400170 struct weston_surface *cursor_surface;
171 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300172 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200173 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200174
175 struct drm_fb *dumb[2];
176 pixman_image_t *image[2];
177 int current_image;
178 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400179};
180
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181/*
182 * An output has a primary display plane plus zero or more sprites for
183 * blending display contents.
184 */
185struct drm_sprite {
186 struct wl_list link;
187
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400188 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500189
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200190 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300191 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500192 struct drm_compositor *compositor;
193
Jesse Barnes58ef3792012-02-23 09:45:49 -0500194 uint32_t possible_crtcs;
195 uint32_t plane_id;
196 uint32_t count_formats;
197
198 int32_t src_x, src_y;
199 uint32_t src_w, src_h;
200 uint32_t dest_x, dest_y;
201 uint32_t dest_w, dest_h;
202
203 uint32_t formats[];
204};
205
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500206static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400207
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400208static void
209drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400210
Jesse Barnes58ef3792012-02-23 09:45:49 -0500211static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500212drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
213{
214 struct weston_compositor *ec = output_base->compositor;
215 struct drm_compositor *c =(struct drm_compositor *) ec;
216 struct drm_output *output = (struct drm_output *) output_base;
217 int crtc;
218
219 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
220 if (c->crtcs[crtc] != output->crtc_id)
221 continue;
222
223 if (supported & (1 << crtc))
224 return -1;
225 }
226
227 return 0;
228}
229
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300230static void
231drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
232{
233 struct drm_fb *fb = data;
234 struct gbm_device *gbm = gbm_bo_get_device(bo);
235
236 if (fb->fb_id)
237 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
238
Pekka Paalanende685b82012-12-04 15:58:12 +0200239 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300240
241 free(data);
242}
243
244static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200245drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
246{
247 struct drm_fb *fb;
248 int ret;
249
250 struct drm_mode_create_dumb create_arg;
251 struct drm_mode_destroy_dumb destroy_arg;
252 struct drm_mode_map_dumb map_arg;
253
254 fb = calloc(1, sizeof *fb);
255 if (!fb)
256 return NULL;
257
258 create_arg.bpp = 32;
259 create_arg.width = width;
260 create_arg.height = height;
261
262 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
263 if (ret)
264 goto err_fb;
265
266 fb->handle = create_arg.handle;
267 fb->stride = create_arg.pitch;
268 fb->size = create_arg.size;
269 fb->fd = ec->drm.fd;
270
271 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
272 fb->stride, fb->handle, &fb->fb_id);
273 if (ret)
274 goto err_bo;
275
276 memset(&map_arg, 0, sizeof(map_arg));
277 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400278 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200279 if (ret)
280 goto err_add_fb;
281
282 fb->map = mmap(0, fb->size, PROT_WRITE,
283 MAP_SHARED, ec->drm.fd, map_arg.offset);
284 if (fb->map == MAP_FAILED)
285 goto err_add_fb;
286
287 return fb;
288
289err_add_fb:
290 drmModeRmFB(ec->drm.fd, fb->fb_id);
291err_bo:
292 memset(&destroy_arg, 0, sizeof(destroy_arg));
293 destroy_arg.handle = create_arg.handle;
294 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
295err_fb:
296 free(fb);
297 return NULL;
298}
299
300static void
301drm_fb_destroy_dumb(struct drm_fb *fb)
302{
303 struct drm_mode_destroy_dumb destroy_arg;
304
305 if (!fb->map)
306 return;
307
308 if (fb->fb_id)
309 drmModeRmFB(fb->fd, fb->fb_id);
310
311 weston_buffer_reference(&fb->buffer_ref, NULL);
312
313 munmap(fb->map, fb->size);
314
315 memset(&destroy_arg, 0, sizeof(destroy_arg));
316 destroy_arg.handle = fb->handle;
317 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
318
319 free(fb);
320}
321
322static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500323drm_fb_get_from_bo(struct gbm_bo *bo,
324 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300325{
326 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200327 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200328 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300329 int ret;
330
331 if (fb)
332 return fb;
333
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200334 fb = calloc(1, sizeof *fb);
335 if (!fb)
336 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300337
338 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300339
340 width = gbm_bo_get_width(bo);
341 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200342 fb->stride = gbm_bo_get_stride(bo);
343 fb->handle = gbm_bo_get_handle(bo).u32;
344 fb->size = fb->stride * height;
345 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300346
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200347 if (compositor->min_width > width || width > compositor->max_width ||
348 compositor->min_height > height ||
349 height > compositor->max_height) {
350 weston_log("bo geometry out of bounds\n");
351 goto err_free;
352 }
353
354 ret = -1;
355
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200356 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200357 handles[0] = fb->handle;
358 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200359 offsets[0] = 0;
360
361 ret = drmModeAddFB2(compositor->drm.fd, width, height,
362 format, handles, pitches, offsets,
363 &fb->fb_id, 0);
364 if (ret) {
365 weston_log("addfb2 failed: %m\n");
366 compositor->no_addfb2 = 1;
367 compositor->sprites_are_broken = 1;
368 }
369 }
370
371 if (ret)
372 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200373 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200374
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300375 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200376 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200377 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300378 }
379
380 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
381
382 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200383
384err_free:
385 free(fb);
386 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300387}
388
389static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200390drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
391{
Pekka Paalanende685b82012-12-04 15:58:12 +0200392 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200393
394 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395
Pekka Paalanende685b82012-12-04 15:58:12 +0200396 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397}
398
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200399static void
400drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
401{
402 if (!fb)
403 return;
404
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200405 if (fb->map &&
406 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200407 drm_fb_destroy_dumb(fb);
408 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200409 if (fb->is_client_buffer)
410 gbm_bo_destroy(fb->bo);
411 else
412 gbm_surface_release_buffer(output->surface,
413 output->current->bo);
414 }
415}
416
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500417static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200418drm_output_check_scanout_format(struct drm_output *output,
419 struct weston_surface *es, struct gbm_bo *bo)
420{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200421 uint32_t format;
422 pixman_region32_t r;
423
424 format = gbm_bo_get_format(bo);
425
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500426 switch (format) {
427 case GBM_FORMAT_XRGB8888:
428 return format;
429 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200430 /* We can only scanout an ARGB buffer if the surface's
431 * opaque region covers the whole output */
432 pixman_region32_init(&r);
433 pixman_region32_subtract(&r, &output->base.region,
434 &es->opaque);
435
436 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500437 format = GBM_FORMAT_XRGB8888;
438 else
439 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200440
441 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200442
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500443 return format;
444 default:
445 return 0;
446 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200447}
448
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400449static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400450drm_output_prepare_scanout_surface(struct weston_output *_output,
451 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500452{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400453 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500454 struct drm_compositor *c =
455 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200456 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300457 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500458 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500459
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500460 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200461 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200462 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200463 buffer->width != output->base.current->width ||
464 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200465 output->base.transform != es->buffer_transform ||
466 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400467 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500468
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400469 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200470 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500471
Rob Bradford9b101872012-09-14 23:25:41 +0100472 /* Unable to use the buffer for scanout */
473 if (!bo)
474 return NULL;
475
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500476 format = drm_output_check_scanout_format(output, es, bo);
477 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300478 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400479 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300480 }
481
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500482 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300483 if (!output->next) {
484 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400485 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300486 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500487
Pekka Paalanende685b82012-12-04 15:58:12 +0200488 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500489
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400490 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500491}
492
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500493static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200494drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400495{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200496 struct drm_compositor *c =
497 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300498 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400499
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200500 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400501
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300502 bo = gbm_surface_lock_front_buffer(output->surface);
503 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200504 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400505 return;
506 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300507
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500508 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300509 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200510 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300511 gbm_surface_release_buffer(output->surface, bo);
512 return;
513 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400514}
515
516static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200517drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
518{
519 struct weston_compositor *ec = output->base.compositor;
520 pixman_region32_t total_damage, previous_damage;
521
522 pixman_region32_init(&total_damage);
523 pixman_region32_init(&previous_damage);
524
525 pixman_region32_copy(&previous_damage, damage);
526
527 pixman_region32_union(&total_damage, damage, &output->previous_damage);
528 pixman_region32_copy(&output->previous_damage, &previous_damage);
529
530 output->current_image ^= 1;
531
532 output->next = output->dumb[output->current_image];
533 pixman_renderer_output_set_buffer(&output->base,
534 output->image[output->current_image]);
535
536 ec->renderer->repaint_output(&output->base, &total_damage);
537
538 pixman_region32_fini(&total_damage);
539 pixman_region32_fini(&previous_damage);
540}
541
542static void
543drm_output_render(struct drm_output *output, pixman_region32_t *damage)
544{
545 struct drm_compositor *c =
546 (struct drm_compositor *) output->base.compositor;
547
548 if (c->use_pixman)
549 drm_output_render_pixman(output, damage);
550 else
551 drm_output_render_gl(output, damage);
552
553 pixman_region32_subtract(&c->base.primary_plane.damage,
554 &c->base.primary_plane.damage, damage);
555}
556
557static void
Richard Hughese7299962013-05-01 21:52:12 +0100558drm_output_set_gamma(struct weston_output *output_base,
559 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
560{
561 int rc;
562 struct drm_output *output = (struct drm_output *) output_base;
563 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
564
565 /* check */
566 if (output_base->gamma_size != size)
567 return;
568 if (!output->original_crtc)
569 return;
570
571 rc = drmModeCrtcSetGamma(compositor->drm.fd,
572 output->crtc_id,
573 size, r, g, b);
574 if (rc)
575 weston_log("set gamma failed: %m\n");
576}
577
578static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500579drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400580 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100581{
582 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500583 struct drm_compositor *compositor =
584 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500585 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400586 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500587 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100588
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300589 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400590 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300591 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400592 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100593
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400594 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300595 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400596 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300597 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400598 &output->connector_id, 1,
599 &mode->mode_info);
600 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200601 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400602 return;
603 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200604 }
605
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500606 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300607 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500608 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200609 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500610 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500611 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100612
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300613 output->page_flip_pending = 1;
614
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400615 drm_output_set_cursor(output);
616
Jesse Barnes58ef3792012-02-23 09:45:49 -0500617 /*
618 * Now, update all the sprite surfaces
619 */
620 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200621 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 drmVBlank vbl = {
623 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
624 .request.sequence = 1,
625 };
626
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200627 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200628 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629 continue;
630
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200631 if (s->next && !compositor->sprites_hidden)
632 fb_id = s->next->fb_id;
633
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200635 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500636 s->dest_x, s->dest_y,
637 s->dest_w, s->dest_h,
638 s->src_x, s->src_y,
639 s->src_w, s->src_h);
640 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200641 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500642 ret, strerror(errno));
643
Rob Clark5ca1a472012-08-08 20:27:37 -0500644 if (output->pipe > 0)
645 vbl.request.type |= DRM_VBLANK_SECONDARY;
646
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 /*
648 * Queue a vblank signal so we know when the surface
649 * becomes active on the display or has been replaced.
650 */
651 vbl.request.signal = (unsigned long)s;
652 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
653 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200654 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655 ret, strerror(errno));
656 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300657
658 s->output = output;
659 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500660 }
661
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500662 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400663}
664
665static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200666drm_output_start_repaint_loop(struct weston_output *output_base)
667{
668 struct drm_output *output = (struct drm_output *) output_base;
669 struct drm_compositor *compositor = (struct drm_compositor *)
670 output_base->compositor;
671 uint32_t fb_id;
672
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300673 struct timespec ts;
674
675 if (!output->current) {
676 /* We can't page flip if there's no mode set */
677 uint32_t msec;
678
679 clock_gettime(compositor->clock, &ts);
680 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
681 weston_output_finish_frame(output_base, msec);
682 return;
683 }
684
685 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200686
687 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
688 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
689 weston_log("queueing pageflip failed: %m\n");
690 return;
691 }
692}
693
694static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500695vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
696 void *data)
697{
698 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300699 struct drm_output *output = s->output;
700 uint32_t msecs;
701
702 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500703
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200704 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200705 s->current = s->next;
706 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300707
708 if (!output->page_flip_pending) {
709 msecs = sec * 1000 + usec / 1000;
710 weston_output_finish_frame(&output->base, msecs);
711 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500712}
713
714static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400715page_flip_handler(int fd, unsigned int frame,
716 unsigned int sec, unsigned int usec, void *data)
717{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200718 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400719 uint32_t msecs;
720
Jonas Ådahle5a12252013-04-05 23:07:11 +0200721 /* We don't set page_flip_pending on start_repaint_loop, in that case
722 * we just want to page flip to the current buffer to get an accurate
723 * timestamp */
724 if (output->page_flip_pending) {
725 drm_output_release_fb(output, output->current);
726 output->current = output->next;
727 output->next = NULL;
728 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300729
Jonas Ådahle5a12252013-04-05 23:07:11 +0200730 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400731
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300732 if (!output->vblank_pending) {
733 msecs = sec * 1000 + usec / 1000;
734 weston_output_finish_frame(&output->base, msecs);
735 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200736}
737
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500738static uint32_t
739drm_output_check_sprite_format(struct drm_sprite *s,
740 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500741{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500742 uint32_t i, format;
743
744 format = gbm_bo_get_format(bo);
745
746 if (format == GBM_FORMAT_ARGB8888) {
747 pixman_region32_t r;
748
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500749 pixman_region32_init_rect(&r, 0, 0,
750 es->geometry.width,
751 es->geometry.height);
752 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500753
754 if (!pixman_region32_not_empty(&r))
755 format = GBM_FORMAT_XRGB8888;
756
757 pixman_region32_fini(&r);
758 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500759
760 for (i = 0; i < s->count_formats; i++)
761 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500762 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500763
764 return 0;
765}
766
767static int
768drm_surface_transform_supported(struct weston_surface *es)
769{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500770 return !es->transform.enabled ||
771 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772}
773
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400774static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400776 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500777{
778 struct weston_compositor *ec = output_base->compositor;
779 struct drm_compositor *c =(struct drm_compositor *) ec;
780 struct drm_sprite *s;
781 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500782 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500783 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200784 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500785 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400786 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500787
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200788 if (c->gbm == NULL)
789 return NULL;
790
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200791 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200792 return NULL;
793
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500794 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400795 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500796
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300797 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400798 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300799
Pekka Paalanende685b82012-12-04 15:58:12 +0200800 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400801 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200803 if (es->alpha != 1.0f)
804 return NULL;
805
Pekka Paalanende685b82012-12-04 15:58:12 +0200806 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500807 return NULL;
808
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500811
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812 wl_list_for_each(s, &c->sprite_list, link) {
813 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
814 continue;
815
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200816 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817 found = 1;
818 break;
819 }
820 }
821
822 /* No sprites available */
823 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400824 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500825
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400826 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200827 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400828 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400829 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400830
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500831 format = drm_output_check_sprite_format(s, es, bo);
832 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200833 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835 }
836
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200837 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200838 if (!s->next) {
839 gbm_bo_destroy(bo);
840 return NULL;
841 }
842
Pekka Paalanende685b82012-12-04 15:58:12 +0200843 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400845 box = pixman_region32_extents(&es->transform.boundingbox);
846 s->plane.x = box->x1;
847 s->plane.y = box->y1;
848
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849 /*
850 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200851 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500852 * for us already).
853 */
854 pixman_region32_init(&dest_rect);
855 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
856 &output_base->region);
857 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
858 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200859 tbox = weston_transformed_rect(output_base->width,
860 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200861 output_base->transform,
862 1, *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200863 s->dest_x = tbox.x1;
864 s->dest_y = tbox.y1;
865 s->dest_w = tbox.x2 - tbox.x1;
866 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500867 pixman_region32_fini(&dest_rect);
868
869 pixman_region32_init(&src_rect);
870 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
871 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500872 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400873
874 weston_surface_from_global_fixed(es,
875 wl_fixed_from_int(box->x1),
876 wl_fixed_from_int(box->y1),
877 &sx1, &sy1);
878 weston_surface_from_global_fixed(es,
879 wl_fixed_from_int(box->x2),
880 wl_fixed_from_int(box->y2),
881 &sx2, &sy2);
882
883 if (sx1 < 0)
884 sx1 = 0;
885 if (sy1 < 0)
886 sy1 = 0;
887 if (sx2 > wl_fixed_from_int(es->geometry.width))
888 sx2 = wl_fixed_from_int(es->geometry.width);
889 if (sy2 > wl_fixed_from_int(es->geometry.height))
890 sy2 = wl_fixed_from_int(es->geometry.height);
891
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200892 tbox.x1 = sx1;
893 tbox.y1 = sy1;
894 tbox.x2 = sx2;
895 tbox.y2 = sy2;
896
897 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
898 wl_fixed_from_int(es->geometry.height),
Alexander Larsson4ea95522013-05-22 14:41:37 +0200899 es->buffer_transform, 1, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200900
901 s->src_x = tbox.x1 << 8;
902 s->src_y = tbox.y1 << 8;
903 s->src_w = (tbox.x2 - tbox.x1) << 8;
904 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500905 pixman_region32_fini(&src_rect);
906
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400907 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500908}
909
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400910static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400911drm_output_prepare_cursor_surface(struct weston_output *output_base,
912 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500913{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400914 struct drm_compositor *c =
915 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400916 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400917
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200918 if (c->gbm == NULL)
919 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200920 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
921 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400922 if (output->cursor_surface)
923 return NULL;
924 if (es->output_mask != (1u << output_base->id))
925 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500926 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400927 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200928 if (es->buffer_ref.buffer == NULL ||
929 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400930 es->geometry.width > 64 || es->geometry.height > 64)
931 return NULL;
932
933 output->cursor_surface = es;
934
935 return &output->cursor_plane;
936}
937
938static void
939drm_output_set_cursor(struct drm_output *output)
940{
941 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400942 struct drm_compositor *c =
943 (struct drm_compositor *) output->base.compositor;
944 EGLint handle, stride;
945 struct gbm_bo *bo;
946 uint32_t buf[64 * 64];
947 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400948 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500949
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400950 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400951 if (es == NULL) {
952 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
953 return;
954 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500955
Pekka Paalanende685b82012-12-04 15:58:12 +0200956 if (es->buffer_ref.buffer &&
957 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400958 pixman_region32_fini(&output->cursor_plane.damage);
959 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400960 output->current_cursor ^= 1;
961 bo = output->cursor_bo[output->current_cursor];
962 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200963 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
964 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400965 for (i = 0; i < es->geometry.height; i++)
966 memcpy(buf + i * 64, s + i * stride,
967 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500968
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400969 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300970 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400971
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400972 handle = gbm_bo_get_handle(bo).s32;
973 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500974 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300975 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500976 c->cursors_are_broken = 1;
977 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400978 }
979
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400980 x = es->geometry.x - output->base.x;
981 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400982 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500983 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400984 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500985 c->cursors_are_broken = 1;
986 }
987
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400988 output->cursor_plane.x = x;
989 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400990 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500991}
992
Jesse Barnes58ef3792012-02-23 09:45:49 -0500993static void
994drm_assign_planes(struct weston_output *output)
995{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400996 struct drm_compositor *c =
997 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400998 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500999 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001000 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001001
1002 /*
1003 * Find a surface for each sprite in the output using some heuristics:
1004 * 1) size
1005 * 2) frequency of update
1006 * 3) opacity (though some hw might support alpha blending)
1007 * 4) clipping (this can be fixed with color keys)
1008 *
1009 * The idea is to save on blitting since this should save power.
1010 * If we can get a large video surface on the sprite for example,
1011 * the main display surface may not need to update at all, and
1012 * the client buffer can be used directly for the sprite surface
1013 * as we do for flipping full screen surfaces.
1014 */
1015 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001016 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001017 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001018 /* test whether this buffer can ever go into a plane:
1019 * non-shm, or small enough to be a cursor
1020 */
1021 if ((es->buffer_ref.buffer &&
1022 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1023 (es->geometry.width <= 64 && es->geometry.height <= 64))
1024 es->keep_buffer = 1;
1025 else
1026 es->keep_buffer = 0;
1027
Jesse Barnes58ef3792012-02-23 09:45:49 -05001028 pixman_region32_init(&surface_overlap);
1029 pixman_region32_intersect(&surface_overlap, &overlap,
1030 &es->transform.boundingbox);
1031
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001032 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001033 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001034 next_plane = primary;
1035 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001036 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001037 if (next_plane == NULL)
1038 next_plane = drm_output_prepare_scanout_surface(output, es);
1039 if (next_plane == NULL)
1040 next_plane = drm_output_prepare_overlay_surface(output, es);
1041 if (next_plane == NULL)
1042 next_plane = primary;
1043 weston_surface_move_to_plane(es, next_plane);
1044 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001045 pixman_region32_union(&overlap, &overlap,
1046 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001047
Jesse Barnes58ef3792012-02-23 09:45:49 -05001048 pixman_region32_fini(&surface_overlap);
1049 }
1050 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001051}
1052
Matt Roper361d2ad2011-08-29 13:52:23 -07001053static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001054drm_output_fini_pixman(struct drm_output *output);
1055
1056static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001057drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001058{
1059 struct drm_output *output = (struct drm_output *) output_base;
1060 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001061 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001062 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001063
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001064 if (output->backlight)
1065 backlight_destroy(output->backlight);
1066
Matt Roper361d2ad2011-08-29 13:52:23 -07001067 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001068 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001069
1070 /* Restore original CRTC state */
1071 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001072 origcrtc->x, origcrtc->y,
1073 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001074 drmModeFreeCrtc(origcrtc);
1075
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001076 c->crtc_allocator &= ~(1 << output->crtc_id);
1077 c->connector_allocator &= ~(1 << output->connector_id);
1078
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001079 if (c->use_pixman) {
1080 drm_output_fini_pixman(output);
1081 } else {
1082 gl_renderer_output_destroy(output_base);
1083 gbm_surface_destroy(output->surface);
1084 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001085
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001086 weston_plane_release(&output->fb_plane);
1087 weston_plane_release(&output->cursor_plane);
1088
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001089 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001090 wl_list_remove(&output->base.link);
1091
Matt Roper361d2ad2011-08-29 13:52:23 -07001092 free(output);
1093}
1094
Alex Wub7b8bda2012-04-17 17:20:48 +08001095static struct drm_mode *
1096choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1097{
1098 struct drm_mode *tmp_mode = NULL, *mode;
1099
1100 if (output->base.current->width == target_mode->width &&
1101 output->base.current->height == target_mode->height &&
1102 (output->base.current->refresh == target_mode->refresh ||
1103 target_mode->refresh == 0))
1104 return (struct drm_mode *)output->base.current;
1105
1106 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1107 if (mode->mode_info.hdisplay == target_mode->width &&
1108 mode->mode_info.vdisplay == target_mode->height) {
1109 if (mode->mode_info.vrefresh == target_mode->refresh ||
1110 target_mode->refresh == 0) {
1111 return mode;
1112 } else if (!tmp_mode)
1113 tmp_mode = mode;
1114 }
1115 }
1116
1117 return tmp_mode;
1118}
1119
1120static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001121drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001122static int
1123drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001124
1125static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001126drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1127{
1128 struct drm_output *output;
1129 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001130 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001131
1132 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001133 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001134 return -1;
1135 }
1136
1137 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001138 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001139 return -1;
1140 }
1141
1142 ec = (struct drm_compositor *)output_base->compositor;
1143 output = (struct drm_output *)output_base;
1144 drm_mode = choose_mode (output, mode);
1145
1146 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001147 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001148 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001149 }
1150
1151 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001152 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001153
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001154 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001155
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001156 output->base.current = &drm_mode->base;
1157 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001158 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1159
Alex Wub7b8bda2012-04-17 17:20:48 +08001160 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001161 drm_output_release_fb(output, output->current);
1162 drm_output_release_fb(output, output->next);
1163 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001164
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001165 if (ec->use_pixman) {
1166 drm_output_fini_pixman(output);
1167 if (drm_output_init_pixman(output, ec) < 0) {
1168 weston_log("failed to init output pixman state with "
1169 "new mode\n");
1170 return -1;
1171 }
1172 } else {
1173 gl_renderer_output_destroy(&output->base);
1174 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001175
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001176 if (drm_output_init_egl(output, ec) < 0) {
1177 weston_log("failed to init output egl state with "
1178 "new mode");
1179 return -1;
1180 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001181 }
1182
Alex Wub7b8bda2012-04-17 17:20:48 +08001183 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001184}
1185
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001186static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001187on_drm_input(int fd, uint32_t mask, void *data)
1188{
1189 drmEventContext evctx;
1190
1191 memset(&evctx, 0, sizeof evctx);
1192 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1193 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001194 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001195 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001196
1197 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001198}
1199
1200static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001201init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001202{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001203 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001204 uint64_t cap;
1205 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001206
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001207 sysnum = udev_device_get_sysnum(device);
1208 if (sysnum)
1209 ec->drm.id = atoi(sysnum);
1210 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001211 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001212 return -1;
1213 }
1214
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001215 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001216 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001217 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001218 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001219 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001220 udev_device_get_devnode(device));
1221 return -1;
1222 }
1223
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001224 weston_log("using %s\n", filename);
1225
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001226 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001227
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001228 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1229 if (ret == 0 && cap == 1)
1230 ec->clock = CLOCK_MONOTONIC;
1231 else
1232 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001233
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001234 return 0;
1235}
1236
1237static int
1238init_egl(struct drm_compositor *ec)
1239{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001240 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001241
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001242 if (!ec->gbm)
1243 return -1;
1244
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001245 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001246 NULL) < 0) {
1247 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001248 return -1;
1249 }
1250
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001251 return 0;
1252}
1253
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001254static int
1255init_pixman(struct drm_compositor *ec)
1256{
1257 return pixman_renderer_init(&ec->base);
1258}
1259
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001260static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001261drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1262{
1263 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001264 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001265
1266 mode = malloc(sizeof *mode);
1267 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001268 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001269
1270 mode->base.flags = 0;
1271 mode->base.width = info->hdisplay;
1272 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001273
1274 /* Calculate higher precision (mHz) refresh rate */
1275 refresh = (info->clock * 1000000LL / info->htotal +
1276 info->vtotal / 2) / info->vtotal;
1277
1278 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1279 refresh *= 2;
1280 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1281 refresh /= 2;
1282 if (info->vscan > 1)
1283 refresh /= info->vscan;
1284
1285 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001286 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001287
1288 if (info->type & DRM_MODE_TYPE_PREFERRED)
1289 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1290
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001291 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1292
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001293 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001294}
1295
1296static int
1297drm_subpixel_to_wayland(int drm_value)
1298{
1299 switch (drm_value) {
1300 default:
1301 case DRM_MODE_SUBPIXEL_UNKNOWN:
1302 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1303 case DRM_MODE_SUBPIXEL_NONE:
1304 return WL_OUTPUT_SUBPIXEL_NONE;
1305 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1306 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1307 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1308 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1309 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1310 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1311 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1312 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1313 }
1314}
1315
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001316/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001317static uint32_t
1318drm_get_backlight(struct drm_output *output)
1319{
1320 long brightness, max_brightness, norm;
1321
1322 brightness = backlight_get_brightness(output->backlight);
1323 max_brightness = backlight_get_max_brightness(output->backlight);
1324
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001325 /* convert it on a scale of 0 to 255 */
1326 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001327
1328 return (uint32_t) norm;
1329}
1330
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001331/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001332static void
1333drm_set_backlight(struct weston_output *output_base, uint32_t value)
1334{
1335 struct drm_output *output = (struct drm_output *) output_base;
1336 long max_brightness, new_brightness;
1337
1338 if (!output->backlight)
1339 return;
1340
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001341 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001342 return;
1343
1344 max_brightness = backlight_get_max_brightness(output->backlight);
1345
1346 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001347 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001348
1349 backlight_set_brightness(output->backlight, new_brightness);
1350}
1351
1352static drmModePropertyPtr
1353drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1354{
1355 drmModePropertyPtr props;
1356 int i;
1357
1358 for (i = 0; i < connector->count_props; i++) {
1359 props = drmModeGetProperty(fd, connector->props[i]);
1360 if (!props)
1361 continue;
1362
1363 if (!strcmp(props->name, name))
1364 return props;
1365
1366 drmModeFreeProperty(props);
1367 }
1368
1369 return NULL;
1370}
1371
1372static void
1373drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1374{
1375 struct drm_output *output = (struct drm_output *) output_base;
1376 struct weston_compositor *ec = output_base->compositor;
1377 struct drm_compositor *c = (struct drm_compositor *) ec;
1378 drmModeConnectorPtr connector;
1379 drmModePropertyPtr prop;
1380
1381 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1382 if (!connector)
1383 return;
1384
1385 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1386 if (!prop) {
1387 drmModeFreeConnector(connector);
1388 return;
1389 }
1390
1391 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1392 prop->prop_id, level);
1393 drmModeFreeProperty(prop);
1394 drmModeFreeConnector(connector);
1395}
1396
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001397static const char *connector_type_names[] = {
1398 "None",
1399 "VGA",
1400 "DVI",
1401 "DVI",
1402 "DVI",
1403 "Composite",
1404 "TV",
1405 "LVDS",
1406 "CTV",
1407 "DIN",
1408 "DP",
1409 "HDMI",
1410 "HDMI",
1411 "TV",
1412 "eDP",
1413};
1414
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001415static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001416find_crtc_for_connector(struct drm_compositor *ec,
1417 drmModeRes *resources, drmModeConnector *connector)
1418{
1419 drmModeEncoder *encoder;
1420 uint32_t possible_crtcs;
1421 int i, j;
1422
1423 for (j = 0; j < connector->count_encoders; j++) {
1424 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1425 if (encoder == NULL) {
1426 weston_log("Failed to get encoder.\n");
1427 return -1;
1428 }
1429 possible_crtcs = encoder->possible_crtcs;
1430 drmModeFreeEncoder(encoder);
1431
1432 for (i = 0; i < resources->count_crtcs; i++) {
1433 if (possible_crtcs & (1 << i) &&
1434 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1435 return i;
1436 }
1437 }
1438
1439 return -1;
1440}
1441
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001442/* Init output state that depends on gl or gbm */
1443static int
1444drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1445{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001446 int i, flags;
1447
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001448 output->surface = gbm_surface_create(ec->gbm,
1449 output->base.current->width,
1450 output->base.current->height,
1451 GBM_FORMAT_XRGB8888,
1452 GBM_BO_USE_SCANOUT |
1453 GBM_BO_USE_RENDERING);
1454 if (!output->surface) {
1455 weston_log("failed to create gbm surface\n");
1456 return -1;
1457 }
1458
1459 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001460 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001461 gbm_surface_destroy(output->surface);
1462 return -1;
1463 }
1464
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001465 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1466
1467 for (i = 0; i < 2; i++) {
1468 if (output->cursor_bo[i])
1469 continue;
1470
1471 output->cursor_bo[i] =
1472 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1473 flags);
1474 }
1475
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001476 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1477 weston_log("cursor buffers unavailable, using gl cursors\n");
1478 ec->cursors_are_broken = 1;
1479 }
1480
1481 return 0;
1482}
1483
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001484static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001485drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1486{
1487 int w = output->base.current->width;
1488 int h = output->base.current->height;
1489 unsigned int i;
1490
1491 /* FIXME error checking */
1492
1493 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1494 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1495 if (!output->dumb[i])
1496 goto err;
1497
1498 output->image[i] =
1499 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1500 output->dumb[i]->map,
1501 output->dumb[i]->stride);
1502 if (!output->image[i])
1503 goto err;
1504 }
1505
1506 if (pixman_renderer_output_create(&output->base) < 0)
1507 goto err;
1508
1509 pixman_region32_init_rect(&output->previous_damage,
1510 output->base.x, output->base.y, w, h);
1511
1512 return 0;
1513
1514err:
1515 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1516 if (output->dumb[i])
1517 drm_fb_destroy_dumb(output->dumb[i]);
1518 if (output->image[i])
1519 pixman_image_unref(output->image[i]);
1520
1521 output->dumb[i] = NULL;
1522 output->image[i] = NULL;
1523 }
1524
1525 return -1;
1526}
1527
1528static void
1529drm_output_fini_pixman(struct drm_output *output)
1530{
1531 unsigned int i;
1532
1533 pixman_renderer_output_destroy(&output->base);
1534 pixman_region32_fini(&output->previous_damage);
1535
1536 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1537 drm_fb_destroy_dumb(output->dumb[i]);
1538 pixman_image_unref(output->image[i]);
1539 output->dumb[i] = NULL;
1540 output->image[i] = NULL;
1541 }
1542}
1543
Richard Hughes2b2092a2013-04-24 14:58:02 +01001544static void
1545edid_parse_string(const uint8_t *data, char text[])
1546{
1547 int i;
1548 int replaced = 0;
1549
1550 /* this is always 12 bytes, but we can't guarantee it's null
1551 * terminated or not junk. */
1552 strncpy(text, (const char *) data, 12);
1553
1554 /* remove insane chars */
1555 for (i = 0; text[i] != '\0'; i++) {
1556 if (text[i] == '\n' ||
1557 text[i] == '\r') {
1558 text[i] = '\0';
1559 break;
1560 }
1561 }
1562
1563 /* ensure string is printable */
1564 for (i = 0; text[i] != '\0'; i++) {
1565 if (!isprint(text[i])) {
1566 text[i] = '-';
1567 replaced++;
1568 }
1569 }
1570
1571 /* if the string is random junk, ignore the string */
1572 if (replaced > 4)
1573 text[0] = '\0';
1574}
1575
1576#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1577#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1578#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1579#define EDID_OFFSET_DATA_BLOCKS 0x36
1580#define EDID_OFFSET_LAST_BLOCK 0x6c
1581#define EDID_OFFSET_PNPID 0x08
1582#define EDID_OFFSET_SERIAL 0x0c
1583
1584static int
1585edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1586{
1587 int i;
1588 uint32_t serial_number;
1589
1590 /* check header */
1591 if (length < 128)
1592 return -1;
1593 if (data[0] != 0x00 || data[1] != 0xff)
1594 return -1;
1595
1596 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1597 * /--08--\/--09--\
1598 * 7654321076543210
1599 * |\---/\---/\---/
1600 * R C1 C2 C3 */
1601 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1602 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1603 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1604 edid->pnp_id[3] = '\0';
1605
1606 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1607 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1608 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1609 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1610 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1611 if (serial_number > 0)
1612 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1613
1614 /* parse EDID data */
1615 for (i = EDID_OFFSET_DATA_BLOCKS;
1616 i <= EDID_OFFSET_LAST_BLOCK;
1617 i += 18) {
1618 /* ignore pixel clock data */
1619 if (data[i] != 0)
1620 continue;
1621 if (data[i+2] != 0)
1622 continue;
1623
1624 /* any useful blocks? */
1625 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1626 edid_parse_string(&data[i+5],
1627 edid->monitor_name);
1628 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1629 edid_parse_string(&data[i+5],
1630 edid->serial_number);
1631 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1632 edid_parse_string(&data[i+5],
1633 edid->eisa_id);
1634 }
1635 }
1636 return 0;
1637}
1638
1639static void
1640find_and_parse_output_edid(struct drm_compositor *ec,
1641 struct drm_output *output,
1642 drmModeConnector *connector)
1643{
1644 drmModePropertyBlobPtr edid_blob = NULL;
1645 drmModePropertyPtr property;
1646 int i;
1647 int rc;
1648
1649 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1650 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1651 if (!property)
1652 continue;
1653 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1654 !strcmp(property->name, "EDID")) {
1655 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1656 connector->prop_values[i]);
1657 }
1658 drmModeFreeProperty(property);
1659 }
1660 if (!edid_blob)
1661 return;
1662
1663 rc = edid_parse(&output->edid,
1664 edid_blob->data,
1665 edid_blob->length);
1666 if (!rc) {
1667 weston_log("EDID data '%s', '%s', '%s'\n",
1668 output->edid.pnp_id,
1669 output->edid.monitor_name,
1670 output->edid.serial_number);
1671 if (output->edid.pnp_id[0] != '\0')
1672 output->base.make = output->edid.pnp_id;
1673 if (output->edid.monitor_name[0] != '\0')
1674 output->base.model = output->edid.monitor_name;
1675 if (output->edid.serial_number[0] != '\0')
1676 output->base.serial_number = output->edid.serial_number;
1677 }
1678 drmModeFreePropertyBlob(edid_blob);
1679}
1680
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001681static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001682create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001683 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001684 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001685 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001686{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001687 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001688 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1689 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001690 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001691 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001692 drmModeModeInfo crtc_mode;
1693 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001694 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001695 char name[32];
1696 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001697
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001698 i = find_crtc_for_connector(ec, resources, connector);
1699 if (i < 0) {
1700 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001701 return -1;
1702 }
1703
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001704 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001705 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001706 return -1;
1707
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001708 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001709 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1710 output->base.make = "unknown";
1711 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001712 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001713 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001714
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001715 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1716 type_name = connector_type_names[connector->connector_type];
1717 else
1718 type_name = "UNKNOWN";
1719 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001720 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001721
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001722 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001723 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001724 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001725 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001726 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001727
Matt Roper361d2ad2011-08-29 13:52:23 -07001728 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1729
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001730 /* Get the current mode on the crtc that's currently driving
1731 * this connector. */
1732 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001733 memset(&crtc_mode, 0, sizeof crtc_mode);
1734 if (encoder != NULL) {
1735 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1736 drmModeFreeEncoder(encoder);
1737 if (crtc == NULL)
1738 goto err_free;
1739 if (crtc->mode_valid)
1740 crtc_mode = crtc->mode;
1741 drmModeFreeCrtc(crtc);
1742 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001743
David Herrmann0f0d54e2011-12-08 17:05:45 +01001744 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001745 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1746 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001747 goto err_free;
1748 }
1749
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001750 preferred = NULL;
1751 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001752 configured = NULL;
1753
1754 wl_list_for_each(temp, &configured_output_list, link) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001755 if (strcmp(temp->name, output->base.name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001756 if (temp->mode)
1757 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001758 temp->name, temp->mode);
1759 o = temp;
1760 break;
1761 }
1762 }
1763
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001764 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001765 weston_log("Disabling output %s\n", o->name);
1766
1767 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1768 0, 0, 0, 0, 0, NULL);
1769 goto err_free;
1770 }
1771
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001772 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001773 if (o && o->config == OUTPUT_CONFIG_MODE &&
1774 o->width == drm_mode->base.width &&
1775 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001776 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001777 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001778 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001779 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001780 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001781 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001782
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001783 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001784 configured = drm_output_add_mode(output, &o->crtc_mode);
1785 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001786 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001787 current = configured;
1788 }
1789
Wang Quanxianacb805a2012-07-30 18:09:46 -04001790 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001791 current = drm_output_add_mode(output, &crtc_mode);
1792 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001793 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001794 }
1795
Scott Moreau8ab5d452012-07-30 19:51:08 -06001796 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1797 configured = current;
1798
Wang Quanxianacb805a2012-07-30 18:09:46 -04001799 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001800 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001801 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001802 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001803 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001804 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001805 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001806 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001807
1808 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001809 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001810 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001811 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001812
Wang Quanxianacb805a2012-07-30 18:09:46 -04001813 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1814
John Kåre Alsaker94659272012-11-13 19:10:18 +01001815 weston_output_init(&output->base, &ec->base, x, y,
1816 connector->mmWidth, connector->mmHeight,
Alexander Larsson4ea95522013-05-22 14:41:37 +02001817 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL, 1);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001818
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001819 if (ec->use_pixman) {
1820 if (drm_output_init_pixman(output, ec) < 0) {
1821 weston_log("Failed to init output pixman state\n");
1822 goto err_output;
1823 }
1824 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001825 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001826 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001827 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001828
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001829 output->backlight = backlight_init(drm_device,
1830 connector->connector_type);
1831 if (output->backlight) {
1832 output->base.set_backlight = drm_set_backlight;
1833 output->base.backlight_current = drm_get_backlight(output);
1834 }
1835
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001836 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1837
Richard Hughes2b2092a2013-04-24 14:58:02 +01001838 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001839 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1840 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001841
Alex Wubd3354b2012-04-17 17:20:49 +08001842 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001843 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001844 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001845 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001846 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001847 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001848 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001849
Richard Hughese7299962013-05-01 21:52:12 +01001850 output->base.gamma_size = output->original_crtc->gamma_size;
1851 output->base.set_gamma = drm_output_set_gamma;
1852
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001853 weston_plane_init(&output->cursor_plane, 0, 0);
1854 weston_plane_init(&output->fb_plane, 0, 0);
1855
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001856 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1857 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1858 &ec->base.primary_plane);
1859
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001860 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001861 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001862 wl_list_for_each(m, &output->base.mode_list, link)
1863 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1864 m->width, m->height, m->refresh / 1000.0,
1865 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1866 ", preferred" : "",
1867 m->flags & WL_OUTPUT_MODE_CURRENT ?
1868 ", current" : "",
1869 connector->count_modes == 0 ?
1870 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001871
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001872 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001873
John Kåre Alsaker94659272012-11-13 19:10:18 +01001874err_output:
1875 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001876err_free:
1877 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1878 base.link) {
1879 wl_list_remove(&drm_mode->base.link);
1880 free(drm_mode);
1881 }
1882
1883 drmModeFreeCrtc(output->original_crtc);
1884 ec->crtc_allocator &= ~(1 << output->crtc_id);
1885 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001886 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001887
David Herrmann0f0d54e2011-12-08 17:05:45 +01001888 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001889}
1890
Jesse Barnes58ef3792012-02-23 09:45:49 -05001891static void
1892create_sprites(struct drm_compositor *ec)
1893{
1894 struct drm_sprite *sprite;
1895 drmModePlaneRes *plane_res;
1896 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001897 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001898
1899 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1900 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001901 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001902 strerror(errno));
1903 return;
1904 }
1905
1906 for (i = 0; i < plane_res->count_planes; i++) {
1907 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1908 if (!plane)
1909 continue;
1910
1911 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1912 plane->count_formats));
1913 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001914 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001915 __func__);
1916 free(plane);
1917 continue;
1918 }
1919
1920 memset(sprite, 0, sizeof *sprite);
1921
1922 sprite->possible_crtcs = plane->possible_crtcs;
1923 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001924 sprite->current = NULL;
1925 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001926 sprite->compositor = ec;
1927 sprite->count_formats = plane->count_formats;
1928 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001929 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001930 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001931 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001932 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1933 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001934
1935 wl_list_insert(&ec->sprite_list, &sprite->link);
1936 }
1937
1938 free(plane_res->planes);
1939 free(plane_res);
1940}
1941
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001942static void
1943destroy_sprites(struct drm_compositor *compositor)
1944{
1945 struct drm_sprite *sprite, *next;
1946 struct drm_output *output;
1947
1948 output = container_of(compositor->base.output_list.next,
1949 struct drm_output, base.link);
1950
1951 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1952 drmModeSetPlane(compositor->drm.fd,
1953 sprite->plane_id,
1954 output->crtc_id, 0, 0,
1955 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001956 drm_output_release_fb(output, sprite->current);
1957 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001958 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001959 free(sprite);
1960 }
1961}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001962
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001963static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001964create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001965 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001966{
1967 drmModeConnector *connector;
1968 drmModeRes *resources;
1969 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001970 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001971
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001972 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001973 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001974 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001975 return -1;
1976 }
1977
Jesse Barnes58ef3792012-02-23 09:45:49 -05001978 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001979 if (!ec->crtcs) {
1980 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001981 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001982 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001983
Rob Clark4339add2012-08-09 14:18:28 -05001984 ec->min_width = resources->min_width;
1985 ec->max_width = resources->max_width;
1986 ec->min_height = resources->min_height;
1987 ec->max_height = resources->max_height;
1988
Jesse Barnes58ef3792012-02-23 09:45:49 -05001989 ec->num_crtcs = resources->count_crtcs;
1990 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1991
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001992 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001993 connector = drmModeGetConnector(ec->drm.fd,
1994 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001995 if (connector == NULL)
1996 continue;
1997
1998 if (connector->connection == DRM_MODE_CONNECTED &&
1999 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002000 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002001 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002002 connector, x, y,
2003 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002004 drmModeFreeConnector(connector);
2005 continue;
2006 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002007
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002008 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002009 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002010 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002011 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002012
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002013 drmModeFreeConnector(connector);
2014 }
2015
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002016 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002017 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002018 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002019 return -1;
2020 }
2021
2022 drmModeFreeResources(resources);
2023
2024 return 0;
2025}
2026
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002027static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002028update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002029{
2030 drmModeConnector *connector;
2031 drmModeRes *resources;
2032 struct drm_output *output, *next;
2033 int x = 0, y = 0;
2034 int x_offset = 0, y_offset = 0;
2035 uint32_t connected = 0, disconnects = 0;
2036 int i;
2037
2038 resources = drmModeGetResources(ec->drm.fd);
2039 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002040 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002041 return;
2042 }
2043
2044 /* collect new connects */
2045 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002046 int connector_id = resources->connectors[i];
2047
2048 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002049 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002050 continue;
2051
David Herrmann7551cff2011-12-08 17:05:43 +01002052 if (connector->connection != DRM_MODE_CONNECTED) {
2053 drmModeFreeConnector(connector);
2054 continue;
2055 }
2056
Benjamin Franzke117483d2011-08-30 11:38:26 +02002057 connected |= (1 << connector_id);
2058
2059 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002060 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002061 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002062 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002063
2064 /* XXX: not yet needed, we die with 0 outputs */
2065 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002066 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002067 else
2068 x = 0;
2069 y = 0;
2070 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002071 connector, x, y,
2072 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002073 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002074
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002075 }
2076 drmModeFreeConnector(connector);
2077 }
2078 drmModeFreeResources(resources);
2079
2080 disconnects = ec->connector_allocator & ~connected;
2081 if (disconnects) {
2082 wl_list_for_each_safe(output, next, &ec->base.output_list,
2083 base.link) {
2084 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002085 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002086 output->base.x - x_offset,
2087 output->base.y - y_offset);
2088 }
2089
2090 if (disconnects & (1 << output->connector_id)) {
2091 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002092 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002093 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002094 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002095 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002096 }
2097 }
2098 }
2099
2100 /* FIXME: handle zero outputs, without terminating */
2101 if (ec->connector_allocator == 0)
2102 wl_display_terminate(ec->base.wl_display);
2103}
2104
2105static int
David Herrmannd7488c22012-03-11 20:05:21 +01002106udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002107{
David Herrmannd7488c22012-03-11 20:05:21 +01002108 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002109 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002110
2111 sysnum = udev_device_get_sysnum(device);
2112 if (!sysnum || atoi(sysnum) != ec->drm.id)
2113 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002114
David Herrmann6ac52db2012-03-11 20:05:22 +01002115 val = udev_device_get_property_value(device, "HOTPLUG");
2116 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002117 return 0;
2118
David Herrmann6ac52db2012-03-11 20:05:22 +01002119 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002120}
2121
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002122static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002123udev_drm_event(int fd, uint32_t mask, void *data)
2124{
2125 struct drm_compositor *ec = data;
2126 struct udev_device *event;
2127
2128 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002129
David Herrmannd7488c22012-03-11 20:05:21 +01002130 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002131 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002132
2133 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002134
2135 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002136}
2137
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002138static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002139drm_restore(struct weston_compositor *ec)
2140{
2141 struct drm_compositor *d = (struct drm_compositor *) ec;
2142
2143 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2144 weston_log("failed to drop master: %m\n");
2145 tty_reset(d->tty);
2146}
2147
2148static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002149drm_free_configured_output(struct drm_configured_output *output)
2150{
2151 free(output->name);
2152 free(output->mode);
2153 free(output);
2154}
2155
2156static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002157drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002158{
2159 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002160 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002161 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002162
Kristian Høgsberge8091032013-02-18 15:43:29 -05002163 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2164 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002165 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002166 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002167
2168 wl_event_source_remove(d->udev_drm_source);
2169 wl_event_source_remove(d->drm_source);
2170
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002171 destroy_sprites(d);
2172
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002173 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002174
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002175 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002176
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002177 if (d->gbm)
2178 gbm_device_destroy(d->gbm);
2179
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002180 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002181 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002182 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002183
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002184 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002185}
2186
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002187static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002188drm_compositor_set_modes(struct drm_compositor *compositor)
2189{
2190 struct drm_output *output;
2191 struct drm_mode *drm_mode;
2192 int ret;
2193
2194 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002195 if (!output->current) {
2196 /* If something that would cause the output to
2197 * switch mode happened while in another vt, we
2198 * might not have a current drm_fb. In that case,
2199 * schedule a repaint and let drm_output_repaint
2200 * handle setting the mode. */
2201 weston_output_schedule_repaint(&output->base);
2202 continue;
2203 }
2204
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002205 drm_mode = (struct drm_mode *) output->base.current;
2206 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002207 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002208 &output->connector_id, 1,
2209 &drm_mode->mode_info);
2210 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002211 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002212 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002213 drm_mode->base.width, drm_mode->base.height,
2214 output->base.x, output->base.y);
2215 }
2216 }
2217}
2218
2219static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002220vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002221{
2222 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002223 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002224 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002225 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002226
2227 switch (event) {
2228 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002229 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002230 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002231 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002232 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002233 wl_display_terminate(compositor->wl_display);
2234 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002235 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002236 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002237 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002238 wl_list_for_each(seat, &compositor->seat_list, base.link)
2239 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002240 break;
2241 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002242 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002243 wl_list_for_each(seat, &compositor->seat_list, base.link)
2244 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002245
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002246 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002247 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002248 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002249
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002250 /* If we have a repaint scheduled (either from a
2251 * pending pageflip or the idle handler), make sure we
2252 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002253 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002254 * further attemps at repainting. When we switch
2255 * back, we schedule a repaint, which will process
2256 * pending frame callbacks. */
2257
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002258 wl_list_for_each(output, &ec->base.output_list, base.link) {
2259 output->base.repaint_needed = 0;
2260 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002261 }
2262
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002263 output = container_of(ec->base.output_list.next,
2264 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002265
2266 wl_list_for_each(sprite, &ec->sprite_list, link)
2267 drmModeSetPlane(ec->drm.fd,
2268 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002269 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002270 0, 0, 0, 0, 0, 0, 0, 0);
2271
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002272 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002273 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002274
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002275 break;
2276 };
2277}
2278
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002279static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002280switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002281{
2282 struct drm_compositor *ec = data;
2283
Daniel Stone325fc2d2012-05-30 16:31:58 +01002284 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002285}
2286
David Herrmann0af066f2012-10-29 19:21:16 +01002287/*
2288 * Find primary GPU
2289 * Some systems may have multiple DRM devices attached to a single seat. This
2290 * function loops over all devices and tries to find a PCI device with the
2291 * boot_vga sysfs attribute set to 1.
2292 * If no such device is found, the first DRM device reported by udev is used.
2293 */
2294static struct udev_device*
2295find_primary_gpu(struct drm_compositor *ec, const char *seat)
2296{
2297 struct udev_enumerate *e;
2298 struct udev_list_entry *entry;
2299 const char *path, *device_seat, *id;
2300 struct udev_device *device, *drm_device, *pci;
2301
2302 e = udev_enumerate_new(ec->udev);
2303 udev_enumerate_add_match_subsystem(e, "drm");
2304 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2305
2306 udev_enumerate_scan_devices(e);
2307 drm_device = NULL;
2308 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2309 path = udev_list_entry_get_name(entry);
2310 device = udev_device_new_from_syspath(ec->udev, path);
2311 if (!device)
2312 continue;
2313 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2314 if (!device_seat)
2315 device_seat = default_seat;
2316 if (strcmp(device_seat, seat)) {
2317 udev_device_unref(device);
2318 continue;
2319 }
2320
2321 pci = udev_device_get_parent_with_subsystem_devtype(device,
2322 "pci", NULL);
2323 if (pci) {
2324 id = udev_device_get_sysattr_value(pci, "boot_vga");
2325 if (id && !strcmp(id, "1")) {
2326 if (drm_device)
2327 udev_device_unref(drm_device);
2328 drm_device = device;
2329 break;
2330 }
2331 }
2332
2333 if (!drm_device)
2334 drm_device = device;
2335 else
2336 udev_device_unref(device);
2337 }
2338
2339 udev_enumerate_unref(e);
2340 return drm_device;
2341}
2342
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002343static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002344planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002345{
2346 struct drm_compositor *c = data;
2347
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002348 switch (key) {
2349 case KEY_C:
2350 c->cursors_are_broken ^= 1;
2351 break;
2352 case KEY_V:
2353 c->sprites_are_broken ^= 1;
2354 break;
2355 case KEY_O:
2356 c->sprites_hidden ^= 1;
2357 break;
2358 default:
2359 break;
2360 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002361}
2362
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002363static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002364drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002365 int connector, const char *seat, int tty, int pixman,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002366 int *argc, char *argv[], int config_fd)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002367{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002368 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002369 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002370 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002371 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002372 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002373 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002374
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002375 weston_log("initializing drm backend\n");
2376
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002377 ec = malloc(sizeof *ec);
2378 if (ec == NULL)
2379 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002380 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002381
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002382 /* KMS support for sprites is not complete yet, so disable the
2383 * functionality for now. */
2384 ec->sprites_are_broken = 1;
2385
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002386 ec->use_pixman = pixman;
2387
Daniel Stone725c2c32012-06-22 14:04:36 +01002388 if (weston_compositor_init(&ec->base, display, argc, argv,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002389 config_fd) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002390 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002391 goto err_base;
2392 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002393
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002394 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002395 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002396 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002397 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002398 goto err_compositor;
2399 }
2400
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002401 ec->udev = udev_new();
2402 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002403 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002404 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002405 }
2406
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002407 ec->base.wl_display = display;
2408 ec->tty = tty_create(&ec->base, vt_func, tty);
2409 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002410 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002411 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002412 }
2413
David Herrmann0af066f2012-10-29 19:21:16 +01002414 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002415 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002416 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002417 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002418 }
David Herrmann0af066f2012-10-29 19:21:16 +01002419 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002420
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002421 if (init_drm(ec, drm_device) < 0) {
2422 weston_log("failed to initialize kms\n");
2423 goto err_udev_dev;
2424 }
2425
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002426 if (ec->use_pixman) {
2427 if (init_pixman(ec) < 0) {
2428 weston_log("failed to initialize pixman renderer\n");
2429 goto err_udev_dev;
2430 }
2431 } else {
2432 if (init_egl(ec) < 0) {
2433 weston_log("failed to initialize egl\n");
2434 goto err_udev_dev;
2435 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002436 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002437
2438 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002439 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002440
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002441 ec->base.focus = 1;
2442
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002443 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002444
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002445 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002446 weston_compositor_add_key_binding(&ec->base, key,
2447 MODIFIER_CTRL | MODIFIER_ALT,
2448 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002449
Jesse Barnes58ef3792012-02-23 09:45:49 -05002450 wl_list_init(&ec->sprite_list);
2451 create_sprites(ec);
2452
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002453 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002454 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002455 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002456 }
2457
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002458 path = NULL;
2459
Kristian Høgsberge8091032013-02-18 15:43:29 -05002460 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002461 weston_log("failed to create input devices\n");
2462 goto err_sprite;
2463 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002464
2465 loop = wl_display_get_event_loop(ec->base.wl_display);
2466 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002467 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002468 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002469
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002470 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2471 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002472 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002473 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002474 }
2475 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2476 "drm", NULL);
2477 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002478 wl_event_loop_add_fd(loop,
2479 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002480 WL_EVENT_READABLE, udev_drm_event, ec);
2481
2482 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002483 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002484 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002485 }
2486
Daniel Stonea96b93c2012-06-22 14:04:37 +01002487 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002488
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002489 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002490 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002491 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002492 planes_binding, ec);
2493 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2494 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002495
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002496 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002497
2498err_udev_monitor:
2499 wl_event_source_remove(ec->udev_drm_source);
2500 udev_monitor_unref(ec->udev_monitor);
2501err_drm_source:
2502 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002503 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2504 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002505err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002506 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002507 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002508 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002509err_udev_dev:
2510 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002511err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002512 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2513 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002514 tty_destroy(ec->tty);
2515err_udev:
2516 udev_unref(ec->udev);
2517err_compositor:
2518 weston_compositor_shutdown(&ec->base);
2519err_base:
2520 free(ec);
2521 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002522}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002523
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002524static int
2525set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2526{
2527 mode->flags = 0;
2528
2529 if (strcmp(hsync, "+hsync") == 0)
2530 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2531 else if (strcmp(hsync, "-hsync") == 0)
2532 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2533 else
2534 return -1;
2535
2536 if (strcmp(vsync, "+vsync") == 0)
2537 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2538 else if (strcmp(vsync, "-vsync") == 0)
2539 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2540 else
2541 return -1;
2542
2543 return 0;
2544}
2545
2546static int
2547check_for_modeline(struct drm_configured_output *output)
2548{
2549 drmModeModeInfo mode;
2550 char hsync[16];
2551 char vsync[16];
2552 char mode_name[16];
2553 float fclock;
2554
2555 mode.type = DRM_MODE_TYPE_USERDEF;
2556 mode.hskew = 0;
2557 mode.vscan = 0;
2558 mode.vrefresh = 0;
2559
2560 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2561 &fclock, &mode.hdisplay,
2562 &mode.hsync_start,
2563 &mode.hsync_end, &mode.htotal,
2564 &mode.vdisplay,
2565 &mode.vsync_start,
2566 &mode.vsync_end, &mode.vtotal,
2567 hsync, vsync) == 11) {
2568 if (set_sync_flags(&mode, hsync, vsync))
2569 return -1;
2570
2571 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2572 strcpy(mode.name, mode_name);
2573
2574 mode.clock = fclock * 1000;
2575 } else
2576 return -1;
2577
2578 output->crtc_mode = mode;
2579
2580 return 0;
2581}
2582
Scott Moreau8ab5d452012-07-30 19:51:08 -06002583static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002584drm_output_set_transform(struct drm_configured_output *output)
2585{
2586 if (!output_transform) {
2587 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2588 return;
2589 }
2590
2591 if (!strcmp(output_transform, "normal"))
2592 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2593 else if (!strcmp(output_transform, "90"))
2594 output->transform = WL_OUTPUT_TRANSFORM_90;
2595 else if (!strcmp(output_transform, "180"))
2596 output->transform = WL_OUTPUT_TRANSFORM_180;
2597 else if (!strcmp(output_transform, "270"))
2598 output->transform = WL_OUTPUT_TRANSFORM_270;
2599 else if (!strcmp(output_transform, "flipped"))
2600 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2601 else if (!strcmp(output_transform, "flipped-90"))
2602 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2603 else if (!strcmp(output_transform, "flipped-180"))
2604 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2605 else if (!strcmp(output_transform, "flipped-270"))
2606 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2607 else {
2608 weston_log("Invalid transform \"%s\" for output %s\n",
2609 output_transform, output_name);
2610 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2611 }
2612
2613 free(output_transform);
2614 output_transform = NULL;
2615}
2616
2617static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002618output_section_done(void *data)
2619{
2620 struct drm_configured_output *output;
2621
2622 output = malloc(sizeof *output);
2623
Scott Moreau1bad5db2012-08-18 01:04:05 -06002624 if (!output || !output_name || (output_name[0] == 'X') ||
2625 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002626 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002627 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002628 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002629 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002630 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002631 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002632 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002633 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002634 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002635
2636 output->config = OUTPUT_CONFIG_INVALID;
2637 output->name = output_name;
2638 output->mode = output_mode;
2639
Scott Moreau1bad5db2012-08-18 01:04:05 -06002640 if (output_mode) {
2641 if (strcmp(output_mode, "off") == 0)
2642 output->config = OUTPUT_CONFIG_OFF;
2643 else if (strcmp(output_mode, "preferred") == 0)
2644 output->config = OUTPUT_CONFIG_PREFERRED;
2645 else if (strcmp(output_mode, "current") == 0)
2646 output->config = OUTPUT_CONFIG_CURRENT;
2647 else if (sscanf(output_mode, "%dx%d",
2648 &output->width, &output->height) == 2)
2649 output->config = OUTPUT_CONFIG_MODE;
2650 else if (check_for_modeline(output) == 0)
2651 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002652
Scott Moreau1bad5db2012-08-18 01:04:05 -06002653 if (output->config == OUTPUT_CONFIG_INVALID)
2654 weston_log("Invalid mode \"%s\" for output %s\n",
2655 output_mode, output_name);
2656 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002657 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002658
2659 drm_output_set_transform(output);
2660
2661 wl_list_insert(&configured_output_list, &output->link);
2662
2663 if (output_transform)
2664 free(output_transform);
2665 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002666}
2667
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002668WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002669backend_init(struct wl_display *display, int *argc, char *argv[],
Ossama Othmana50e6e42013-05-14 09:48:26 -07002670 int config_fd)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002671{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002672 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002673 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002674
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002675 const struct weston_option drm_options[] = {
2676 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2677 { WESTON_OPTION_STRING, "seat", 0, &seat },
2678 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002679 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002680 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002681 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002682
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002683 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002684
Scott Moreau8ab5d452012-07-30 19:51:08 -06002685 wl_list_init(&configured_output_list);
2686
2687 const struct config_key drm_config_keys[] = {
2688 { "name", CONFIG_KEY_STRING, &output_name },
2689 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002690 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002691 };
2692
2693 const struct config_section config_section[] = {
2694 { "output", drm_config_keys,
2695 ARRAY_LENGTH(drm_config_keys), output_section_done },
2696 };
2697
Ossama Othmana50e6e42013-05-14 09:48:26 -07002698 parse_config_file(config_fd, config_section,
Scott Moreau8ab5d452012-07-30 19:51:08 -06002699 ARRAY_LENGTH(config_section), NULL);
2700
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002701 return drm_compositor_create(display, connector, seat, tty, use_pixman,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002702 argc, argv, config_fd);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002703}