blob: 9dce80928ad4fb466e6b364b0f3162c4a778bcee [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,
861 output_base->transform, *box);
862 s->dest_x = tbox.x1;
863 s->dest_y = tbox.y1;
864 s->dest_w = tbox.x2 - tbox.x1;
865 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500866 pixman_region32_fini(&dest_rect);
867
868 pixman_region32_init(&src_rect);
869 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
870 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500871 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400872
873 weston_surface_from_global_fixed(es,
874 wl_fixed_from_int(box->x1),
875 wl_fixed_from_int(box->y1),
876 &sx1, &sy1);
877 weston_surface_from_global_fixed(es,
878 wl_fixed_from_int(box->x2),
879 wl_fixed_from_int(box->y2),
880 &sx2, &sy2);
881
882 if (sx1 < 0)
883 sx1 = 0;
884 if (sy1 < 0)
885 sy1 = 0;
886 if (sx2 > wl_fixed_from_int(es->geometry.width))
887 sx2 = wl_fixed_from_int(es->geometry.width);
888 if (sy2 > wl_fixed_from_int(es->geometry.height))
889 sy2 = wl_fixed_from_int(es->geometry.height);
890
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200891 tbox.x1 = sx1;
892 tbox.y1 = sy1;
893 tbox.x2 = sx2;
894 tbox.y2 = sy2;
895
896 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
897 wl_fixed_from_int(es->geometry.height),
898 es->buffer_transform, tbox);
899
900 s->src_x = tbox.x1 << 8;
901 s->src_y = tbox.y1 << 8;
902 s->src_w = (tbox.x2 - tbox.x1) << 8;
903 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500904 pixman_region32_fini(&src_rect);
905
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400906 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500907}
908
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400909static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400910drm_output_prepare_cursor_surface(struct weston_output *output_base,
911 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500912{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400913 struct drm_compositor *c =
914 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400915 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400916
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200917 if (c->gbm == NULL)
918 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200919 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
920 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400921 if (output->cursor_surface)
922 return NULL;
923 if (es->output_mask != (1u << output_base->id))
924 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500925 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400926 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200927 if (es->buffer_ref.buffer == NULL ||
928 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400929 es->geometry.width > 64 || es->geometry.height > 64)
930 return NULL;
931
932 output->cursor_surface = es;
933
934 return &output->cursor_plane;
935}
936
937static void
938drm_output_set_cursor(struct drm_output *output)
939{
940 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400941 struct drm_compositor *c =
942 (struct drm_compositor *) output->base.compositor;
943 EGLint handle, stride;
944 struct gbm_bo *bo;
945 uint32_t buf[64 * 64];
946 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400947 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500948
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400949 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400950 if (es == NULL) {
951 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
952 return;
953 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500954
Pekka Paalanende685b82012-12-04 15:58:12 +0200955 if (es->buffer_ref.buffer &&
956 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400957 pixman_region32_fini(&output->cursor_plane.damage);
958 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400959 output->current_cursor ^= 1;
960 bo = output->cursor_bo[output->current_cursor];
961 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200962 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
963 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400964 for (i = 0; i < es->geometry.height; i++)
965 memcpy(buf + i * 64, s + i * stride,
966 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500967
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400968 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300969 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400970
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400971 handle = gbm_bo_get_handle(bo).s32;
972 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500973 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300974 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500975 c->cursors_are_broken = 1;
976 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400977 }
978
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400979 x = es->geometry.x - output->base.x;
980 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400981 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500982 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400983 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500984 c->cursors_are_broken = 1;
985 }
986
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400987 output->cursor_plane.x = x;
988 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400989 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500990}
991
Jesse Barnes58ef3792012-02-23 09:45:49 -0500992static void
993drm_assign_planes(struct weston_output *output)
994{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400995 struct drm_compositor *c =
996 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400997 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500998 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400999 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001000
1001 /*
1002 * Find a surface for each sprite in the output using some heuristics:
1003 * 1) size
1004 * 2) frequency of update
1005 * 3) opacity (though some hw might support alpha blending)
1006 * 4) clipping (this can be fixed with color keys)
1007 *
1008 * The idea is to save on blitting since this should save power.
1009 * If we can get a large video surface on the sprite for example,
1010 * the main display surface may not need to update at all, and
1011 * the client buffer can be used directly for the sprite surface
1012 * as we do for flipping full screen surfaces.
1013 */
1014 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001015 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001016 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001017 /* test whether this buffer can ever go into a plane:
1018 * non-shm, or small enough to be a cursor
1019 */
1020 if ((es->buffer_ref.buffer &&
1021 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1022 (es->geometry.width <= 64 && es->geometry.height <= 64))
1023 es->keep_buffer = 1;
1024 else
1025 es->keep_buffer = 0;
1026
Jesse Barnes58ef3792012-02-23 09:45:49 -05001027 pixman_region32_init(&surface_overlap);
1028 pixman_region32_intersect(&surface_overlap, &overlap,
1029 &es->transform.boundingbox);
1030
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001031 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001032 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001033 next_plane = primary;
1034 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001035 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001036 if (next_plane == NULL)
1037 next_plane = drm_output_prepare_scanout_surface(output, es);
1038 if (next_plane == NULL)
1039 next_plane = drm_output_prepare_overlay_surface(output, es);
1040 if (next_plane == NULL)
1041 next_plane = primary;
1042 weston_surface_move_to_plane(es, next_plane);
1043 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001044 pixman_region32_union(&overlap, &overlap,
1045 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001046
Jesse Barnes58ef3792012-02-23 09:45:49 -05001047 pixman_region32_fini(&surface_overlap);
1048 }
1049 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001050}
1051
Matt Roper361d2ad2011-08-29 13:52:23 -07001052static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001053drm_output_fini_pixman(struct drm_output *output);
1054
1055static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001056drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001057{
1058 struct drm_output *output = (struct drm_output *) output_base;
1059 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001060 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001061 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001062
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001063 if (output->backlight)
1064 backlight_destroy(output->backlight);
1065
Matt Roper361d2ad2011-08-29 13:52:23 -07001066 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001067 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001068
1069 /* Restore original CRTC state */
1070 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001071 origcrtc->x, origcrtc->y,
1072 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001073 drmModeFreeCrtc(origcrtc);
1074
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001075 c->crtc_allocator &= ~(1 << output->crtc_id);
1076 c->connector_allocator &= ~(1 << output->connector_id);
1077
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001078 if (c->use_pixman) {
1079 drm_output_fini_pixman(output);
1080 } else {
1081 gl_renderer_output_destroy(output_base);
1082 gbm_surface_destroy(output->surface);
1083 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001084
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001085 weston_plane_release(&output->fb_plane);
1086 weston_plane_release(&output->cursor_plane);
1087
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001088 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001089 wl_list_remove(&output->base.link);
1090
Matt Roper361d2ad2011-08-29 13:52:23 -07001091 free(output);
1092}
1093
Alex Wub7b8bda2012-04-17 17:20:48 +08001094static struct drm_mode *
1095choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1096{
1097 struct drm_mode *tmp_mode = NULL, *mode;
1098
1099 if (output->base.current->width == target_mode->width &&
1100 output->base.current->height == target_mode->height &&
1101 (output->base.current->refresh == target_mode->refresh ||
1102 target_mode->refresh == 0))
1103 return (struct drm_mode *)output->base.current;
1104
1105 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1106 if (mode->mode_info.hdisplay == target_mode->width &&
1107 mode->mode_info.vdisplay == target_mode->height) {
1108 if (mode->mode_info.vrefresh == target_mode->refresh ||
1109 target_mode->refresh == 0) {
1110 return mode;
1111 } else if (!tmp_mode)
1112 tmp_mode = mode;
1113 }
1114 }
1115
1116 return tmp_mode;
1117}
1118
1119static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001120drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001121static int
1122drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001123
1124static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001125drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1126{
1127 struct drm_output *output;
1128 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001129 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001130
1131 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001132 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001133 return -1;
1134 }
1135
1136 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001137 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001138 return -1;
1139 }
1140
1141 ec = (struct drm_compositor *)output_base->compositor;
1142 output = (struct drm_output *)output_base;
1143 drm_mode = choose_mode (output, mode);
1144
1145 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001146 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001147 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001148 }
1149
1150 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001151 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001152
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001153 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001154
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001155 output->base.current = &drm_mode->base;
1156 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001157 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1158
Alex Wub7b8bda2012-04-17 17:20:48 +08001159 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001160 drm_output_release_fb(output, output->current);
1161 drm_output_release_fb(output, output->next);
1162 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001163
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001164 if (ec->use_pixman) {
1165 drm_output_fini_pixman(output);
1166 if (drm_output_init_pixman(output, ec) < 0) {
1167 weston_log("failed to init output pixman state with "
1168 "new mode\n");
1169 return -1;
1170 }
1171 } else {
1172 gl_renderer_output_destroy(&output->base);
1173 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001174
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001175 if (drm_output_init_egl(output, ec) < 0) {
1176 weston_log("failed to init output egl state with "
1177 "new mode");
1178 return -1;
1179 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001180 }
1181
Alex Wub7b8bda2012-04-17 17:20:48 +08001182 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001183}
1184
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001185static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001186on_drm_input(int fd, uint32_t mask, void *data)
1187{
1188 drmEventContext evctx;
1189
1190 memset(&evctx, 0, sizeof evctx);
1191 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1192 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001193 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001194 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001195
1196 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001197}
1198
1199static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001200init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001201{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001202 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001203 uint64_t cap;
1204 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001205
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001206 sysnum = udev_device_get_sysnum(device);
1207 if (sysnum)
1208 ec->drm.id = atoi(sysnum);
1209 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001210 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001211 return -1;
1212 }
1213
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001214 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001215 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001216 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001217 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001218 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001219 udev_device_get_devnode(device));
1220 return -1;
1221 }
1222
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001223 weston_log("using %s\n", filename);
1224
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001225 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001226
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001227 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1228 if (ret == 0 && cap == 1)
1229 ec->clock = CLOCK_MONOTONIC;
1230 else
1231 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001232
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001233 return 0;
1234}
1235
1236static int
1237init_egl(struct drm_compositor *ec)
1238{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001239 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001240
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001241 if (!ec->gbm)
1242 return -1;
1243
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001244 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001245 NULL) < 0) {
1246 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001247 return -1;
1248 }
1249
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001250 return 0;
1251}
1252
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001253static int
1254init_pixman(struct drm_compositor *ec)
1255{
1256 return pixman_renderer_init(&ec->base);
1257}
1258
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001259static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001260drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1261{
1262 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001263 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001264
1265 mode = malloc(sizeof *mode);
1266 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001267 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001268
1269 mode->base.flags = 0;
1270 mode->base.width = info->hdisplay;
1271 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001272
1273 /* Calculate higher precision (mHz) refresh rate */
1274 refresh = (info->clock * 1000000LL / info->htotal +
1275 info->vtotal / 2) / info->vtotal;
1276
1277 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1278 refresh *= 2;
1279 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1280 refresh /= 2;
1281 if (info->vscan > 1)
1282 refresh /= info->vscan;
1283
1284 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001285 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001286
1287 if (info->type & DRM_MODE_TYPE_PREFERRED)
1288 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1289
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001290 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1291
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001292 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001293}
1294
1295static int
1296drm_subpixel_to_wayland(int drm_value)
1297{
1298 switch (drm_value) {
1299 default:
1300 case DRM_MODE_SUBPIXEL_UNKNOWN:
1301 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1302 case DRM_MODE_SUBPIXEL_NONE:
1303 return WL_OUTPUT_SUBPIXEL_NONE;
1304 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1305 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1306 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1307 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1308 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1309 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1310 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1311 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1312 }
1313}
1314
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001315/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001316static uint32_t
1317drm_get_backlight(struct drm_output *output)
1318{
1319 long brightness, max_brightness, norm;
1320
1321 brightness = backlight_get_brightness(output->backlight);
1322 max_brightness = backlight_get_max_brightness(output->backlight);
1323
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001324 /* convert it on a scale of 0 to 255 */
1325 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001326
1327 return (uint32_t) norm;
1328}
1329
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001330/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001331static void
1332drm_set_backlight(struct weston_output *output_base, uint32_t value)
1333{
1334 struct drm_output *output = (struct drm_output *) output_base;
1335 long max_brightness, new_brightness;
1336
1337 if (!output->backlight)
1338 return;
1339
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001340 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001341 return;
1342
1343 max_brightness = backlight_get_max_brightness(output->backlight);
1344
1345 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001346 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001347
1348 backlight_set_brightness(output->backlight, new_brightness);
1349}
1350
1351static drmModePropertyPtr
1352drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1353{
1354 drmModePropertyPtr props;
1355 int i;
1356
1357 for (i = 0; i < connector->count_props; i++) {
1358 props = drmModeGetProperty(fd, connector->props[i]);
1359 if (!props)
1360 continue;
1361
1362 if (!strcmp(props->name, name))
1363 return props;
1364
1365 drmModeFreeProperty(props);
1366 }
1367
1368 return NULL;
1369}
1370
1371static void
1372drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1373{
1374 struct drm_output *output = (struct drm_output *) output_base;
1375 struct weston_compositor *ec = output_base->compositor;
1376 struct drm_compositor *c = (struct drm_compositor *) ec;
1377 drmModeConnectorPtr connector;
1378 drmModePropertyPtr prop;
1379
1380 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1381 if (!connector)
1382 return;
1383
1384 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1385 if (!prop) {
1386 drmModeFreeConnector(connector);
1387 return;
1388 }
1389
1390 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1391 prop->prop_id, level);
1392 drmModeFreeProperty(prop);
1393 drmModeFreeConnector(connector);
1394}
1395
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001396static const char *connector_type_names[] = {
1397 "None",
1398 "VGA",
1399 "DVI",
1400 "DVI",
1401 "DVI",
1402 "Composite",
1403 "TV",
1404 "LVDS",
1405 "CTV",
1406 "DIN",
1407 "DP",
1408 "HDMI",
1409 "HDMI",
1410 "TV",
1411 "eDP",
1412};
1413
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001414static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001415find_crtc_for_connector(struct drm_compositor *ec,
1416 drmModeRes *resources, drmModeConnector *connector)
1417{
1418 drmModeEncoder *encoder;
1419 uint32_t possible_crtcs;
1420 int i, j;
1421
1422 for (j = 0; j < connector->count_encoders; j++) {
1423 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1424 if (encoder == NULL) {
1425 weston_log("Failed to get encoder.\n");
1426 return -1;
1427 }
1428 possible_crtcs = encoder->possible_crtcs;
1429 drmModeFreeEncoder(encoder);
1430
1431 for (i = 0; i < resources->count_crtcs; i++) {
1432 if (possible_crtcs & (1 << i) &&
1433 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1434 return i;
1435 }
1436 }
1437
1438 return -1;
1439}
1440
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001441/* Init output state that depends on gl or gbm */
1442static int
1443drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1444{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001445 int i, flags;
1446
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001447 output->surface = gbm_surface_create(ec->gbm,
1448 output->base.current->width,
1449 output->base.current->height,
1450 GBM_FORMAT_XRGB8888,
1451 GBM_BO_USE_SCANOUT |
1452 GBM_BO_USE_RENDERING);
1453 if (!output->surface) {
1454 weston_log("failed to create gbm surface\n");
1455 return -1;
1456 }
1457
1458 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001459 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001460 gbm_surface_destroy(output->surface);
1461 return -1;
1462 }
1463
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001464 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1465
1466 for (i = 0; i < 2; i++) {
1467 if (output->cursor_bo[i])
1468 continue;
1469
1470 output->cursor_bo[i] =
1471 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1472 flags);
1473 }
1474
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001475 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1476 weston_log("cursor buffers unavailable, using gl cursors\n");
1477 ec->cursors_are_broken = 1;
1478 }
1479
1480 return 0;
1481}
1482
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001483static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001484drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1485{
1486 int w = output->base.current->width;
1487 int h = output->base.current->height;
1488 unsigned int i;
1489
1490 /* FIXME error checking */
1491
1492 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1493 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1494 if (!output->dumb[i])
1495 goto err;
1496
1497 output->image[i] =
1498 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1499 output->dumb[i]->map,
1500 output->dumb[i]->stride);
1501 if (!output->image[i])
1502 goto err;
1503 }
1504
1505 if (pixman_renderer_output_create(&output->base) < 0)
1506 goto err;
1507
1508 pixman_region32_init_rect(&output->previous_damage,
1509 output->base.x, output->base.y, w, h);
1510
1511 return 0;
1512
1513err:
1514 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1515 if (output->dumb[i])
1516 drm_fb_destroy_dumb(output->dumb[i]);
1517 if (output->image[i])
1518 pixman_image_unref(output->image[i]);
1519
1520 output->dumb[i] = NULL;
1521 output->image[i] = NULL;
1522 }
1523
1524 return -1;
1525}
1526
1527static void
1528drm_output_fini_pixman(struct drm_output *output)
1529{
1530 unsigned int i;
1531
1532 pixman_renderer_output_destroy(&output->base);
1533 pixman_region32_fini(&output->previous_damage);
1534
1535 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1536 drm_fb_destroy_dumb(output->dumb[i]);
1537 pixman_image_unref(output->image[i]);
1538 output->dumb[i] = NULL;
1539 output->image[i] = NULL;
1540 }
1541}
1542
Richard Hughes2b2092a2013-04-24 14:58:02 +01001543static void
1544edid_parse_string(const uint8_t *data, char text[])
1545{
1546 int i;
1547 int replaced = 0;
1548
1549 /* this is always 12 bytes, but we can't guarantee it's null
1550 * terminated or not junk. */
1551 strncpy(text, (const char *) data, 12);
1552
1553 /* remove insane chars */
1554 for (i = 0; text[i] != '\0'; i++) {
1555 if (text[i] == '\n' ||
1556 text[i] == '\r') {
1557 text[i] = '\0';
1558 break;
1559 }
1560 }
1561
1562 /* ensure string is printable */
1563 for (i = 0; text[i] != '\0'; i++) {
1564 if (!isprint(text[i])) {
1565 text[i] = '-';
1566 replaced++;
1567 }
1568 }
1569
1570 /* if the string is random junk, ignore the string */
1571 if (replaced > 4)
1572 text[0] = '\0';
1573}
1574
1575#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1576#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1577#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1578#define EDID_OFFSET_DATA_BLOCKS 0x36
1579#define EDID_OFFSET_LAST_BLOCK 0x6c
1580#define EDID_OFFSET_PNPID 0x08
1581#define EDID_OFFSET_SERIAL 0x0c
1582
1583static int
1584edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1585{
1586 int i;
1587 uint32_t serial_number;
1588
1589 /* check header */
1590 if (length < 128)
1591 return -1;
1592 if (data[0] != 0x00 || data[1] != 0xff)
1593 return -1;
1594
1595 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1596 * /--08--\/--09--\
1597 * 7654321076543210
1598 * |\---/\---/\---/
1599 * R C1 C2 C3 */
1600 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1601 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1602 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1603 edid->pnp_id[3] = '\0';
1604
1605 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1606 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1607 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1608 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1609 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1610 if (serial_number > 0)
1611 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1612
1613 /* parse EDID data */
1614 for (i = EDID_OFFSET_DATA_BLOCKS;
1615 i <= EDID_OFFSET_LAST_BLOCK;
1616 i += 18) {
1617 /* ignore pixel clock data */
1618 if (data[i] != 0)
1619 continue;
1620 if (data[i+2] != 0)
1621 continue;
1622
1623 /* any useful blocks? */
1624 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1625 edid_parse_string(&data[i+5],
1626 edid->monitor_name);
1627 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1628 edid_parse_string(&data[i+5],
1629 edid->serial_number);
1630 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1631 edid_parse_string(&data[i+5],
1632 edid->eisa_id);
1633 }
1634 }
1635 return 0;
1636}
1637
1638static void
1639find_and_parse_output_edid(struct drm_compositor *ec,
1640 struct drm_output *output,
1641 drmModeConnector *connector)
1642{
1643 drmModePropertyBlobPtr edid_blob = NULL;
1644 drmModePropertyPtr property;
1645 int i;
1646 int rc;
1647
1648 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1649 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1650 if (!property)
1651 continue;
1652 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1653 !strcmp(property->name, "EDID")) {
1654 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1655 connector->prop_values[i]);
1656 }
1657 drmModeFreeProperty(property);
1658 }
1659 if (!edid_blob)
1660 return;
1661
1662 rc = edid_parse(&output->edid,
1663 edid_blob->data,
1664 edid_blob->length);
1665 if (!rc) {
1666 weston_log("EDID data '%s', '%s', '%s'\n",
1667 output->edid.pnp_id,
1668 output->edid.monitor_name,
1669 output->edid.serial_number);
1670 if (output->edid.pnp_id[0] != '\0')
1671 output->base.make = output->edid.pnp_id;
1672 if (output->edid.monitor_name[0] != '\0')
1673 output->base.model = output->edid.monitor_name;
1674 if (output->edid.serial_number[0] != '\0')
1675 output->base.serial_number = output->edid.serial_number;
1676 }
1677 drmModeFreePropertyBlob(edid_blob);
1678}
1679
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001680static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001681create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001682 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001683 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001684 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001685{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001686 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001687 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1688 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001689 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001690 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001691 drmModeModeInfo crtc_mode;
1692 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001693 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001694 char name[32];
1695 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001696
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001697 i = find_crtc_for_connector(ec, resources, connector);
1698 if (i < 0) {
1699 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001700 return -1;
1701 }
1702
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001703 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001704 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001705 return -1;
1706
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001707 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001708 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1709 output->base.make = "unknown";
1710 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001711 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001712 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001713
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001714 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1715 type_name = connector_type_names[connector->connector_type];
1716 else
1717 type_name = "UNKNOWN";
1718 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001719 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001720
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001721 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001722 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001723 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001724 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001725 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001726
Matt Roper361d2ad2011-08-29 13:52:23 -07001727 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1728
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001729 /* Get the current mode on the crtc that's currently driving
1730 * this connector. */
1731 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001732 memset(&crtc_mode, 0, sizeof crtc_mode);
1733 if (encoder != NULL) {
1734 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1735 drmModeFreeEncoder(encoder);
1736 if (crtc == NULL)
1737 goto err_free;
1738 if (crtc->mode_valid)
1739 crtc_mode = crtc->mode;
1740 drmModeFreeCrtc(crtc);
1741 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001742
David Herrmann0f0d54e2011-12-08 17:05:45 +01001743 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001744 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1745 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001746 goto err_free;
1747 }
1748
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001749 preferred = NULL;
1750 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001751 configured = NULL;
1752
1753 wl_list_for_each(temp, &configured_output_list, link) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001754 if (strcmp(temp->name, output->base.name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001755 if (temp->mode)
1756 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001757 temp->name, temp->mode);
1758 o = temp;
1759 break;
1760 }
1761 }
1762
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001763 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001764 weston_log("Disabling output %s\n", o->name);
1765
1766 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1767 0, 0, 0, 0, 0, NULL);
1768 goto err_free;
1769 }
1770
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001771 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001772 if (o && o->config == OUTPUT_CONFIG_MODE &&
1773 o->width == drm_mode->base.width &&
1774 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001775 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001776 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001777 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001778 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001779 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001780 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001781
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001782 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001783 configured = drm_output_add_mode(output, &o->crtc_mode);
1784 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001785 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001786 current = configured;
1787 }
1788
Wang Quanxianacb805a2012-07-30 18:09:46 -04001789 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001790 current = drm_output_add_mode(output, &crtc_mode);
1791 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001792 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001793 }
1794
Scott Moreau8ab5d452012-07-30 19:51:08 -06001795 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1796 configured = current;
1797
Wang Quanxianacb805a2012-07-30 18:09:46 -04001798 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001799 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001800 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001801 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001802 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001803 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001804 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001805 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001806
1807 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001808 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001809 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001810 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001811
Wang Quanxianacb805a2012-07-30 18:09:46 -04001812 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1813
John Kåre Alsaker94659272012-11-13 19:10:18 +01001814 weston_output_init(&output->base, &ec->base, x, y,
1815 connector->mmWidth, connector->mmHeight,
1816 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1817
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001818 if (ec->use_pixman) {
1819 if (drm_output_init_pixman(output, ec) < 0) {
1820 weston_log("Failed to init output pixman state\n");
1821 goto err_output;
1822 }
1823 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001824 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001825 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001826 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001827
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001828 output->backlight = backlight_init(drm_device,
1829 connector->connector_type);
1830 if (output->backlight) {
1831 output->base.set_backlight = drm_set_backlight;
1832 output->base.backlight_current = drm_get_backlight(output);
1833 }
1834
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001835 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1836
Richard Hughes2b2092a2013-04-24 14:58:02 +01001837 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001838 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1839 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001840
Alex Wubd3354b2012-04-17 17:20:49 +08001841 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001842 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001843 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001844 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001845 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001846 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001847 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001848
Richard Hughese7299962013-05-01 21:52:12 +01001849 output->base.gamma_size = output->original_crtc->gamma_size;
1850 output->base.set_gamma = drm_output_set_gamma;
1851
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001852 weston_plane_init(&output->cursor_plane, 0, 0);
1853 weston_plane_init(&output->fb_plane, 0, 0);
1854
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001855 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1856 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1857 &ec->base.primary_plane);
1858
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001859 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001860 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001861 wl_list_for_each(m, &output->base.mode_list, link)
1862 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1863 m->width, m->height, m->refresh / 1000.0,
1864 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1865 ", preferred" : "",
1866 m->flags & WL_OUTPUT_MODE_CURRENT ?
1867 ", current" : "",
1868 connector->count_modes == 0 ?
1869 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001870
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001871 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001872
John Kåre Alsaker94659272012-11-13 19:10:18 +01001873err_output:
1874 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001875err_free:
1876 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1877 base.link) {
1878 wl_list_remove(&drm_mode->base.link);
1879 free(drm_mode);
1880 }
1881
1882 drmModeFreeCrtc(output->original_crtc);
1883 ec->crtc_allocator &= ~(1 << output->crtc_id);
1884 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001885 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001886
David Herrmann0f0d54e2011-12-08 17:05:45 +01001887 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001888}
1889
Jesse Barnes58ef3792012-02-23 09:45:49 -05001890static void
1891create_sprites(struct drm_compositor *ec)
1892{
1893 struct drm_sprite *sprite;
1894 drmModePlaneRes *plane_res;
1895 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001896 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001897
1898 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1899 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001900 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001901 strerror(errno));
1902 return;
1903 }
1904
1905 for (i = 0; i < plane_res->count_planes; i++) {
1906 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1907 if (!plane)
1908 continue;
1909
1910 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1911 plane->count_formats));
1912 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001913 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001914 __func__);
1915 free(plane);
1916 continue;
1917 }
1918
1919 memset(sprite, 0, sizeof *sprite);
1920
1921 sprite->possible_crtcs = plane->possible_crtcs;
1922 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001923 sprite->current = NULL;
1924 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001925 sprite->compositor = ec;
1926 sprite->count_formats = plane->count_formats;
1927 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001928 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001929 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001930 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001931 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1932 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001933
1934 wl_list_insert(&ec->sprite_list, &sprite->link);
1935 }
1936
1937 free(plane_res->planes);
1938 free(plane_res);
1939}
1940
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001941static void
1942destroy_sprites(struct drm_compositor *compositor)
1943{
1944 struct drm_sprite *sprite, *next;
1945 struct drm_output *output;
1946
1947 output = container_of(compositor->base.output_list.next,
1948 struct drm_output, base.link);
1949
1950 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1951 drmModeSetPlane(compositor->drm.fd,
1952 sprite->plane_id,
1953 output->crtc_id, 0, 0,
1954 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001955 drm_output_release_fb(output, sprite->current);
1956 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001957 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001958 free(sprite);
1959 }
1960}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001961
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001962static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001963create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001964 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001965{
1966 drmModeConnector *connector;
1967 drmModeRes *resources;
1968 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001969 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001970
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001971 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001972 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001973 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001974 return -1;
1975 }
1976
Jesse Barnes58ef3792012-02-23 09:45:49 -05001977 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001978 if (!ec->crtcs) {
1979 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001980 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001981 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001982
Rob Clark4339add2012-08-09 14:18:28 -05001983 ec->min_width = resources->min_width;
1984 ec->max_width = resources->max_width;
1985 ec->min_height = resources->min_height;
1986 ec->max_height = resources->max_height;
1987
Jesse Barnes58ef3792012-02-23 09:45:49 -05001988 ec->num_crtcs = resources->count_crtcs;
1989 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1990
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001991 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001992 connector = drmModeGetConnector(ec->drm.fd,
1993 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001994 if (connector == NULL)
1995 continue;
1996
1997 if (connector->connection == DRM_MODE_CONNECTED &&
1998 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001999 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002000 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002001 connector, x, y,
2002 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002003 drmModeFreeConnector(connector);
2004 continue;
2005 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002006
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002007 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002008 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002009 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002010 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002011
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002012 drmModeFreeConnector(connector);
2013 }
2014
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002015 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002016 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002017 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002018 return -1;
2019 }
2020
2021 drmModeFreeResources(resources);
2022
2023 return 0;
2024}
2025
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002026static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002027update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002028{
2029 drmModeConnector *connector;
2030 drmModeRes *resources;
2031 struct drm_output *output, *next;
2032 int x = 0, y = 0;
2033 int x_offset = 0, y_offset = 0;
2034 uint32_t connected = 0, disconnects = 0;
2035 int i;
2036
2037 resources = drmModeGetResources(ec->drm.fd);
2038 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002039 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002040 return;
2041 }
2042
2043 /* collect new connects */
2044 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002045 int connector_id = resources->connectors[i];
2046
2047 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002048 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002049 continue;
2050
David Herrmann7551cff2011-12-08 17:05:43 +01002051 if (connector->connection != DRM_MODE_CONNECTED) {
2052 drmModeFreeConnector(connector);
2053 continue;
2054 }
2055
Benjamin Franzke117483d2011-08-30 11:38:26 +02002056 connected |= (1 << connector_id);
2057
2058 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002059 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002060 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002061 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002062
2063 /* XXX: not yet needed, we die with 0 outputs */
2064 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002065 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002066 else
2067 x = 0;
2068 y = 0;
2069 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002070 connector, x, y,
2071 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002072 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002073
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002074 }
2075 drmModeFreeConnector(connector);
2076 }
2077 drmModeFreeResources(resources);
2078
2079 disconnects = ec->connector_allocator & ~connected;
2080 if (disconnects) {
2081 wl_list_for_each_safe(output, next, &ec->base.output_list,
2082 base.link) {
2083 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002084 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002085 output->base.x - x_offset,
2086 output->base.y - y_offset);
2087 }
2088
2089 if (disconnects & (1 << output->connector_id)) {
2090 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002091 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002092 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002093 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002094 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002095 }
2096 }
2097 }
2098
2099 /* FIXME: handle zero outputs, without terminating */
2100 if (ec->connector_allocator == 0)
2101 wl_display_terminate(ec->base.wl_display);
2102}
2103
2104static int
David Herrmannd7488c22012-03-11 20:05:21 +01002105udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002106{
David Herrmannd7488c22012-03-11 20:05:21 +01002107 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002108 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002109
2110 sysnum = udev_device_get_sysnum(device);
2111 if (!sysnum || atoi(sysnum) != ec->drm.id)
2112 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002113
David Herrmann6ac52db2012-03-11 20:05:22 +01002114 val = udev_device_get_property_value(device, "HOTPLUG");
2115 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002116 return 0;
2117
David Herrmann6ac52db2012-03-11 20:05:22 +01002118 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002119}
2120
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002121static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002122udev_drm_event(int fd, uint32_t mask, void *data)
2123{
2124 struct drm_compositor *ec = data;
2125 struct udev_device *event;
2126
2127 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002128
David Herrmannd7488c22012-03-11 20:05:21 +01002129 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002130 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002131
2132 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002133
2134 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002135}
2136
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002137static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002138drm_restore(struct weston_compositor *ec)
2139{
2140 struct drm_compositor *d = (struct drm_compositor *) ec;
2141
2142 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2143 weston_log("failed to drop master: %m\n");
2144 tty_reset(d->tty);
2145}
2146
2147static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002148drm_free_configured_output(struct drm_configured_output *output)
2149{
2150 free(output->name);
2151 free(output->mode);
2152 free(output);
2153}
2154
2155static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002156drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002157{
2158 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002159 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002160 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002161
Kristian Høgsberge8091032013-02-18 15:43:29 -05002162 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2163 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002164 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002165 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002166
2167 wl_event_source_remove(d->udev_drm_source);
2168 wl_event_source_remove(d->drm_source);
2169
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002170 destroy_sprites(d);
2171
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002172 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002173
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002174 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002175
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002176 if (d->gbm)
2177 gbm_device_destroy(d->gbm);
2178
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002179 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002180 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002181 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002182
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002183 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002184}
2185
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002186static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002187drm_compositor_set_modes(struct drm_compositor *compositor)
2188{
2189 struct drm_output *output;
2190 struct drm_mode *drm_mode;
2191 int ret;
2192
2193 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002194 if (!output->current) {
2195 /* If something that would cause the output to
2196 * switch mode happened while in another vt, we
2197 * might not have a current drm_fb. In that case,
2198 * schedule a repaint and let drm_output_repaint
2199 * handle setting the mode. */
2200 weston_output_schedule_repaint(&output->base);
2201 continue;
2202 }
2203
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002204 drm_mode = (struct drm_mode *) output->base.current;
2205 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002206 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002207 &output->connector_id, 1,
2208 &drm_mode->mode_info);
2209 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002210 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002211 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002212 drm_mode->base.width, drm_mode->base.height,
2213 output->base.x, output->base.y);
2214 }
2215 }
2216}
2217
2218static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002219vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002220{
2221 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002222 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002223 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002224 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002225
2226 switch (event) {
2227 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002228 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002229 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002230 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002231 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002232 wl_display_terminate(compositor->wl_display);
2233 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002234 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002235 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002236 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002237 wl_list_for_each(seat, &compositor->seat_list, base.link)
2238 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002239 break;
2240 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002241 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002242 wl_list_for_each(seat, &compositor->seat_list, base.link)
2243 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002244
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002245 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002246 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002247 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002248
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002249 /* If we have a repaint scheduled (either from a
2250 * pending pageflip or the idle handler), make sure we
2251 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002252 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002253 * further attemps at repainting. When we switch
2254 * back, we schedule a repaint, which will process
2255 * pending frame callbacks. */
2256
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002257 wl_list_for_each(output, &ec->base.output_list, base.link) {
2258 output->base.repaint_needed = 0;
2259 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002260 }
2261
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002262 output = container_of(ec->base.output_list.next,
2263 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002264
2265 wl_list_for_each(sprite, &ec->sprite_list, link)
2266 drmModeSetPlane(ec->drm.fd,
2267 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002268 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002269 0, 0, 0, 0, 0, 0, 0, 0);
2270
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002271 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002272 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002273
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002274 break;
2275 };
2276}
2277
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002278static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002279switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002280{
2281 struct drm_compositor *ec = data;
2282
Daniel Stone325fc2d2012-05-30 16:31:58 +01002283 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002284}
2285
David Herrmann0af066f2012-10-29 19:21:16 +01002286/*
2287 * Find primary GPU
2288 * Some systems may have multiple DRM devices attached to a single seat. This
2289 * function loops over all devices and tries to find a PCI device with the
2290 * boot_vga sysfs attribute set to 1.
2291 * If no such device is found, the first DRM device reported by udev is used.
2292 */
2293static struct udev_device*
2294find_primary_gpu(struct drm_compositor *ec, const char *seat)
2295{
2296 struct udev_enumerate *e;
2297 struct udev_list_entry *entry;
2298 const char *path, *device_seat, *id;
2299 struct udev_device *device, *drm_device, *pci;
2300
2301 e = udev_enumerate_new(ec->udev);
2302 udev_enumerate_add_match_subsystem(e, "drm");
2303 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2304
2305 udev_enumerate_scan_devices(e);
2306 drm_device = NULL;
2307 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2308 path = udev_list_entry_get_name(entry);
2309 device = udev_device_new_from_syspath(ec->udev, path);
2310 if (!device)
2311 continue;
2312 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2313 if (!device_seat)
2314 device_seat = default_seat;
2315 if (strcmp(device_seat, seat)) {
2316 udev_device_unref(device);
2317 continue;
2318 }
2319
2320 pci = udev_device_get_parent_with_subsystem_devtype(device,
2321 "pci", NULL);
2322 if (pci) {
2323 id = udev_device_get_sysattr_value(pci, "boot_vga");
2324 if (id && !strcmp(id, "1")) {
2325 if (drm_device)
2326 udev_device_unref(drm_device);
2327 drm_device = device;
2328 break;
2329 }
2330 }
2331
2332 if (!drm_device)
2333 drm_device = device;
2334 else
2335 udev_device_unref(device);
2336 }
2337
2338 udev_enumerate_unref(e);
2339 return drm_device;
2340}
2341
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002342static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002343planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002344{
2345 struct drm_compositor *c = data;
2346
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002347 switch (key) {
2348 case KEY_C:
2349 c->cursors_are_broken ^= 1;
2350 break;
2351 case KEY_V:
2352 c->sprites_are_broken ^= 1;
2353 break;
2354 case KEY_O:
2355 c->sprites_hidden ^= 1;
2356 break;
2357 default:
2358 break;
2359 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002360}
2361
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002362static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002363drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002364 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002365 int *argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002366{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002367 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002368 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002369 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002370 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002371 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002372 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002373
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002374 weston_log("initializing drm backend\n");
2375
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002376 ec = malloc(sizeof *ec);
2377 if (ec == NULL)
2378 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002379 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002380
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002381 /* KMS support for sprites is not complete yet, so disable the
2382 * functionality for now. */
2383 ec->sprites_are_broken = 1;
2384
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002385 ec->use_pixman = pixman;
2386
Daniel Stone725c2c32012-06-22 14:04:36 +01002387 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002388 config_file) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002389 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002390 goto err_base;
2391 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002392
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002393 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002394 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002395 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002396 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002397 goto err_compositor;
2398 }
2399
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002400 ec->udev = udev_new();
2401 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002402 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002403 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002404 }
2405
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002406 ec->base.wl_display = display;
2407 ec->tty = tty_create(&ec->base, vt_func, tty);
2408 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002409 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002410 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002411 }
2412
David Herrmann0af066f2012-10-29 19:21:16 +01002413 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002414 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002415 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002416 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002417 }
David Herrmann0af066f2012-10-29 19:21:16 +01002418 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002419
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002420 if (init_drm(ec, drm_device) < 0) {
2421 weston_log("failed to initialize kms\n");
2422 goto err_udev_dev;
2423 }
2424
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002425 if (ec->use_pixman) {
2426 if (init_pixman(ec) < 0) {
2427 weston_log("failed to initialize pixman renderer\n");
2428 goto err_udev_dev;
2429 }
2430 } else {
2431 if (init_egl(ec) < 0) {
2432 weston_log("failed to initialize egl\n");
2433 goto err_udev_dev;
2434 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002435 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002436
2437 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002438 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002439
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002440 ec->base.focus = 1;
2441
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002442 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002443
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002444 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002445 weston_compositor_add_key_binding(&ec->base, key,
2446 MODIFIER_CTRL | MODIFIER_ALT,
2447 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002448
Jesse Barnes58ef3792012-02-23 09:45:49 -05002449 wl_list_init(&ec->sprite_list);
2450 create_sprites(ec);
2451
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002452 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002453 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002454 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002455 }
2456
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002457 path = NULL;
2458
Kristian Høgsberge8091032013-02-18 15:43:29 -05002459 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002460 weston_log("failed to create input devices\n");
2461 goto err_sprite;
2462 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002463
2464 loop = wl_display_get_event_loop(ec->base.wl_display);
2465 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002466 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002467 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002468
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002469 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2470 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002471 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002472 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002473 }
2474 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2475 "drm", NULL);
2476 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002477 wl_event_loop_add_fd(loop,
2478 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002479 WL_EVENT_READABLE, udev_drm_event, ec);
2480
2481 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002482 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002483 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002484 }
2485
Daniel Stonea96b93c2012-06-22 14:04:37 +01002486 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002487
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002488 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002489 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002490 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002491 planes_binding, ec);
2492 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2493 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002494
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002495 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002496
2497err_udev_monitor:
2498 wl_event_source_remove(ec->udev_drm_source);
2499 udev_monitor_unref(ec->udev_monitor);
2500err_drm_source:
2501 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002502 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2503 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002504err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002505 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002506 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002507 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002508err_udev_dev:
2509 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002510err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002511 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2512 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002513 tty_destroy(ec->tty);
2514err_udev:
2515 udev_unref(ec->udev);
2516err_compositor:
2517 weston_compositor_shutdown(&ec->base);
2518err_base:
2519 free(ec);
2520 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002521}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002522
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002523static int
2524set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2525{
2526 mode->flags = 0;
2527
2528 if (strcmp(hsync, "+hsync") == 0)
2529 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2530 else if (strcmp(hsync, "-hsync") == 0)
2531 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2532 else
2533 return -1;
2534
2535 if (strcmp(vsync, "+vsync") == 0)
2536 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2537 else if (strcmp(vsync, "-vsync") == 0)
2538 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2539 else
2540 return -1;
2541
2542 return 0;
2543}
2544
2545static int
2546check_for_modeline(struct drm_configured_output *output)
2547{
2548 drmModeModeInfo mode;
2549 char hsync[16];
2550 char vsync[16];
2551 char mode_name[16];
2552 float fclock;
2553
2554 mode.type = DRM_MODE_TYPE_USERDEF;
2555 mode.hskew = 0;
2556 mode.vscan = 0;
2557 mode.vrefresh = 0;
2558
2559 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2560 &fclock, &mode.hdisplay,
2561 &mode.hsync_start,
2562 &mode.hsync_end, &mode.htotal,
2563 &mode.vdisplay,
2564 &mode.vsync_start,
2565 &mode.vsync_end, &mode.vtotal,
2566 hsync, vsync) == 11) {
2567 if (set_sync_flags(&mode, hsync, vsync))
2568 return -1;
2569
2570 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2571 strcpy(mode.name, mode_name);
2572
2573 mode.clock = fclock * 1000;
2574 } else
2575 return -1;
2576
2577 output->crtc_mode = mode;
2578
2579 return 0;
2580}
2581
Scott Moreau8ab5d452012-07-30 19:51:08 -06002582static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002583drm_output_set_transform(struct drm_configured_output *output)
2584{
2585 if (!output_transform) {
2586 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2587 return;
2588 }
2589
2590 if (!strcmp(output_transform, "normal"))
2591 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2592 else if (!strcmp(output_transform, "90"))
2593 output->transform = WL_OUTPUT_TRANSFORM_90;
2594 else if (!strcmp(output_transform, "180"))
2595 output->transform = WL_OUTPUT_TRANSFORM_180;
2596 else if (!strcmp(output_transform, "270"))
2597 output->transform = WL_OUTPUT_TRANSFORM_270;
2598 else if (!strcmp(output_transform, "flipped"))
2599 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2600 else if (!strcmp(output_transform, "flipped-90"))
2601 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2602 else if (!strcmp(output_transform, "flipped-180"))
2603 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2604 else if (!strcmp(output_transform, "flipped-270"))
2605 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2606 else {
2607 weston_log("Invalid transform \"%s\" for output %s\n",
2608 output_transform, output_name);
2609 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2610 }
2611
2612 free(output_transform);
2613 output_transform = NULL;
2614}
2615
2616static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002617output_section_done(void *data)
2618{
2619 struct drm_configured_output *output;
2620
2621 output = malloc(sizeof *output);
2622
Scott Moreau1bad5db2012-08-18 01:04:05 -06002623 if (!output || !output_name || (output_name[0] == 'X') ||
2624 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002625 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002626 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002627 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002628 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002629 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002630 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002631 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002632 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002633 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002634
2635 output->config = OUTPUT_CONFIG_INVALID;
2636 output->name = output_name;
2637 output->mode = output_mode;
2638
Scott Moreau1bad5db2012-08-18 01:04:05 -06002639 if (output_mode) {
2640 if (strcmp(output_mode, "off") == 0)
2641 output->config = OUTPUT_CONFIG_OFF;
2642 else if (strcmp(output_mode, "preferred") == 0)
2643 output->config = OUTPUT_CONFIG_PREFERRED;
2644 else if (strcmp(output_mode, "current") == 0)
2645 output->config = OUTPUT_CONFIG_CURRENT;
2646 else if (sscanf(output_mode, "%dx%d",
2647 &output->width, &output->height) == 2)
2648 output->config = OUTPUT_CONFIG_MODE;
2649 else if (check_for_modeline(output) == 0)
2650 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002651
Scott Moreau1bad5db2012-08-18 01:04:05 -06002652 if (output->config == OUTPUT_CONFIG_INVALID)
2653 weston_log("Invalid mode \"%s\" for output %s\n",
2654 output_mode, output_name);
2655 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002656 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002657
2658 drm_output_set_transform(output);
2659
2660 wl_list_insert(&configured_output_list, &output->link);
2661
2662 if (output_transform)
2663 free(output_transform);
2664 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002665}
2666
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002667WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002668backend_init(struct wl_display *display, int *argc, char *argv[],
Daniel Stonec1be8e52012-06-01 11:14:02 -04002669 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002670{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002671 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002672 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002673
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002674 const struct weston_option drm_options[] = {
2675 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2676 { WESTON_OPTION_STRING, "seat", 0, &seat },
2677 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002678 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002679 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002680 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002681
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002682 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002683
Scott Moreau8ab5d452012-07-30 19:51:08 -06002684 wl_list_init(&configured_output_list);
2685
2686 const struct config_key drm_config_keys[] = {
2687 { "name", CONFIG_KEY_STRING, &output_name },
2688 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002689 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002690 };
2691
2692 const struct config_section config_section[] = {
2693 { "output", drm_config_keys,
2694 ARRAY_LENGTH(drm_config_keys), output_section_done },
2695 };
2696
2697 parse_config_file(config_file, config_section,
2698 ARRAY_LENGTH(config_section), NULL);
2699
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002700 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2701 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002702}