blob: 7aae70bd6e13cfd2680a811cb3be05ae6d9259a8 [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;
Alexander Larssond9a7bb72013-05-22 14:41:39 +020064static char *output_scale;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065static struct wl_list configured_output_list;
66
67enum output_config {
68 OUTPUT_CONFIG_INVALID = 0,
69 OUTPUT_CONFIG_OFF,
70 OUTPUT_CONFIG_PREFERRED,
71 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060072 OUTPUT_CONFIG_MODE,
73 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060074};
75
76struct drm_configured_output {
77 char *name;
78 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060079 uint32_t transform;
Alexander Larssond9a7bb72013-05-22 14:41:39 +020080 int32_t scale;
Scott Moreau8ab5d452012-07-30 19:51:08 -060081 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060082 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060083 enum output_config config;
84 struct wl_list link;
85};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040086
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040087struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050088 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040089
90 struct udev *udev;
91 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040092
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010093 struct udev_monitor *udev_monitor;
94 struct wl_event_source *udev_drm_source;
95
Benjamin Franzke2af7f102011-03-02 11:14:59 +010096 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010097 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010098 int fd;
99 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200100 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101 uint32_t *crtcs;
102 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -0500103 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100104 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -0500105 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106
Rob Clark4339add2012-08-09 14:18:28 -0500107 /* we need these parameters in order to not fail drmModeAddFB2()
108 * due to out of bounds dimensions, and then mistakenly set
109 * sprites_are_broken:
110 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200111 uint32_t min_width, max_width;
112 uint32_t min_height, max_height;
113 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500114
Jesse Barnes58ef3792012-02-23 09:45:49 -0500115 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500116 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200117 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500118
Rob Clarkab5b1e32012-08-09 13:24:45 -0500119 int cursors_are_broken;
120
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200121 int use_pixman;
122
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200123 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300124
125 clockid_t clock;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126};
127
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400128struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500129 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400130 drmModeModeInfo mode_info;
131};
132
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300133struct drm_output;
134
135struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300136 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200137 uint32_t fb_id, stride, handle, size;
138 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300139 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200140 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200141
142 /* Used by gbm fbs */
143 struct gbm_bo *bo;
144
145 /* Used by dumb fbs */
146 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300147};
148
Richard Hughes2b2092a2013-04-24 14:58:02 +0100149struct drm_edid {
150 char eisa_id[13];
151 char monitor_name[13];
152 char pnp_id[5];
153 char serial_number[13];
154};
155
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400156struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500157 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400158
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500160 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400161 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700162 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100163 struct drm_edid edid;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200164
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300165 int vblank_pending;
166 int page_flip_pending;
167
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400168 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400169 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400170 struct weston_plane cursor_plane;
171 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400172 struct weston_surface *cursor_surface;
173 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300174 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200175 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200176
177 struct drm_fb *dumb[2];
178 pixman_image_t *image[2];
179 int current_image;
180 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400181};
182
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183/*
184 * An output has a primary display plane plus zero or more sprites for
185 * blending display contents.
186 */
187struct drm_sprite {
188 struct wl_list link;
189
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400190 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500191
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200192 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300193 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500194 struct drm_compositor *compositor;
195
Jesse Barnes58ef3792012-02-23 09:45:49 -0500196 uint32_t possible_crtcs;
197 uint32_t plane_id;
198 uint32_t count_formats;
199
200 int32_t src_x, src_y;
201 uint32_t src_w, src_h;
202 uint32_t dest_x, dest_y;
203 uint32_t dest_w, dest_h;
204
205 uint32_t formats[];
206};
207
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500208static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400209
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400210static void
211drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400212
Jesse Barnes58ef3792012-02-23 09:45:49 -0500213static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500214drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
215{
216 struct weston_compositor *ec = output_base->compositor;
217 struct drm_compositor *c =(struct drm_compositor *) ec;
218 struct drm_output *output = (struct drm_output *) output_base;
219 int crtc;
220
221 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
222 if (c->crtcs[crtc] != output->crtc_id)
223 continue;
224
225 if (supported & (1 << crtc))
226 return -1;
227 }
228
229 return 0;
230}
231
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300232static void
233drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
234{
235 struct drm_fb *fb = data;
236 struct gbm_device *gbm = gbm_bo_get_device(bo);
237
238 if (fb->fb_id)
239 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
240
Pekka Paalanende685b82012-12-04 15:58:12 +0200241 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300242
243 free(data);
244}
245
246static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200247drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
248{
249 struct drm_fb *fb;
250 int ret;
251
252 struct drm_mode_create_dumb create_arg;
253 struct drm_mode_destroy_dumb destroy_arg;
254 struct drm_mode_map_dumb map_arg;
255
256 fb = calloc(1, sizeof *fb);
257 if (!fb)
258 return NULL;
259
260 create_arg.bpp = 32;
261 create_arg.width = width;
262 create_arg.height = height;
263
264 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
265 if (ret)
266 goto err_fb;
267
268 fb->handle = create_arg.handle;
269 fb->stride = create_arg.pitch;
270 fb->size = create_arg.size;
271 fb->fd = ec->drm.fd;
272
273 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
274 fb->stride, fb->handle, &fb->fb_id);
275 if (ret)
276 goto err_bo;
277
278 memset(&map_arg, 0, sizeof(map_arg));
279 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400280 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200281 if (ret)
282 goto err_add_fb;
283
284 fb->map = mmap(0, fb->size, PROT_WRITE,
285 MAP_SHARED, ec->drm.fd, map_arg.offset);
286 if (fb->map == MAP_FAILED)
287 goto err_add_fb;
288
289 return fb;
290
291err_add_fb:
292 drmModeRmFB(ec->drm.fd, fb->fb_id);
293err_bo:
294 memset(&destroy_arg, 0, sizeof(destroy_arg));
295 destroy_arg.handle = create_arg.handle;
296 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
297err_fb:
298 free(fb);
299 return NULL;
300}
301
302static void
303drm_fb_destroy_dumb(struct drm_fb *fb)
304{
305 struct drm_mode_destroy_dumb destroy_arg;
306
307 if (!fb->map)
308 return;
309
310 if (fb->fb_id)
311 drmModeRmFB(fb->fd, fb->fb_id);
312
313 weston_buffer_reference(&fb->buffer_ref, NULL);
314
315 munmap(fb->map, fb->size);
316
317 memset(&destroy_arg, 0, sizeof(destroy_arg));
318 destroy_arg.handle = fb->handle;
319 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
320
321 free(fb);
322}
323
324static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500325drm_fb_get_from_bo(struct gbm_bo *bo,
326 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327{
328 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200330 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 int ret;
332
333 if (fb)
334 return fb;
335
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200336 fb = calloc(1, sizeof *fb);
337 if (!fb)
338 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300339
340 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341
342 width = gbm_bo_get_width(bo);
343 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 fb->stride = gbm_bo_get_stride(bo);
345 fb->handle = gbm_bo_get_handle(bo).u32;
346 fb->size = fb->stride * height;
347 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300348
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 if (compositor->min_width > width || width > compositor->max_width ||
350 compositor->min_height > height ||
351 height > compositor->max_height) {
352 weston_log("bo geometry out of bounds\n");
353 goto err_free;
354 }
355
356 ret = -1;
357
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200358 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 handles[0] = fb->handle;
360 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361 offsets[0] = 0;
362
363 ret = drmModeAddFB2(compositor->drm.fd, width, height,
364 format, handles, pitches, offsets,
365 &fb->fb_id, 0);
366 if (ret) {
367 weston_log("addfb2 failed: %m\n");
368 compositor->no_addfb2 = 1;
369 compositor->sprites_are_broken = 1;
370 }
371 }
372
373 if (ret)
374 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200375 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200378 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300380 }
381
382 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
383
384 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
386err_free:
387 free(fb);
388 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300389}
390
391static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200392drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
393{
Pekka Paalanende685b82012-12-04 15:58:12 +0200394 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395
396 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397
Pekka Paalanende685b82012-12-04 15:58:12 +0200398 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200399}
400
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200401static void
402drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
403{
404 if (!fb)
405 return;
406
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200407 if (fb->map &&
408 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200409 drm_fb_destroy_dumb(fb);
410 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200411 if (fb->is_client_buffer)
412 gbm_bo_destroy(fb->bo);
413 else
414 gbm_surface_release_buffer(output->surface,
415 output->current->bo);
416 }
417}
418
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500419static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200420drm_output_check_scanout_format(struct drm_output *output,
421 struct weston_surface *es, struct gbm_bo *bo)
422{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200423 uint32_t format;
424 pixman_region32_t r;
425
426 format = gbm_bo_get_format(bo);
427
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500428 switch (format) {
429 case GBM_FORMAT_XRGB8888:
430 return format;
431 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200432 /* We can only scanout an ARGB buffer if the surface's
433 * opaque region covers the whole output */
434 pixman_region32_init(&r);
435 pixman_region32_subtract(&r, &output->base.region,
436 &es->opaque);
437
438 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500439 format = GBM_FORMAT_XRGB8888;
440 else
441 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200442
443 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200444
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500445 return format;
446 default:
447 return 0;
448 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200449}
450
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400451static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400452drm_output_prepare_scanout_surface(struct weston_output *_output,
453 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500454{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400455 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500456 struct drm_compositor *c =
457 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200458 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300459 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500460 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500461
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500462 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200463 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200464 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200465 buffer->width != output->base.current->width ||
466 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200467 output->base.transform != es->buffer_transform ||
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200468 output->base.scale != es->buffer_scale ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200469 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400470 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500471
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400472 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200473 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500474
Rob Bradford9b101872012-09-14 23:25:41 +0100475 /* Unable to use the buffer for scanout */
476 if (!bo)
477 return NULL;
478
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500479 format = drm_output_check_scanout_format(output, es, bo);
480 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300481 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400482 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300483 }
484
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500485 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300486 if (!output->next) {
487 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400488 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300489 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500490
Pekka Paalanende685b82012-12-04 15:58:12 +0200491 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500492
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400493 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500494}
495
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500496static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200497drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400498{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200499 struct drm_compositor *c =
500 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400502
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200503 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400504
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300505 bo = gbm_surface_lock_front_buffer(output->surface);
506 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200507 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400508 return;
509 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500511 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300512 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200513 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300514 gbm_surface_release_buffer(output->surface, bo);
515 return;
516 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400517}
518
519static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200520drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
521{
522 struct weston_compositor *ec = output->base.compositor;
523 pixman_region32_t total_damage, previous_damage;
524
525 pixman_region32_init(&total_damage);
526 pixman_region32_init(&previous_damage);
527
528 pixman_region32_copy(&previous_damage, damage);
529
530 pixman_region32_union(&total_damage, damage, &output->previous_damage);
531 pixman_region32_copy(&output->previous_damage, &previous_damage);
532
533 output->current_image ^= 1;
534
535 output->next = output->dumb[output->current_image];
536 pixman_renderer_output_set_buffer(&output->base,
537 output->image[output->current_image]);
538
539 ec->renderer->repaint_output(&output->base, &total_damage);
540
541 pixman_region32_fini(&total_damage);
542 pixman_region32_fini(&previous_damage);
543}
544
545static void
546drm_output_render(struct drm_output *output, pixman_region32_t *damage)
547{
548 struct drm_compositor *c =
549 (struct drm_compositor *) output->base.compositor;
550
551 if (c->use_pixman)
552 drm_output_render_pixman(output, damage);
553 else
554 drm_output_render_gl(output, damage);
555
556 pixman_region32_subtract(&c->base.primary_plane.damage,
557 &c->base.primary_plane.damage, damage);
558}
559
560static void
Richard Hughese7299962013-05-01 21:52:12 +0100561drm_output_set_gamma(struct weston_output *output_base,
562 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
563{
564 int rc;
565 struct drm_output *output = (struct drm_output *) output_base;
566 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
567
568 /* check */
569 if (output_base->gamma_size != size)
570 return;
571 if (!output->original_crtc)
572 return;
573
574 rc = drmModeCrtcSetGamma(compositor->drm.fd,
575 output->crtc_id,
576 size, r, g, b);
577 if (rc)
578 weston_log("set gamma failed: %m\n");
579}
580
581static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500582drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400583 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100584{
585 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500586 struct drm_compositor *compositor =
587 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400589 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500590 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100591
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300592 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400593 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300594 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400595 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100596
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400597 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300598 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400599 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300600 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400601 &output->connector_id, 1,
602 &mode->mode_info);
603 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200604 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400605 return;
606 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200607 }
608
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500609 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300610 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500611 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200612 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500613 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500614 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100615
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300616 output->page_flip_pending = 1;
617
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400618 drm_output_set_cursor(output);
619
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620 /*
621 * Now, update all the sprite surfaces
622 */
623 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200624 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500625 drmVBlank vbl = {
626 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
627 .request.sequence = 1,
628 };
629
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200630 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200631 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 continue;
633
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200634 if (s->next && !compositor->sprites_hidden)
635 fb_id = s->next->fb_id;
636
Jesse Barnes58ef3792012-02-23 09:45:49 -0500637 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200638 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 s->dest_x, s->dest_y,
640 s->dest_w, s->dest_h,
641 s->src_x, s->src_y,
642 s->src_w, s->src_h);
643 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200644 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 ret, strerror(errno));
646
Rob Clark5ca1a472012-08-08 20:27:37 -0500647 if (output->pipe > 0)
648 vbl.request.type |= DRM_VBLANK_SECONDARY;
649
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650 /*
651 * Queue a vblank signal so we know when the surface
652 * becomes active on the display or has been replaced.
653 */
654 vbl.request.signal = (unsigned long)s;
655 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
656 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200657 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658 ret, strerror(errno));
659 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300660
661 s->output = output;
662 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500663 }
664
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500665 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400666}
667
668static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200669drm_output_start_repaint_loop(struct weston_output *output_base)
670{
671 struct drm_output *output = (struct drm_output *) output_base;
672 struct drm_compositor *compositor = (struct drm_compositor *)
673 output_base->compositor;
674 uint32_t fb_id;
675
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300676 struct timespec ts;
677
678 if (!output->current) {
679 /* We can't page flip if there's no mode set */
680 uint32_t msec;
681
682 clock_gettime(compositor->clock, &ts);
683 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
684 weston_output_finish_frame(output_base, msec);
685 return;
686 }
687
688 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200689
690 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
691 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
692 weston_log("queueing pageflip failed: %m\n");
693 return;
694 }
695}
696
697static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500698vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
699 void *data)
700{
701 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300702 struct drm_output *output = s->output;
703 uint32_t msecs;
704
705 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500706
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200707 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200708 s->current = s->next;
709 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300710
711 if (!output->page_flip_pending) {
712 msecs = sec * 1000 + usec / 1000;
713 weston_output_finish_frame(&output->base, msecs);
714 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500715}
716
717static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400718page_flip_handler(int fd, unsigned int frame,
719 unsigned int sec, unsigned int usec, void *data)
720{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200721 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400722 uint32_t msecs;
723
Jonas Ådahle5a12252013-04-05 23:07:11 +0200724 /* We don't set page_flip_pending on start_repaint_loop, in that case
725 * we just want to page flip to the current buffer to get an accurate
726 * timestamp */
727 if (output->page_flip_pending) {
728 drm_output_release_fb(output, output->current);
729 output->current = output->next;
730 output->next = NULL;
731 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300732
Jonas Ådahle5a12252013-04-05 23:07:11 +0200733 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400734
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300735 if (!output->vblank_pending) {
736 msecs = sec * 1000 + usec / 1000;
737 weston_output_finish_frame(&output->base, msecs);
738 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200739}
740
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500741static uint32_t
742drm_output_check_sprite_format(struct drm_sprite *s,
743 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500744{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500745 uint32_t i, format;
746
747 format = gbm_bo_get_format(bo);
748
749 if (format == GBM_FORMAT_ARGB8888) {
750 pixman_region32_t r;
751
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500752 pixman_region32_init_rect(&r, 0, 0,
753 es->geometry.width,
754 es->geometry.height);
755 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500756
757 if (!pixman_region32_not_empty(&r))
758 format = GBM_FORMAT_XRGB8888;
759
760 pixman_region32_fini(&r);
761 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500762
763 for (i = 0; i < s->count_formats; i++)
764 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500765 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766
767 return 0;
768}
769
770static int
771drm_surface_transform_supported(struct weston_surface *es)
772{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500773 return !es->transform.enabled ||
774 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775}
776
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400777static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500778drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400779 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500780{
781 struct weston_compositor *ec = output_base->compositor;
782 struct drm_compositor *c =(struct drm_compositor *) ec;
783 struct drm_sprite *s;
784 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500785 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500786 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200787 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500788 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400789 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500790
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200791 if (c->gbm == NULL)
792 return NULL;
793
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200794 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200795 return NULL;
796
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200797 if (es->buffer_scale != output_base->scale)
798 return NULL;
799
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500800 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400801 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500802
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300803 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400804 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300805
Pekka Paalanende685b82012-12-04 15:58:12 +0200806 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400807 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200809 if (es->alpha != 1.0f)
810 return NULL;
811
Pekka Paalanende685b82012-12-04 15:58:12 +0200812 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500813 return NULL;
814
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400816 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818 wl_list_for_each(s, &c->sprite_list, link) {
819 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
820 continue;
821
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200822 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823 found = 1;
824 break;
825 }
826 }
827
828 /* No sprites available */
829 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400830 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400832 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200833 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400834 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400835 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400836
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500837 format = drm_output_check_sprite_format(s, es, bo);
838 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200839 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400840 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 }
842
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200843 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200844 if (!s->next) {
845 gbm_bo_destroy(bo);
846 return NULL;
847 }
848
Pekka Paalanende685b82012-12-04 15:58:12 +0200849 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400851 box = pixman_region32_extents(&es->transform.boundingbox);
852 s->plane.x = box->x1;
853 s->plane.y = box->y1;
854
Jesse Barnes58ef3792012-02-23 09:45:49 -0500855 /*
856 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200857 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500858 * for us already).
859 */
860 pixman_region32_init(&dest_rect);
861 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
862 &output_base->region);
863 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
864 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200865 tbox = weston_transformed_rect(output_base->width,
866 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200867 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200868 output_base->scale,
869 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200870 s->dest_x = tbox.x1;
871 s->dest_y = tbox.y1;
872 s->dest_w = tbox.x2 - tbox.x1;
873 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500874 pixman_region32_fini(&dest_rect);
875
876 pixman_region32_init(&src_rect);
877 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
878 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500879 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400880
881 weston_surface_from_global_fixed(es,
882 wl_fixed_from_int(box->x1),
883 wl_fixed_from_int(box->y1),
884 &sx1, &sy1);
885 weston_surface_from_global_fixed(es,
886 wl_fixed_from_int(box->x2),
887 wl_fixed_from_int(box->y2),
888 &sx2, &sy2);
889
890 if (sx1 < 0)
891 sx1 = 0;
892 if (sy1 < 0)
893 sy1 = 0;
894 if (sx2 > wl_fixed_from_int(es->geometry.width))
895 sx2 = wl_fixed_from_int(es->geometry.width);
896 if (sy2 > wl_fixed_from_int(es->geometry.height))
897 sy2 = wl_fixed_from_int(es->geometry.height);
898
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200899 tbox.x1 = sx1;
900 tbox.y1 = sy1;
901 tbox.x2 = sx2;
902 tbox.y2 = sy2;
903
904 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
905 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200906 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200907
908 s->src_x = tbox.x1 << 8;
909 s->src_y = tbox.y1 << 8;
910 s->src_w = (tbox.x2 - tbox.x1) << 8;
911 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500912 pixman_region32_fini(&src_rect);
913
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400914 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500915}
916
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400917static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400918drm_output_prepare_cursor_surface(struct weston_output *output_base,
919 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500920{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400921 struct drm_compositor *c =
922 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400923 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400924
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200925 if (c->gbm == NULL)
926 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200927 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
928 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400929 if (output->cursor_surface)
930 return NULL;
931 if (es->output_mask != (1u << output_base->id))
932 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500933 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400934 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200935 if (es->buffer_ref.buffer == NULL ||
936 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400937 es->geometry.width > 64 || es->geometry.height > 64)
938 return NULL;
939
940 output->cursor_surface = es;
941
942 return &output->cursor_plane;
943}
944
945static void
946drm_output_set_cursor(struct drm_output *output)
947{
948 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400949 struct drm_compositor *c =
950 (struct drm_compositor *) output->base.compositor;
951 EGLint handle, stride;
952 struct gbm_bo *bo;
953 uint32_t buf[64 * 64];
954 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400955 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500956
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400957 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400958 if (es == NULL) {
959 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
960 return;
961 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500962
Pekka Paalanende685b82012-12-04 15:58:12 +0200963 if (es->buffer_ref.buffer &&
964 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400965 pixman_region32_fini(&output->cursor_plane.damage);
966 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400967 output->current_cursor ^= 1;
968 bo = output->cursor_bo[output->current_cursor];
969 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200970 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
971 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400972 for (i = 0; i < es->geometry.height; i++)
973 memcpy(buf + i * 64, s + i * stride,
974 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500975
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400976 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300977 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400978
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400979 handle = gbm_bo_get_handle(bo).s32;
980 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500981 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300982 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500983 c->cursors_are_broken = 1;
984 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400985 }
986
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200987 x = (es->geometry.x - output->base.x) * output->base.scale;
988 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400989 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500990 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400991 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500992 c->cursors_are_broken = 1;
993 }
994
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400995 output->cursor_plane.x = x;
996 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400997 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500998}
999
Jesse Barnes58ef3792012-02-23 09:45:49 -05001000static void
1001drm_assign_planes(struct weston_output *output)
1002{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001003 struct drm_compositor *c =
1004 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001005 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001006 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001007 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001008
1009 /*
1010 * Find a surface for each sprite in the output using some heuristics:
1011 * 1) size
1012 * 2) frequency of update
1013 * 3) opacity (though some hw might support alpha blending)
1014 * 4) clipping (this can be fixed with color keys)
1015 *
1016 * The idea is to save on blitting since this should save power.
1017 * If we can get a large video surface on the sprite for example,
1018 * the main display surface may not need to update at all, and
1019 * the client buffer can be used directly for the sprite surface
1020 * as we do for flipping full screen surfaces.
1021 */
1022 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001023 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001024 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001025 /* test whether this buffer can ever go into a plane:
1026 * non-shm, or small enough to be a cursor
1027 */
1028 if ((es->buffer_ref.buffer &&
1029 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1030 (es->geometry.width <= 64 && es->geometry.height <= 64))
1031 es->keep_buffer = 1;
1032 else
1033 es->keep_buffer = 0;
1034
Jesse Barnes58ef3792012-02-23 09:45:49 -05001035 pixman_region32_init(&surface_overlap);
1036 pixman_region32_intersect(&surface_overlap, &overlap,
1037 &es->transform.boundingbox);
1038
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001039 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001040 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001041 next_plane = primary;
1042 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001043 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001044 if (next_plane == NULL)
1045 next_plane = drm_output_prepare_scanout_surface(output, es);
1046 if (next_plane == NULL)
1047 next_plane = drm_output_prepare_overlay_surface(output, es);
1048 if (next_plane == NULL)
1049 next_plane = primary;
1050 weston_surface_move_to_plane(es, next_plane);
1051 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001052 pixman_region32_union(&overlap, &overlap,
1053 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001054
Jesse Barnes58ef3792012-02-23 09:45:49 -05001055 pixman_region32_fini(&surface_overlap);
1056 }
1057 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001058}
1059
Matt Roper361d2ad2011-08-29 13:52:23 -07001060static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001061drm_output_fini_pixman(struct drm_output *output);
1062
1063static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001064drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001065{
1066 struct drm_output *output = (struct drm_output *) output_base;
1067 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001068 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001069 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001070
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001071 if (output->backlight)
1072 backlight_destroy(output->backlight);
1073
Matt Roper361d2ad2011-08-29 13:52:23 -07001074 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001075 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001076
1077 /* Restore original CRTC state */
1078 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001079 origcrtc->x, origcrtc->y,
1080 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001081 drmModeFreeCrtc(origcrtc);
1082
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001083 c->crtc_allocator &= ~(1 << output->crtc_id);
1084 c->connector_allocator &= ~(1 << output->connector_id);
1085
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001086 if (c->use_pixman) {
1087 drm_output_fini_pixman(output);
1088 } else {
1089 gl_renderer_output_destroy(output_base);
1090 gbm_surface_destroy(output->surface);
1091 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001092
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001093 weston_plane_release(&output->fb_plane);
1094 weston_plane_release(&output->cursor_plane);
1095
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001096 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001097 wl_list_remove(&output->base.link);
1098
Matt Roper361d2ad2011-08-29 13:52:23 -07001099 free(output);
1100}
1101
Alex Wub7b8bda2012-04-17 17:20:48 +08001102static struct drm_mode *
1103choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1104{
1105 struct drm_mode *tmp_mode = NULL, *mode;
1106
1107 if (output->base.current->width == target_mode->width &&
1108 output->base.current->height == target_mode->height &&
1109 (output->base.current->refresh == target_mode->refresh ||
1110 target_mode->refresh == 0))
1111 return (struct drm_mode *)output->base.current;
1112
1113 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1114 if (mode->mode_info.hdisplay == target_mode->width &&
1115 mode->mode_info.vdisplay == target_mode->height) {
1116 if (mode->mode_info.vrefresh == target_mode->refresh ||
1117 target_mode->refresh == 0) {
1118 return mode;
1119 } else if (!tmp_mode)
1120 tmp_mode = mode;
1121 }
1122 }
1123
1124 return tmp_mode;
1125}
1126
1127static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001128drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001129static int
1130drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001131
1132static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001133drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1134{
1135 struct drm_output *output;
1136 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001137 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001138
1139 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001140 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001141 return -1;
1142 }
1143
1144 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001145 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001146 return -1;
1147 }
1148
1149 ec = (struct drm_compositor *)output_base->compositor;
1150 output = (struct drm_output *)output_base;
1151 drm_mode = choose_mode (output, mode);
1152
1153 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001154 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001155 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001156 }
1157
1158 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001159 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001160
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001161 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001162
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001163 output->base.current = &drm_mode->base;
1164 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001165 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1166
Alex Wub7b8bda2012-04-17 17:20:48 +08001167 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001168 drm_output_release_fb(output, output->current);
1169 drm_output_release_fb(output, output->next);
1170 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001171
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001172 if (ec->use_pixman) {
1173 drm_output_fini_pixman(output);
1174 if (drm_output_init_pixman(output, ec) < 0) {
1175 weston_log("failed to init output pixman state with "
1176 "new mode\n");
1177 return -1;
1178 }
1179 } else {
1180 gl_renderer_output_destroy(&output->base);
1181 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001182
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001183 if (drm_output_init_egl(output, ec) < 0) {
1184 weston_log("failed to init output egl state with "
1185 "new mode");
1186 return -1;
1187 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001188 }
1189
Alex Wub7b8bda2012-04-17 17:20:48 +08001190 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001191}
1192
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001193static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001194on_drm_input(int fd, uint32_t mask, void *data)
1195{
1196 drmEventContext evctx;
1197
1198 memset(&evctx, 0, sizeof evctx);
1199 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1200 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001201 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001202 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001203
1204 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001205}
1206
1207static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001208init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001209{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001210 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001211 uint64_t cap;
1212 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001213
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001214 sysnum = udev_device_get_sysnum(device);
1215 if (sysnum)
1216 ec->drm.id = atoi(sysnum);
1217 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001218 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001219 return -1;
1220 }
1221
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001222 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001223 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001224 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001225 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001226 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001227 udev_device_get_devnode(device));
1228 return -1;
1229 }
1230
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001231 weston_log("using %s\n", filename);
1232
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001233 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001234
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001235 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1236 if (ret == 0 && cap == 1)
1237 ec->clock = CLOCK_MONOTONIC;
1238 else
1239 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001240
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001241 return 0;
1242}
1243
1244static int
1245init_egl(struct drm_compositor *ec)
1246{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001247 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001248
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001249 if (!ec->gbm)
1250 return -1;
1251
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001252 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001253 NULL) < 0) {
1254 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001255 return -1;
1256 }
1257
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001258 return 0;
1259}
1260
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001261static int
1262init_pixman(struct drm_compositor *ec)
1263{
1264 return pixman_renderer_init(&ec->base);
1265}
1266
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001267static struct drm_mode *
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001268drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info, struct drm_configured_output *config)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001269{
1270 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001271 uint64_t refresh;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001272 int scale;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001273
1274 mode = malloc(sizeof *mode);
1275 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001276 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001277
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001278 scale = 1;
1279 if (config)
1280 scale = config->scale;
1281
1282 if (info->hdisplay % scale != 0 ||
1283 info->vdisplay % scale) {
1284 weston_log("Mode %dx%d not multiple of scale %d\n", info->hdisplay, info->vdisplay, scale);
1285 return NULL;
1286 }
1287
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001288 mode->base.flags = 0;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001289 mode->base.width = info->hdisplay / scale;
1290 mode->base.height = info->vdisplay / scale;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001291
1292 /* Calculate higher precision (mHz) refresh rate */
1293 refresh = (info->clock * 1000000LL / info->htotal +
1294 info->vtotal / 2) / info->vtotal;
1295
1296 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1297 refresh *= 2;
1298 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1299 refresh /= 2;
1300 if (info->vscan > 1)
1301 refresh /= info->vscan;
1302
1303 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001304 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001305
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001306 if (scale != 1)
1307 mode->base.flags |= WL_OUTPUT_MODE_SCALED;
1308
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001309 if (info->type & DRM_MODE_TYPE_PREFERRED)
1310 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1311
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001312 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1313
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001314 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001315}
1316
1317static int
1318drm_subpixel_to_wayland(int drm_value)
1319{
1320 switch (drm_value) {
1321 default:
1322 case DRM_MODE_SUBPIXEL_UNKNOWN:
1323 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1324 case DRM_MODE_SUBPIXEL_NONE:
1325 return WL_OUTPUT_SUBPIXEL_NONE;
1326 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1327 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1328 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1329 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1330 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1331 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1332 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1333 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1334 }
1335}
1336
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001337/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001338static uint32_t
1339drm_get_backlight(struct drm_output *output)
1340{
1341 long brightness, max_brightness, norm;
1342
1343 brightness = backlight_get_brightness(output->backlight);
1344 max_brightness = backlight_get_max_brightness(output->backlight);
1345
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001346 /* convert it on a scale of 0 to 255 */
1347 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001348
1349 return (uint32_t) norm;
1350}
1351
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001352/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001353static void
1354drm_set_backlight(struct weston_output *output_base, uint32_t value)
1355{
1356 struct drm_output *output = (struct drm_output *) output_base;
1357 long max_brightness, new_brightness;
1358
1359 if (!output->backlight)
1360 return;
1361
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001362 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001363 return;
1364
1365 max_brightness = backlight_get_max_brightness(output->backlight);
1366
1367 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001368 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001369
1370 backlight_set_brightness(output->backlight, new_brightness);
1371}
1372
1373static drmModePropertyPtr
1374drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1375{
1376 drmModePropertyPtr props;
1377 int i;
1378
1379 for (i = 0; i < connector->count_props; i++) {
1380 props = drmModeGetProperty(fd, connector->props[i]);
1381 if (!props)
1382 continue;
1383
1384 if (!strcmp(props->name, name))
1385 return props;
1386
1387 drmModeFreeProperty(props);
1388 }
1389
1390 return NULL;
1391}
1392
1393static void
1394drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1395{
1396 struct drm_output *output = (struct drm_output *) output_base;
1397 struct weston_compositor *ec = output_base->compositor;
1398 struct drm_compositor *c = (struct drm_compositor *) ec;
1399 drmModeConnectorPtr connector;
1400 drmModePropertyPtr prop;
1401
1402 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1403 if (!connector)
1404 return;
1405
1406 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1407 if (!prop) {
1408 drmModeFreeConnector(connector);
1409 return;
1410 }
1411
1412 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1413 prop->prop_id, level);
1414 drmModeFreeProperty(prop);
1415 drmModeFreeConnector(connector);
1416}
1417
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001418static const char *connector_type_names[] = {
1419 "None",
1420 "VGA",
1421 "DVI",
1422 "DVI",
1423 "DVI",
1424 "Composite",
1425 "TV",
1426 "LVDS",
1427 "CTV",
1428 "DIN",
1429 "DP",
1430 "HDMI",
1431 "HDMI",
1432 "TV",
1433 "eDP",
1434};
1435
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001436static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001437find_crtc_for_connector(struct drm_compositor *ec,
1438 drmModeRes *resources, drmModeConnector *connector)
1439{
1440 drmModeEncoder *encoder;
1441 uint32_t possible_crtcs;
1442 int i, j;
1443
1444 for (j = 0; j < connector->count_encoders; j++) {
1445 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1446 if (encoder == NULL) {
1447 weston_log("Failed to get encoder.\n");
1448 return -1;
1449 }
1450 possible_crtcs = encoder->possible_crtcs;
1451 drmModeFreeEncoder(encoder);
1452
1453 for (i = 0; i < resources->count_crtcs; i++) {
1454 if (possible_crtcs & (1 << i) &&
1455 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1456 return i;
1457 }
1458 }
1459
1460 return -1;
1461}
1462
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001463/* Init output state that depends on gl or gbm */
1464static int
1465drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1466{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001467 int i, flags;
1468
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001469 output->surface = gbm_surface_create(ec->gbm,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001470 output->base.current->width * output->base.scale,
1471 output->base.current->height * output->base.scale,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001472 GBM_FORMAT_XRGB8888,
1473 GBM_BO_USE_SCANOUT |
1474 GBM_BO_USE_RENDERING);
1475 if (!output->surface) {
1476 weston_log("failed to create gbm surface\n");
1477 return -1;
1478 }
1479
1480 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001481 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001482 gbm_surface_destroy(output->surface);
1483 return -1;
1484 }
1485
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001486 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1487
1488 for (i = 0; i < 2; i++) {
1489 if (output->cursor_bo[i])
1490 continue;
1491
1492 output->cursor_bo[i] =
1493 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1494 flags);
1495 }
1496
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001497 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1498 weston_log("cursor buffers unavailable, using gl cursors\n");
1499 ec->cursors_are_broken = 1;
1500 }
1501
1502 return 0;
1503}
1504
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001505static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001506drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1507{
1508 int w = output->base.current->width;
1509 int h = output->base.current->height;
1510 unsigned int i;
1511
1512 /* FIXME error checking */
1513
1514 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001515 output->dumb[i] = drm_fb_create_dumb(c, w * output->base.scale, h * output->base.scale);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001516 if (!output->dumb[i])
1517 goto err;
1518
1519 output->image[i] =
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001520 pixman_image_create_bits(PIXMAN_x8r8g8b8, w * output->base.scale, h * output->base.scale,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001521 output->dumb[i]->map,
1522 output->dumb[i]->stride);
1523 if (!output->image[i])
1524 goto err;
1525 }
1526
1527 if (pixman_renderer_output_create(&output->base) < 0)
1528 goto err;
1529
1530 pixman_region32_init_rect(&output->previous_damage,
1531 output->base.x, output->base.y, w, h);
1532
1533 return 0;
1534
1535err:
1536 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1537 if (output->dumb[i])
1538 drm_fb_destroy_dumb(output->dumb[i]);
1539 if (output->image[i])
1540 pixman_image_unref(output->image[i]);
1541
1542 output->dumb[i] = NULL;
1543 output->image[i] = NULL;
1544 }
1545
1546 return -1;
1547}
1548
1549static void
1550drm_output_fini_pixman(struct drm_output *output)
1551{
1552 unsigned int i;
1553
1554 pixman_renderer_output_destroy(&output->base);
1555 pixman_region32_fini(&output->previous_damage);
1556
1557 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1558 drm_fb_destroy_dumb(output->dumb[i]);
1559 pixman_image_unref(output->image[i]);
1560 output->dumb[i] = NULL;
1561 output->image[i] = NULL;
1562 }
1563}
1564
Richard Hughes2b2092a2013-04-24 14:58:02 +01001565static void
1566edid_parse_string(const uint8_t *data, char text[])
1567{
1568 int i;
1569 int replaced = 0;
1570
1571 /* this is always 12 bytes, but we can't guarantee it's null
1572 * terminated or not junk. */
1573 strncpy(text, (const char *) data, 12);
1574
1575 /* remove insane chars */
1576 for (i = 0; text[i] != '\0'; i++) {
1577 if (text[i] == '\n' ||
1578 text[i] == '\r') {
1579 text[i] = '\0';
1580 break;
1581 }
1582 }
1583
1584 /* ensure string is printable */
1585 for (i = 0; text[i] != '\0'; i++) {
1586 if (!isprint(text[i])) {
1587 text[i] = '-';
1588 replaced++;
1589 }
1590 }
1591
1592 /* if the string is random junk, ignore the string */
1593 if (replaced > 4)
1594 text[0] = '\0';
1595}
1596
1597#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1598#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1599#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1600#define EDID_OFFSET_DATA_BLOCKS 0x36
1601#define EDID_OFFSET_LAST_BLOCK 0x6c
1602#define EDID_OFFSET_PNPID 0x08
1603#define EDID_OFFSET_SERIAL 0x0c
1604
1605static int
1606edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1607{
1608 int i;
1609 uint32_t serial_number;
1610
1611 /* check header */
1612 if (length < 128)
1613 return -1;
1614 if (data[0] != 0x00 || data[1] != 0xff)
1615 return -1;
1616
1617 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1618 * /--08--\/--09--\
1619 * 7654321076543210
1620 * |\---/\---/\---/
1621 * R C1 C2 C3 */
1622 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1623 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1624 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1625 edid->pnp_id[3] = '\0';
1626
1627 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1628 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1629 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1630 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1631 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1632 if (serial_number > 0)
1633 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1634
1635 /* parse EDID data */
1636 for (i = EDID_OFFSET_DATA_BLOCKS;
1637 i <= EDID_OFFSET_LAST_BLOCK;
1638 i += 18) {
1639 /* ignore pixel clock data */
1640 if (data[i] != 0)
1641 continue;
1642 if (data[i+2] != 0)
1643 continue;
1644
1645 /* any useful blocks? */
1646 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1647 edid_parse_string(&data[i+5],
1648 edid->monitor_name);
1649 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1650 edid_parse_string(&data[i+5],
1651 edid->serial_number);
1652 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1653 edid_parse_string(&data[i+5],
1654 edid->eisa_id);
1655 }
1656 }
1657 return 0;
1658}
1659
1660static void
1661find_and_parse_output_edid(struct drm_compositor *ec,
1662 struct drm_output *output,
1663 drmModeConnector *connector)
1664{
1665 drmModePropertyBlobPtr edid_blob = NULL;
1666 drmModePropertyPtr property;
1667 int i;
1668 int rc;
1669
1670 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1671 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1672 if (!property)
1673 continue;
1674 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1675 !strcmp(property->name, "EDID")) {
1676 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1677 connector->prop_values[i]);
1678 }
1679 drmModeFreeProperty(property);
1680 }
1681 if (!edid_blob)
1682 return;
1683
1684 rc = edid_parse(&output->edid,
1685 edid_blob->data,
1686 edid_blob->length);
1687 if (!rc) {
1688 weston_log("EDID data '%s', '%s', '%s'\n",
1689 output->edid.pnp_id,
1690 output->edid.monitor_name,
1691 output->edid.serial_number);
1692 if (output->edid.pnp_id[0] != '\0')
1693 output->base.make = output->edid.pnp_id;
1694 if (output->edid.monitor_name[0] != '\0')
1695 output->base.model = output->edid.monitor_name;
1696 if (output->edid.serial_number[0] != '\0')
1697 output->base.serial_number = output->edid.serial_number;
1698 }
1699 drmModeFreePropertyBlob(edid_blob);
1700}
1701
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001702static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001703create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001704 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001705 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001706 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001707{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001708 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001709 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1710 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001711 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001712 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001713 drmModeModeInfo crtc_mode;
1714 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001715 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001716 char name[32];
1717 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001718
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001719 i = find_crtc_for_connector(ec, resources, connector);
1720 if (i < 0) {
1721 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001722 return -1;
1723 }
1724
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001725 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001726 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001727 return -1;
1728
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001729 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001730 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1731 output->base.make = "unknown";
1732 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001733 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001734 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001735
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001736 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1737 type_name = connector_type_names[connector->connector_type];
1738 else
1739 type_name = "UNKNOWN";
1740 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001741 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001742
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001743 wl_list_for_each(temp, &configured_output_list, link) {
1744 if (strcmp(temp->name, output->base.name) == 0) {
1745 if (temp->mode)
1746 weston_log("%s mode \"%s\" in config\n",
1747 temp->name, temp->mode);
1748 o = temp;
1749 break;
1750 }
1751 }
1752
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001753 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001754 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001755 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001756 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001757 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001758
Matt Roper361d2ad2011-08-29 13:52:23 -07001759 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1760
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001761 /* Get the current mode on the crtc that's currently driving
1762 * this connector. */
1763 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001764 memset(&crtc_mode, 0, sizeof crtc_mode);
1765 if (encoder != NULL) {
1766 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1767 drmModeFreeEncoder(encoder);
1768 if (crtc == NULL)
1769 goto err_free;
1770 if (crtc->mode_valid)
1771 crtc_mode = crtc->mode;
1772 drmModeFreeCrtc(crtc);
1773 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001774
David Herrmann0f0d54e2011-12-08 17:05:45 +01001775 for (i = 0; i < connector->count_modes; i++) {
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001776 drm_mode = drm_output_add_mode(output, &connector->modes[i], o);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001777 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001778 goto err_free;
1779 }
1780
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001781 preferred = NULL;
1782 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001783 configured = NULL;
1784
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001785 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001786 weston_log("Disabling output %s\n", o->name);
1787
1788 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1789 0, 0, 0, 0, 0, NULL);
1790 goto err_free;
1791 }
1792
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001793 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001794 if (o && o->config == OUTPUT_CONFIG_MODE &&
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001795 o->width == drm_mode->base.width * o->scale &&
1796 o->height == drm_mode->base.height * o->scale)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001797 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001798 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001799 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001800 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001801 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001802 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001803
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001804 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001805 configured = drm_output_add_mode(output, &o->crtc_mode, 0);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001806 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001807 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001808 current = configured;
1809 }
1810
Wang Quanxianacb805a2012-07-30 18:09:46 -04001811 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001812 current = drm_output_add_mode(output, &crtc_mode, 0);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001813 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001814 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001815 }
1816
Scott Moreau8ab5d452012-07-30 19:51:08 -06001817 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1818 configured = current;
1819
Wang Quanxianacb805a2012-07-30 18:09:46 -04001820 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001821 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001822 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001823 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001824 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001825 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001826 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001827 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001828
1829 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001830 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001831 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001832 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001833
Wang Quanxianacb805a2012-07-30 18:09:46 -04001834 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1835
John Kåre Alsaker94659272012-11-13 19:10:18 +01001836 weston_output_init(&output->base, &ec->base, x, y,
1837 connector->mmWidth, connector->mmHeight,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001838 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL,
1839 o ? o->scale : 1);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001840
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001841 if (ec->use_pixman) {
1842 if (drm_output_init_pixman(output, ec) < 0) {
1843 weston_log("Failed to init output pixman state\n");
1844 goto err_output;
1845 }
1846 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001847 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001848 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001849 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001850
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001851 output->backlight = backlight_init(drm_device,
1852 connector->connector_type);
1853 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001854 weston_log("Initialized backlight, device %s\n",
1855 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001856 output->base.set_backlight = drm_set_backlight;
1857 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001858 } else {
1859 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001860 }
1861
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001862 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1863
Richard Hughes2b2092a2013-04-24 14:58:02 +01001864 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001865 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1866 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001867
Alex Wubd3354b2012-04-17 17:20:49 +08001868 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001869 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001870 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001871 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001872 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001873 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001874 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001875
Richard Hughese7299962013-05-01 21:52:12 +01001876 output->base.gamma_size = output->original_crtc->gamma_size;
1877 output->base.set_gamma = drm_output_set_gamma;
1878
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001879 weston_plane_init(&output->cursor_plane, 0, 0);
1880 weston_plane_init(&output->fb_plane, 0, 0);
1881
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001882 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1883 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1884 &ec->base.primary_plane);
1885
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001886 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001887 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001888 wl_list_for_each(m, &output->base.mode_list, link)
1889 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1890 m->width, m->height, m->refresh / 1000.0,
1891 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1892 ", preferred" : "",
1893 m->flags & WL_OUTPUT_MODE_CURRENT ?
1894 ", current" : "",
1895 connector->count_modes == 0 ?
1896 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001897
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001898 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001899
John Kåre Alsaker94659272012-11-13 19:10:18 +01001900err_output:
1901 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001902err_free:
1903 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1904 base.link) {
1905 wl_list_remove(&drm_mode->base.link);
1906 free(drm_mode);
1907 }
1908
1909 drmModeFreeCrtc(output->original_crtc);
1910 ec->crtc_allocator &= ~(1 << output->crtc_id);
1911 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001912 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001913
David Herrmann0f0d54e2011-12-08 17:05:45 +01001914 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001915}
1916
Jesse Barnes58ef3792012-02-23 09:45:49 -05001917static void
1918create_sprites(struct drm_compositor *ec)
1919{
1920 struct drm_sprite *sprite;
1921 drmModePlaneRes *plane_res;
1922 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001923 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001924
1925 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1926 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001927 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001928 strerror(errno));
1929 return;
1930 }
1931
1932 for (i = 0; i < plane_res->count_planes; i++) {
1933 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1934 if (!plane)
1935 continue;
1936
1937 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1938 plane->count_formats));
1939 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001940 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001941 __func__);
1942 free(plane);
1943 continue;
1944 }
1945
1946 memset(sprite, 0, sizeof *sprite);
1947
1948 sprite->possible_crtcs = plane->possible_crtcs;
1949 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001950 sprite->current = NULL;
1951 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001952 sprite->compositor = ec;
1953 sprite->count_formats = plane->count_formats;
1954 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001955 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001956 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001957 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001958 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1959 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001960
1961 wl_list_insert(&ec->sprite_list, &sprite->link);
1962 }
1963
1964 free(plane_res->planes);
1965 free(plane_res);
1966}
1967
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001968static void
1969destroy_sprites(struct drm_compositor *compositor)
1970{
1971 struct drm_sprite *sprite, *next;
1972 struct drm_output *output;
1973
1974 output = container_of(compositor->base.output_list.next,
1975 struct drm_output, base.link);
1976
1977 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1978 drmModeSetPlane(compositor->drm.fd,
1979 sprite->plane_id,
1980 output->crtc_id, 0, 0,
1981 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001982 drm_output_release_fb(output, sprite->current);
1983 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001984 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001985 free(sprite);
1986 }
1987}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001988
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001989static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001990create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001991 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001992{
1993 drmModeConnector *connector;
1994 drmModeRes *resources;
1995 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001996 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001997
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001998 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001999 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002000 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002001 return -1;
2002 }
2003
Jesse Barnes58ef3792012-02-23 09:45:49 -05002004 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002005 if (!ec->crtcs) {
2006 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002007 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002008 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002009
Rob Clark4339add2012-08-09 14:18:28 -05002010 ec->min_width = resources->min_width;
2011 ec->max_width = resources->max_width;
2012 ec->min_height = resources->min_height;
2013 ec->max_height = resources->max_height;
2014
Jesse Barnes58ef3792012-02-23 09:45:49 -05002015 ec->num_crtcs = resources->count_crtcs;
2016 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2017
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002018 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002019 connector = drmModeGetConnector(ec->drm.fd,
2020 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002021 if (connector == NULL)
2022 continue;
2023
2024 if (connector->connection == DRM_MODE_CONNECTED &&
2025 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002026 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002027 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002028 connector, x, y,
2029 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002030 drmModeFreeConnector(connector);
2031 continue;
2032 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002033
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002034 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002035 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002036 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002037 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002038
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002039 drmModeFreeConnector(connector);
2040 }
2041
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002042 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002043 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002044 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002045 return -1;
2046 }
2047
2048 drmModeFreeResources(resources);
2049
2050 return 0;
2051}
2052
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002053static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002054update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002055{
2056 drmModeConnector *connector;
2057 drmModeRes *resources;
2058 struct drm_output *output, *next;
2059 int x = 0, y = 0;
2060 int x_offset = 0, y_offset = 0;
2061 uint32_t connected = 0, disconnects = 0;
2062 int i;
2063
2064 resources = drmModeGetResources(ec->drm.fd);
2065 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002066 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002067 return;
2068 }
2069
2070 /* collect new connects */
2071 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002072 int connector_id = resources->connectors[i];
2073
2074 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002075 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002076 continue;
2077
David Herrmann7551cff2011-12-08 17:05:43 +01002078 if (connector->connection != DRM_MODE_CONNECTED) {
2079 drmModeFreeConnector(connector);
2080 continue;
2081 }
2082
Benjamin Franzke117483d2011-08-30 11:38:26 +02002083 connected |= (1 << connector_id);
2084
2085 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002086 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002087 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002088 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002089
2090 /* XXX: not yet needed, we die with 0 outputs */
2091 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002092 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002093 else
2094 x = 0;
2095 y = 0;
2096 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002097 connector, x, y,
2098 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002099 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002100
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002101 }
2102 drmModeFreeConnector(connector);
2103 }
2104 drmModeFreeResources(resources);
2105
2106 disconnects = ec->connector_allocator & ~connected;
2107 if (disconnects) {
2108 wl_list_for_each_safe(output, next, &ec->base.output_list,
2109 base.link) {
2110 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002111 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002112 output->base.x - x_offset,
2113 output->base.y - y_offset);
2114 }
2115
2116 if (disconnects & (1 << output->connector_id)) {
2117 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002118 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002119 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002120 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002121 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002122 }
2123 }
2124 }
2125
2126 /* FIXME: handle zero outputs, without terminating */
2127 if (ec->connector_allocator == 0)
2128 wl_display_terminate(ec->base.wl_display);
2129}
2130
2131static int
David Herrmannd7488c22012-03-11 20:05:21 +01002132udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002133{
David Herrmannd7488c22012-03-11 20:05:21 +01002134 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002135 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002136
2137 sysnum = udev_device_get_sysnum(device);
2138 if (!sysnum || atoi(sysnum) != ec->drm.id)
2139 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002140
David Herrmann6ac52db2012-03-11 20:05:22 +01002141 val = udev_device_get_property_value(device, "HOTPLUG");
2142 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002143 return 0;
2144
David Herrmann6ac52db2012-03-11 20:05:22 +01002145 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002146}
2147
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002148static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002149udev_drm_event(int fd, uint32_t mask, void *data)
2150{
2151 struct drm_compositor *ec = data;
2152 struct udev_device *event;
2153
2154 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002155
David Herrmannd7488c22012-03-11 20:05:21 +01002156 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002157 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002158
2159 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002160
2161 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002162}
2163
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002164static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002165drm_restore(struct weston_compositor *ec)
2166{
2167 struct drm_compositor *d = (struct drm_compositor *) ec;
2168
2169 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2170 weston_log("failed to drop master: %m\n");
2171 tty_reset(d->tty);
2172}
2173
2174static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002175drm_free_configured_output(struct drm_configured_output *output)
2176{
2177 free(output->name);
2178 free(output->mode);
2179 free(output);
2180}
2181
2182static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002183drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002184{
2185 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002186 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002187 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002188
Kristian Høgsberge8091032013-02-18 15:43:29 -05002189 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2190 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002191 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002192 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002193
2194 wl_event_source_remove(d->udev_drm_source);
2195 wl_event_source_remove(d->drm_source);
2196
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002197 destroy_sprites(d);
2198
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002199 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002200
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002201 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002202
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002203 if (d->gbm)
2204 gbm_device_destroy(d->gbm);
2205
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002206 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002207 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002208 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002209
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002210 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002211}
2212
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002213static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002214drm_compositor_set_modes(struct drm_compositor *compositor)
2215{
2216 struct drm_output *output;
2217 struct drm_mode *drm_mode;
2218 int ret;
2219
2220 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002221 if (!output->current) {
2222 /* If something that would cause the output to
2223 * switch mode happened while in another vt, we
2224 * might not have a current drm_fb. In that case,
2225 * schedule a repaint and let drm_output_repaint
2226 * handle setting the mode. */
2227 weston_output_schedule_repaint(&output->base);
2228 continue;
2229 }
2230
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002231 drm_mode = (struct drm_mode *) output->base.current;
2232 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002233 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002234 &output->connector_id, 1,
2235 &drm_mode->mode_info);
2236 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002237 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002238 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002239 drm_mode->base.width, drm_mode->base.height,
2240 output->base.x, output->base.y);
2241 }
2242 }
2243}
2244
2245static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002246vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002247{
2248 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002249 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002250 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002251 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002252
2253 switch (event) {
2254 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002255 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002256 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002257 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002258 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002259 wl_display_terminate(compositor->wl_display);
2260 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002261 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002262 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002263 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002264 wl_list_for_each(seat, &compositor->seat_list, base.link)
2265 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002266 break;
2267 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002268 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002269 wl_list_for_each(seat, &compositor->seat_list, base.link)
2270 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002271
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002272 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002273 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002274 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002275
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002276 /* If we have a repaint scheduled (either from a
2277 * pending pageflip or the idle handler), make sure we
2278 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002279 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002280 * further attemps at repainting. When we switch
2281 * back, we schedule a repaint, which will process
2282 * pending frame callbacks. */
2283
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002284 wl_list_for_each(output, &ec->base.output_list, base.link) {
2285 output->base.repaint_needed = 0;
2286 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002287 }
2288
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002289 output = container_of(ec->base.output_list.next,
2290 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002291
2292 wl_list_for_each(sprite, &ec->sprite_list, link)
2293 drmModeSetPlane(ec->drm.fd,
2294 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002295 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002296 0, 0, 0, 0, 0, 0, 0, 0);
2297
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002298 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002299 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002300
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002301 break;
2302 };
2303}
2304
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002305static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002306switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002307{
2308 struct drm_compositor *ec = data;
2309
Daniel Stone325fc2d2012-05-30 16:31:58 +01002310 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002311}
2312
David Herrmann0af066f2012-10-29 19:21:16 +01002313/*
2314 * Find primary GPU
2315 * Some systems may have multiple DRM devices attached to a single seat. This
2316 * function loops over all devices and tries to find a PCI device with the
2317 * boot_vga sysfs attribute set to 1.
2318 * If no such device is found, the first DRM device reported by udev is used.
2319 */
2320static struct udev_device*
2321find_primary_gpu(struct drm_compositor *ec, const char *seat)
2322{
2323 struct udev_enumerate *e;
2324 struct udev_list_entry *entry;
2325 const char *path, *device_seat, *id;
2326 struct udev_device *device, *drm_device, *pci;
2327
2328 e = udev_enumerate_new(ec->udev);
2329 udev_enumerate_add_match_subsystem(e, "drm");
2330 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2331
2332 udev_enumerate_scan_devices(e);
2333 drm_device = NULL;
2334 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2335 path = udev_list_entry_get_name(entry);
2336 device = udev_device_new_from_syspath(ec->udev, path);
2337 if (!device)
2338 continue;
2339 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2340 if (!device_seat)
2341 device_seat = default_seat;
2342 if (strcmp(device_seat, seat)) {
2343 udev_device_unref(device);
2344 continue;
2345 }
2346
2347 pci = udev_device_get_parent_with_subsystem_devtype(device,
2348 "pci", NULL);
2349 if (pci) {
2350 id = udev_device_get_sysattr_value(pci, "boot_vga");
2351 if (id && !strcmp(id, "1")) {
2352 if (drm_device)
2353 udev_device_unref(drm_device);
2354 drm_device = device;
2355 break;
2356 }
2357 }
2358
2359 if (!drm_device)
2360 drm_device = device;
2361 else
2362 udev_device_unref(device);
2363 }
2364
2365 udev_enumerate_unref(e);
2366 return drm_device;
2367}
2368
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002369static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002370planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002371{
2372 struct drm_compositor *c = data;
2373
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002374 switch (key) {
2375 case KEY_C:
2376 c->cursors_are_broken ^= 1;
2377 break;
2378 case KEY_V:
2379 c->sprites_are_broken ^= 1;
2380 break;
2381 case KEY_O:
2382 c->sprites_hidden ^= 1;
2383 break;
2384 default:
2385 break;
2386 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002387}
2388
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002389static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002390drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002391 int connector, const char *seat, int tty, int pixman,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002392 int *argc, char *argv[], int config_fd)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002393{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002394 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002395 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002396 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002397 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002398 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002399 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002400
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002401 weston_log("initializing drm backend\n");
2402
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002403 ec = malloc(sizeof *ec);
2404 if (ec == NULL)
2405 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002406 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002407
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002408 /* KMS support for sprites is not complete yet, so disable the
2409 * functionality for now. */
2410 ec->sprites_are_broken = 1;
2411
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002412 ec->use_pixman = pixman;
2413
Daniel Stone725c2c32012-06-22 14:04:36 +01002414 if (weston_compositor_init(&ec->base, display, argc, argv,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002415 config_fd) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002416 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002417 goto err_base;
2418 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002419
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002420 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002421 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002422 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002423 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002424 goto err_compositor;
2425 }
2426
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002427 ec->udev = udev_new();
2428 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002429 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002430 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002431 }
2432
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002433 ec->base.wl_display = display;
2434 ec->tty = tty_create(&ec->base, vt_func, tty);
2435 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002436 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002437 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002438 }
2439
David Herrmann0af066f2012-10-29 19:21:16 +01002440 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002441 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002442 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002443 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002444 }
David Herrmann0af066f2012-10-29 19:21:16 +01002445 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002446
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002447 if (init_drm(ec, drm_device) < 0) {
2448 weston_log("failed to initialize kms\n");
2449 goto err_udev_dev;
2450 }
2451
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002452 if (ec->use_pixman) {
2453 if (init_pixman(ec) < 0) {
2454 weston_log("failed to initialize pixman renderer\n");
2455 goto err_udev_dev;
2456 }
2457 } else {
2458 if (init_egl(ec) < 0) {
2459 weston_log("failed to initialize egl\n");
2460 goto err_udev_dev;
2461 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002462 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002463
2464 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002465 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002466
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002467 ec->base.focus = 1;
2468
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002469 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002470
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002471 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002472 weston_compositor_add_key_binding(&ec->base, key,
2473 MODIFIER_CTRL | MODIFIER_ALT,
2474 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002475
Jesse Barnes58ef3792012-02-23 09:45:49 -05002476 wl_list_init(&ec->sprite_list);
2477 create_sprites(ec);
2478
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002479 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002480 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002481 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002482 }
2483
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002484 path = NULL;
2485
Kristian Høgsberge8091032013-02-18 15:43:29 -05002486 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002487 weston_log("failed to create input devices\n");
2488 goto err_sprite;
2489 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002490
2491 loop = wl_display_get_event_loop(ec->base.wl_display);
2492 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002493 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002494 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002495
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002496 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2497 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002498 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002499 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002500 }
2501 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2502 "drm", NULL);
2503 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002504 wl_event_loop_add_fd(loop,
2505 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002506 WL_EVENT_READABLE, udev_drm_event, ec);
2507
2508 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002509 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002510 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002511 }
2512
Daniel Stonea96b93c2012-06-22 14:04:37 +01002513 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002514
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002515 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002516 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002517 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002518 planes_binding, ec);
2519 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2520 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002521
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002522 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002523
2524err_udev_monitor:
2525 wl_event_source_remove(ec->udev_drm_source);
2526 udev_monitor_unref(ec->udev_monitor);
2527err_drm_source:
2528 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002529 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2530 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002531err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002532 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002533 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002534 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002535err_udev_dev:
2536 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002537err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002538 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2539 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002540 tty_destroy(ec->tty);
2541err_udev:
2542 udev_unref(ec->udev);
2543err_compositor:
2544 weston_compositor_shutdown(&ec->base);
2545err_base:
2546 free(ec);
2547 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002548}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002549
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002550static int
2551set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2552{
2553 mode->flags = 0;
2554
2555 if (strcmp(hsync, "+hsync") == 0)
2556 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2557 else if (strcmp(hsync, "-hsync") == 0)
2558 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2559 else
2560 return -1;
2561
2562 if (strcmp(vsync, "+vsync") == 0)
2563 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2564 else if (strcmp(vsync, "-vsync") == 0)
2565 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2566 else
2567 return -1;
2568
2569 return 0;
2570}
2571
2572static int
2573check_for_modeline(struct drm_configured_output *output)
2574{
2575 drmModeModeInfo mode;
2576 char hsync[16];
2577 char vsync[16];
2578 char mode_name[16];
2579 float fclock;
2580
2581 mode.type = DRM_MODE_TYPE_USERDEF;
2582 mode.hskew = 0;
2583 mode.vscan = 0;
2584 mode.vrefresh = 0;
2585
2586 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2587 &fclock, &mode.hdisplay,
2588 &mode.hsync_start,
2589 &mode.hsync_end, &mode.htotal,
2590 &mode.vdisplay,
2591 &mode.vsync_start,
2592 &mode.vsync_end, &mode.vtotal,
2593 hsync, vsync) == 11) {
2594 if (set_sync_flags(&mode, hsync, vsync))
2595 return -1;
2596
2597 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2598 strcpy(mode.name, mode_name);
2599
2600 mode.clock = fclock * 1000;
2601 } else
2602 return -1;
2603
2604 output->crtc_mode = mode;
2605
2606 return 0;
2607}
2608
Scott Moreau8ab5d452012-07-30 19:51:08 -06002609static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002610drm_output_set_transform(struct drm_configured_output *output)
2611{
2612 if (!output_transform) {
2613 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2614 return;
2615 }
2616
2617 if (!strcmp(output_transform, "normal"))
2618 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2619 else if (!strcmp(output_transform, "90"))
2620 output->transform = WL_OUTPUT_TRANSFORM_90;
2621 else if (!strcmp(output_transform, "180"))
2622 output->transform = WL_OUTPUT_TRANSFORM_180;
2623 else if (!strcmp(output_transform, "270"))
2624 output->transform = WL_OUTPUT_TRANSFORM_270;
2625 else if (!strcmp(output_transform, "flipped"))
2626 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2627 else if (!strcmp(output_transform, "flipped-90"))
2628 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2629 else if (!strcmp(output_transform, "flipped-180"))
2630 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2631 else if (!strcmp(output_transform, "flipped-270"))
2632 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2633 else {
2634 weston_log("Invalid transform \"%s\" for output %s\n",
2635 output_transform, output_name);
2636 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2637 }
2638
2639 free(output_transform);
2640 output_transform = NULL;
2641}
2642
2643static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002644output_section_done(void *data)
2645{
2646 struct drm_configured_output *output;
2647
2648 output = malloc(sizeof *output);
2649
Scott Moreau1bad5db2012-08-18 01:04:05 -06002650 if (!output || !output_name || (output_name[0] == 'X') ||
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002651 (!output_mode && !output_transform && !output_scale)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002652 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002653 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002654 free(output_transform);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002655 free(output_scale);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002656 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002657 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002658 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002659 output_transform = NULL;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002660 output_scale = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002661 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002662 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002663
2664 output->config = OUTPUT_CONFIG_INVALID;
2665 output->name = output_name;
2666 output->mode = output_mode;
2667
Scott Moreau1bad5db2012-08-18 01:04:05 -06002668 if (output_mode) {
2669 if (strcmp(output_mode, "off") == 0)
2670 output->config = OUTPUT_CONFIG_OFF;
2671 else if (strcmp(output_mode, "preferred") == 0)
2672 output->config = OUTPUT_CONFIG_PREFERRED;
2673 else if (strcmp(output_mode, "current") == 0)
2674 output->config = OUTPUT_CONFIG_CURRENT;
2675 else if (sscanf(output_mode, "%dx%d",
2676 &output->width, &output->height) == 2)
2677 output->config = OUTPUT_CONFIG_MODE;
2678 else if (check_for_modeline(output) == 0)
2679 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002680
Scott Moreau1bad5db2012-08-18 01:04:05 -06002681 if (output->config == OUTPUT_CONFIG_INVALID)
2682 weston_log("Invalid mode \"%s\" for output %s\n",
2683 output_mode, output_name);
2684 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002685 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002686
2687 drm_output_set_transform(output);
2688
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002689 if (!output_scale || sscanf(output_scale, "%d", &output->scale) != 1)
2690 output->scale = 1;
2691
Scott Moreau1bad5db2012-08-18 01:04:05 -06002692 wl_list_insert(&configured_output_list, &output->link);
2693
2694 if (output_transform)
2695 free(output_transform);
2696 output_transform = NULL;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002697 if (output_scale)
2698 free(output_scale);
2699 output_scale = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002700}
2701
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002702WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002703backend_init(struct wl_display *display, int *argc, char *argv[],
Ossama Othmana50e6e42013-05-14 09:48:26 -07002704 int config_fd)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002705{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002706 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002707 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002708
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002709 const struct weston_option drm_options[] = {
2710 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2711 { WESTON_OPTION_STRING, "seat", 0, &seat },
2712 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002713 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002714 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002715 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002716
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002717 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002718
Scott Moreau8ab5d452012-07-30 19:51:08 -06002719 wl_list_init(&configured_output_list);
2720
2721 const struct config_key drm_config_keys[] = {
2722 { "name", CONFIG_KEY_STRING, &output_name },
2723 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002724 { "transform", CONFIG_KEY_STRING, &output_transform },
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002725 { "scale", CONFIG_KEY_STRING, &output_scale },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002726 };
2727
2728 const struct config_section config_section[] = {
2729 { "output", drm_config_keys,
2730 ARRAY_LENGTH(drm_config_keys), output_section_done },
2731 };
2732
Ossama Othmana50e6e42013-05-14 09:48:26 -07002733 parse_config_file(config_fd, config_section,
Scott Moreau8ab5d452012-07-30 19:51:08 -06002734 ARRAY_LENGTH(config_section), NULL);
2735
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002736 return drm_compositor_create(display, connector, seat, tty, use_pixman,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002737 argc, argv, config_fd);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002738}