blob: b9e3fc97c4510c15a1939c72d1270c0fb4c3453d [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
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030033#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020034#include <sys/mman.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030035#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040036
Benjamin Franzkec649a922011-03-02 11:56:04 +010037#include <xf86drm.h>
38#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050039#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010040
Benjamin Franzke060cf802011-04-30 09:32:11 +020041#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020042#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040043#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020044
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010046#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020047#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050048#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010049#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040050
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030051#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
52#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
53#endif
54
Kristian Høgsberg061c4252012-06-28 11:28:15 -040055static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060056
57enum output_config {
58 OUTPUT_CONFIG_INVALID = 0,
59 OUTPUT_CONFIG_OFF,
60 OUTPUT_CONFIG_PREFERRED,
61 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060062 OUTPUT_CONFIG_MODE,
63 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060064};
65
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040066struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050067 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040068
69 struct udev *udev;
70 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010072 struct udev_monitor *udev_monitor;
73 struct wl_event_source *udev_drm_source;
74
Benjamin Franzke2af7f102011-03-02 11:14:59 +010075 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010076 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010077 int fd;
78 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020079 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050080 uint32_t *crtcs;
81 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050082 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010083 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050084 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020085
Rob Clark4339add2012-08-09 14:18:28 -050086 /* we need these parameters in order to not fail drmModeAddFB2()
87 * due to out of bounds dimensions, and then mistakenly set
88 * sprites_are_broken:
89 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020090 uint32_t min_width, max_width;
91 uint32_t min_height, max_height;
92 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050093
Jesse Barnes58ef3792012-02-23 09:45:49 -050094 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050095 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +020096 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -050097
Rob Clarkab5b1e32012-08-09 13:24:45 -050098 int cursors_are_broken;
99
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200100 int use_pixman;
101
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200102 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300103
104 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100105 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400106};
107
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400108struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500109 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400110 drmModeModeInfo mode_info;
111};
112
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300113struct drm_output;
114
115struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300116 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200117 uint32_t fb_id, stride, handle, size;
118 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300119 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200120 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200121
122 /* Used by gbm fbs */
123 struct gbm_bo *bo;
124
125 /* Used by dumb fbs */
126 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300127};
128
Richard Hughes2b2092a2013-04-24 14:58:02 +0100129struct drm_edid {
130 char eisa_id[13];
131 char monitor_name[13];
132 char pnp_id[5];
133 char serial_number[13];
134};
135
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400136struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500137 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400138
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400139 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500140 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400141 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700142 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100143 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300144 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200145
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300146 int vblank_pending;
147 int page_flip_pending;
148
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400149 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400150 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400151 struct weston_plane cursor_plane;
152 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400153 struct weston_surface *cursor_surface;
154 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300155 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200156 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200157
158 struct drm_fb *dumb[2];
159 pixman_image_t *image[2];
160 int current_image;
161 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400162};
163
Jesse Barnes58ef3792012-02-23 09:45:49 -0500164/*
165 * An output has a primary display plane plus zero or more sprites for
166 * blending display contents.
167 */
168struct drm_sprite {
169 struct wl_list link;
170
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400171 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500172
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200173 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300174 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500175 struct drm_compositor *compositor;
176
Jesse Barnes58ef3792012-02-23 09:45:49 -0500177 uint32_t possible_crtcs;
178 uint32_t plane_id;
179 uint32_t count_formats;
180
181 int32_t src_x, src_y;
182 uint32_t src_w, src_h;
183 uint32_t dest_x, dest_y;
184 uint32_t dest_w, dest_h;
185
186 uint32_t formats[];
187};
188
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500189static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400190
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400191static void
192drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400193
Jesse Barnes58ef3792012-02-23 09:45:49 -0500194static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500195drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
196{
197 struct weston_compositor *ec = output_base->compositor;
198 struct drm_compositor *c =(struct drm_compositor *) ec;
199 struct drm_output *output = (struct drm_output *) output_base;
200 int crtc;
201
202 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
203 if (c->crtcs[crtc] != output->crtc_id)
204 continue;
205
206 if (supported & (1 << crtc))
207 return -1;
208 }
209
210 return 0;
211}
212
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300213static void
214drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
215{
216 struct drm_fb *fb = data;
217 struct gbm_device *gbm = gbm_bo_get_device(bo);
218
219 if (fb->fb_id)
220 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
221
Pekka Paalanende685b82012-12-04 15:58:12 +0200222 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300223
224 free(data);
225}
226
227static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200228drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
229{
230 struct drm_fb *fb;
231 int ret;
232
233 struct drm_mode_create_dumb create_arg;
234 struct drm_mode_destroy_dumb destroy_arg;
235 struct drm_mode_map_dumb map_arg;
236
Peter Huttererf3d62272013-08-08 11:57:05 +1000237 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200238 if (!fb)
239 return NULL;
240
241 create_arg.bpp = 32;
242 create_arg.width = width;
243 create_arg.height = height;
244
245 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
246 if (ret)
247 goto err_fb;
248
249 fb->handle = create_arg.handle;
250 fb->stride = create_arg.pitch;
251 fb->size = create_arg.size;
252 fb->fd = ec->drm.fd;
253
254 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
255 fb->stride, fb->handle, &fb->fb_id);
256 if (ret)
257 goto err_bo;
258
259 memset(&map_arg, 0, sizeof(map_arg));
260 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400261 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200262 if (ret)
263 goto err_add_fb;
264
265 fb->map = mmap(0, fb->size, PROT_WRITE,
266 MAP_SHARED, ec->drm.fd, map_arg.offset);
267 if (fb->map == MAP_FAILED)
268 goto err_add_fb;
269
270 return fb;
271
272err_add_fb:
273 drmModeRmFB(ec->drm.fd, fb->fb_id);
274err_bo:
275 memset(&destroy_arg, 0, sizeof(destroy_arg));
276 destroy_arg.handle = create_arg.handle;
277 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
278err_fb:
279 free(fb);
280 return NULL;
281}
282
283static void
284drm_fb_destroy_dumb(struct drm_fb *fb)
285{
286 struct drm_mode_destroy_dumb destroy_arg;
287
288 if (!fb->map)
289 return;
290
291 if (fb->fb_id)
292 drmModeRmFB(fb->fd, fb->fb_id);
293
294 weston_buffer_reference(&fb->buffer_ref, NULL);
295
296 munmap(fb->map, fb->size);
297
298 memset(&destroy_arg, 0, sizeof(destroy_arg));
299 destroy_arg.handle = fb->handle;
300 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
301
302 free(fb);
303}
304
305static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500306drm_fb_get_from_bo(struct gbm_bo *bo,
307 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300308{
309 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200310 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200311 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300312 int ret;
313
314 if (fb)
315 return fb;
316
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200317 fb = calloc(1, sizeof *fb);
318 if (!fb)
319 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300320
321 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300322
323 width = gbm_bo_get_width(bo);
324 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200325 fb->stride = gbm_bo_get_stride(bo);
326 fb->handle = gbm_bo_get_handle(bo).u32;
327 fb->size = fb->stride * height;
328 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300329
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200330 if (compositor->min_width > width || width > compositor->max_width ||
331 compositor->min_height > height ||
332 height > compositor->max_height) {
333 weston_log("bo geometry out of bounds\n");
334 goto err_free;
335 }
336
337 ret = -1;
338
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200339 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200340 handles[0] = fb->handle;
341 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200342 offsets[0] = 0;
343
344 ret = drmModeAddFB2(compositor->drm.fd, width, height,
345 format, handles, pitches, offsets,
346 &fb->fb_id, 0);
347 if (ret) {
348 weston_log("addfb2 failed: %m\n");
349 compositor->no_addfb2 = 1;
350 compositor->sprites_are_broken = 1;
351 }
352 }
353
354 if (ret)
355 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200356 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200357
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300358 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200359 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200360 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300361 }
362
363 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
364
365 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200366
367err_free:
368 free(fb);
369 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300370}
371
372static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500373drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200374{
Pekka Paalanende685b82012-12-04 15:58:12 +0200375 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376
377 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200378
Pekka Paalanende685b82012-12-04 15:58:12 +0200379 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200380}
381
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200382static void
383drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
384{
385 if (!fb)
386 return;
387
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200388 if (fb->map &&
389 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200390 drm_fb_destroy_dumb(fb);
391 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200392 if (fb->is_client_buffer)
393 gbm_bo_destroy(fb->bo);
394 else
395 gbm_surface_release_buffer(output->surface,
396 output->current->bo);
397 }
398}
399
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500400static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200401drm_output_check_scanout_format(struct drm_output *output,
402 struct weston_surface *es, struct gbm_bo *bo)
403{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200404 uint32_t format;
405 pixman_region32_t r;
406
407 format = gbm_bo_get_format(bo);
408
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500409 switch (format) {
410 case GBM_FORMAT_XRGB8888:
411 return format;
412 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200413 /* We can only scanout an ARGB buffer if the surface's
414 * opaque region covers the whole output */
415 pixman_region32_init(&r);
416 pixman_region32_subtract(&r, &output->base.region,
417 &es->opaque);
418
419 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500420 format = GBM_FORMAT_XRGB8888;
421 else
422 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200423
424 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200425
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500426 return format;
427 default:
428 return 0;
429 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200430}
431
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400432static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400433drm_output_prepare_scanout_surface(struct weston_output *_output,
434 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500435{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400436 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500437 struct drm_compositor *c =
438 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500439 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300440 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500441 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500442
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500443 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200444 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200445 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200446 buffer->width != output->base.current->width ||
447 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200448 output->base.transform != es->buffer_transform ||
449 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400450 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500451
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400452 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200453 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500454
Rob Bradford9b101872012-09-14 23:25:41 +0100455 /* Unable to use the buffer for scanout */
456 if (!bo)
457 return NULL;
458
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500459 format = drm_output_check_scanout_format(output, es, bo);
460 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300461 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400462 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300463 }
464
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500465 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300466 if (!output->next) {
467 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400468 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300469 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500470
Pekka Paalanende685b82012-12-04 15:58:12 +0200471 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500472
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400473 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500474}
475
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500476static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200477drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400478{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200479 struct drm_compositor *c =
480 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300481 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400482
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200483 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400484
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300485 bo = gbm_surface_lock_front_buffer(output->surface);
486 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200487 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400488 return;
489 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300490
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500491 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300492 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200493 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300494 gbm_surface_release_buffer(output->surface, bo);
495 return;
496 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400497}
498
499static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200500drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
501{
502 struct weston_compositor *ec = output->base.compositor;
503 pixman_region32_t total_damage, previous_damage;
504
505 pixman_region32_init(&total_damage);
506 pixman_region32_init(&previous_damage);
507
508 pixman_region32_copy(&previous_damage, damage);
509
510 pixman_region32_union(&total_damage, damage, &output->previous_damage);
511 pixman_region32_copy(&output->previous_damage, &previous_damage);
512
513 output->current_image ^= 1;
514
515 output->next = output->dumb[output->current_image];
516 pixman_renderer_output_set_buffer(&output->base,
517 output->image[output->current_image]);
518
519 ec->renderer->repaint_output(&output->base, &total_damage);
520
521 pixman_region32_fini(&total_damage);
522 pixman_region32_fini(&previous_damage);
523}
524
525static void
526drm_output_render(struct drm_output *output, pixman_region32_t *damage)
527{
528 struct drm_compositor *c =
529 (struct drm_compositor *) output->base.compositor;
530
531 if (c->use_pixman)
532 drm_output_render_pixman(output, damage);
533 else
534 drm_output_render_gl(output, damage);
535
536 pixman_region32_subtract(&c->base.primary_plane.damage,
537 &c->base.primary_plane.damage, damage);
538}
539
540static void
Richard Hughese7299962013-05-01 21:52:12 +0100541drm_output_set_gamma(struct weston_output *output_base,
542 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
543{
544 int rc;
545 struct drm_output *output = (struct drm_output *) output_base;
546 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
547
548 /* check */
549 if (output_base->gamma_size != size)
550 return;
551 if (!output->original_crtc)
552 return;
553
554 rc = drmModeCrtcSetGamma(compositor->drm.fd,
555 output->crtc_id,
556 size, r, g, b);
557 if (rc)
558 weston_log("set gamma failed: %m\n");
559}
560
561static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500562drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400563 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100564{
565 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500566 struct drm_compositor *compositor =
567 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500568 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400569 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500570 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100571
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300572 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400573 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300574 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400575 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100576
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400577 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300578 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400579 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300580 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400581 &output->connector_id, 1,
582 &mode->mode_info);
583 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200584 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400585 return;
586 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300587 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200588 }
589
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500590 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300591 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500592 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200593 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500594 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500595 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100596
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300597 output->page_flip_pending = 1;
598
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400599 drm_output_set_cursor(output);
600
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601 /*
602 * Now, update all the sprite surfaces
603 */
604 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200605 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500606 drmVBlank vbl = {
607 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
608 .request.sequence = 1,
609 };
610
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200611 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200612 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613 continue;
614
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200615 if (s->next && !compositor->sprites_hidden)
616 fb_id = s->next->fb_id;
617
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200619 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620 s->dest_x, s->dest_y,
621 s->dest_w, s->dest_h,
622 s->src_x, s->src_y,
623 s->src_w, s->src_h);
624 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200625 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 ret, strerror(errno));
627
Rob Clark5ca1a472012-08-08 20:27:37 -0500628 if (output->pipe > 0)
629 vbl.request.type |= DRM_VBLANK_SECONDARY;
630
Jesse Barnes58ef3792012-02-23 09:45:49 -0500631 /*
632 * Queue a vblank signal so we know when the surface
633 * becomes active on the display or has been replaced.
634 */
635 vbl.request.signal = (unsigned long)s;
636 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
637 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200638 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 ret, strerror(errno));
640 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300641
642 s->output = output;
643 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500644 }
645
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500646 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400647}
648
649static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200650drm_output_start_repaint_loop(struct weston_output *output_base)
651{
652 struct drm_output *output = (struct drm_output *) output_base;
653 struct drm_compositor *compositor = (struct drm_compositor *)
654 output_base->compositor;
655 uint32_t fb_id;
656
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300657 struct timespec ts;
658
659 if (!output->current) {
660 /* We can't page flip if there's no mode set */
661 uint32_t msec;
662
663 clock_gettime(compositor->clock, &ts);
664 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
665 weston_output_finish_frame(output_base, msec);
666 return;
667 }
668
669 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200670
671 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
672 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
673 weston_log("queueing pageflip failed: %m\n");
674 return;
675 }
676}
677
678static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500679vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
680 void *data)
681{
682 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300683 struct drm_output *output = s->output;
684 uint32_t msecs;
685
686 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500687
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200688 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200689 s->current = s->next;
690 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300691
692 if (!output->page_flip_pending) {
693 msecs = sec * 1000 + usec / 1000;
694 weston_output_finish_frame(&output->base, msecs);
695 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500696}
697
698static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400699page_flip_handler(int fd, unsigned int frame,
700 unsigned int sec, unsigned int usec, void *data)
701{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200702 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400703 uint32_t msecs;
704
Jonas Ådahle5a12252013-04-05 23:07:11 +0200705 /* We don't set page_flip_pending on start_repaint_loop, in that case
706 * we just want to page flip to the current buffer to get an accurate
707 * timestamp */
708 if (output->page_flip_pending) {
709 drm_output_release_fb(output, output->current);
710 output->current = output->next;
711 output->next = NULL;
712 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300713
Jonas Ådahle5a12252013-04-05 23:07:11 +0200714 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400715
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300716 if (!output->vblank_pending) {
717 msecs = sec * 1000 + usec / 1000;
718 weston_output_finish_frame(&output->base, msecs);
719 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200720}
721
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500722static uint32_t
723drm_output_check_sprite_format(struct drm_sprite *s,
724 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500725{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500726 uint32_t i, format;
727
728 format = gbm_bo_get_format(bo);
729
730 if (format == GBM_FORMAT_ARGB8888) {
731 pixman_region32_t r;
732
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500733 pixman_region32_init_rect(&r, 0, 0,
734 es->geometry.width,
735 es->geometry.height);
736 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500737
738 if (!pixman_region32_not_empty(&r))
739 format = GBM_FORMAT_XRGB8888;
740
741 pixman_region32_fini(&r);
742 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500743
744 for (i = 0; i < s->count_formats; i++)
745 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500746 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500747
748 return 0;
749}
750
751static int
752drm_surface_transform_supported(struct weston_surface *es)
753{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500754 return !es->transform.enabled ||
755 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500756}
757
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400758static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500759drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400760 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500761{
762 struct weston_compositor *ec = output_base->compositor;
763 struct drm_compositor *c =(struct drm_compositor *) ec;
764 struct drm_sprite *s;
765 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500767 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200768 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400770 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200772 if (c->gbm == NULL)
773 return NULL;
774
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200775 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200776 return NULL;
777
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200778 if (es->buffer_scale != output_base->scale)
779 return NULL;
780
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500781 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400782 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500783
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300784 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400785 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300786
Pekka Paalanende685b82012-12-04 15:58:12 +0200787 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400788 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500789
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200790 if (es->alpha != 1.0f)
791 return NULL;
792
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500793 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500794 return NULL;
795
Jesse Barnes58ef3792012-02-23 09:45:49 -0500796 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400797 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500798
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799 wl_list_for_each(s, &c->sprite_list, link) {
800 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
801 continue;
802
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200803 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804 found = 1;
805 break;
806 }
807 }
808
809 /* No sprites available */
810 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400811 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400813 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200814 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400815 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400816 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400817
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500818 format = drm_output_check_sprite_format(s, es, bo);
819 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200820 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400821 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500822 }
823
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200824 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200825 if (!s->next) {
826 gbm_bo_destroy(bo);
827 return NULL;
828 }
829
Pekka Paalanende685b82012-12-04 15:58:12 +0200830 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400832 box = pixman_region32_extents(&es->transform.boundingbox);
833 s->plane.x = box->x1;
834 s->plane.y = box->y1;
835
Jesse Barnes58ef3792012-02-23 09:45:49 -0500836 /*
837 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200838 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839 * for us already).
840 */
841 pixman_region32_init(&dest_rect);
842 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
843 &output_base->region);
844 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
845 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200846 tbox = weston_transformed_rect(output_base->width,
847 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200848 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200849 output_base->scale,
850 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200851 s->dest_x = tbox.x1;
852 s->dest_y = tbox.y1;
853 s->dest_w = tbox.x2 - tbox.x1;
854 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500855 pixman_region32_fini(&dest_rect);
856
857 pixman_region32_init(&src_rect);
858 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
859 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500860 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400861
862 weston_surface_from_global_fixed(es,
863 wl_fixed_from_int(box->x1),
864 wl_fixed_from_int(box->y1),
865 &sx1, &sy1);
866 weston_surface_from_global_fixed(es,
867 wl_fixed_from_int(box->x2),
868 wl_fixed_from_int(box->y2),
869 &sx2, &sy2);
870
871 if (sx1 < 0)
872 sx1 = 0;
873 if (sy1 < 0)
874 sy1 = 0;
875 if (sx2 > wl_fixed_from_int(es->geometry.width))
876 sx2 = wl_fixed_from_int(es->geometry.width);
877 if (sy2 > wl_fixed_from_int(es->geometry.height))
878 sy2 = wl_fixed_from_int(es->geometry.height);
879
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200880 tbox.x1 = sx1;
881 tbox.y1 = sy1;
882 tbox.x2 = sx2;
883 tbox.y2 = sy2;
884
885 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
886 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200887 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200888
889 s->src_x = tbox.x1 << 8;
890 s->src_y = tbox.y1 << 8;
891 s->src_w = (tbox.x2 - tbox.x1) << 8;
892 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500893 pixman_region32_fini(&src_rect);
894
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400895 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500896}
897
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400898static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400899drm_output_prepare_cursor_surface(struct weston_output *output_base,
900 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500901{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400902 struct drm_compositor *c =
903 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400904 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400905
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200906 if (c->gbm == NULL)
907 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200908 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
909 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400910 if (output->cursor_surface)
911 return NULL;
912 if (es->output_mask != (1u << output_base->id))
913 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500914 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400915 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200916 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500917 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400918 es->geometry.width > 64 || es->geometry.height > 64)
919 return NULL;
920
921 output->cursor_surface = es;
922
923 return &output->cursor_plane;
924}
925
926static void
927drm_output_set_cursor(struct drm_output *output)
928{
929 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400930 struct drm_compositor *c =
931 (struct drm_compositor *) output->base.compositor;
932 EGLint handle, stride;
933 struct gbm_bo *bo;
934 uint32_t buf[64 * 64];
935 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400936 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500937
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400938 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400939 if (es == NULL) {
940 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
941 return;
942 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500943
Pekka Paalanende685b82012-12-04 15:58:12 +0200944 if (es->buffer_ref.buffer &&
945 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400946 pixman_region32_fini(&output->cursor_plane.damage);
947 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400948 output->current_cursor ^= 1;
949 bo = output->cursor_bo[output->current_cursor];
950 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500951 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
952 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400953 for (i = 0; i < es->geometry.height; i++)
954 memcpy(buf + i * 64, s + i * stride,
955 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500956
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400957 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300958 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400959
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400960 handle = gbm_bo_get_handle(bo).s32;
961 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500962 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300963 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500964 c->cursors_are_broken = 1;
965 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400966 }
967
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200968 x = (es->geometry.x - output->base.x) * output->base.scale;
969 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400970 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500971 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400972 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500973 c->cursors_are_broken = 1;
974 }
975
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400976 output->cursor_plane.x = x;
977 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400978 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500979}
980
Jesse Barnes58ef3792012-02-23 09:45:49 -0500981static void
982drm_assign_planes(struct weston_output *output)
983{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400984 struct drm_compositor *c =
985 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400986 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500987 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400988 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500989
990 /*
991 * Find a surface for each sprite in the output using some heuristics:
992 * 1) size
993 * 2) frequency of update
994 * 3) opacity (though some hw might support alpha blending)
995 * 4) clipping (this can be fixed with color keys)
996 *
997 * The idea is to save on blitting since this should save power.
998 * If we can get a large video surface on the sprite for example,
999 * the main display surface may not need to update at all, and
1000 * the client buffer can be used directly for the sprite surface
1001 * as we do for flipping full screen surfaces.
1002 */
1003 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001004 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001005 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001006 /* test whether this buffer can ever go into a plane:
1007 * non-shm, or small enough to be a cursor
1008 */
1009 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001010 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001011 (es->geometry.width <= 64 && es->geometry.height <= 64))
1012 es->keep_buffer = 1;
1013 else
1014 es->keep_buffer = 0;
1015
Jesse Barnes58ef3792012-02-23 09:45:49 -05001016 pixman_region32_init(&surface_overlap);
1017 pixman_region32_intersect(&surface_overlap, &overlap,
1018 &es->transform.boundingbox);
1019
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001020 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001021 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001022 next_plane = primary;
1023 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001024 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001025 if (next_plane == NULL)
1026 next_plane = drm_output_prepare_scanout_surface(output, es);
1027 if (next_plane == NULL)
1028 next_plane = drm_output_prepare_overlay_surface(output, es);
1029 if (next_plane == NULL)
1030 next_plane = primary;
1031 weston_surface_move_to_plane(es, next_plane);
1032 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001033 pixman_region32_union(&overlap, &overlap,
1034 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001035
Jesse Barnes58ef3792012-02-23 09:45:49 -05001036 pixman_region32_fini(&surface_overlap);
1037 }
1038 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001039}
1040
Matt Roper361d2ad2011-08-29 13:52:23 -07001041static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001042drm_output_fini_pixman(struct drm_output *output);
1043
1044static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001045drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001046{
1047 struct drm_output *output = (struct drm_output *) output_base;
1048 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001049 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001050 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001051
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001052 if (output->backlight)
1053 backlight_destroy(output->backlight);
1054
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001055 drmModeFreeProperty(output->dpms_prop);
1056
Matt Roper361d2ad2011-08-29 13:52:23 -07001057 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001058 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001059
1060 /* Restore original CRTC state */
1061 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001062 origcrtc->x, origcrtc->y,
1063 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001064 drmModeFreeCrtc(origcrtc);
1065
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001066 c->crtc_allocator &= ~(1 << output->crtc_id);
1067 c->connector_allocator &= ~(1 << output->connector_id);
1068
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001069 if (c->use_pixman) {
1070 drm_output_fini_pixman(output);
1071 } else {
1072 gl_renderer_output_destroy(output_base);
1073 gbm_surface_destroy(output->surface);
1074 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001075
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001076 weston_plane_release(&output->fb_plane);
1077 weston_plane_release(&output->cursor_plane);
1078
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001079 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001080 wl_list_remove(&output->base.link);
1081
Matt Roper361d2ad2011-08-29 13:52:23 -07001082 free(output);
1083}
1084
Alex Wub7b8bda2012-04-17 17:20:48 +08001085static struct drm_mode *
1086choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1087{
1088 struct drm_mode *tmp_mode = NULL, *mode;
1089
1090 if (output->base.current->width == target_mode->width &&
1091 output->base.current->height == target_mode->height &&
1092 (output->base.current->refresh == target_mode->refresh ||
1093 target_mode->refresh == 0))
1094 return (struct drm_mode *)output->base.current;
1095
1096 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1097 if (mode->mode_info.hdisplay == target_mode->width &&
1098 mode->mode_info.vdisplay == target_mode->height) {
1099 if (mode->mode_info.vrefresh == target_mode->refresh ||
1100 target_mode->refresh == 0) {
1101 return mode;
1102 } else if (!tmp_mode)
1103 tmp_mode = mode;
1104 }
1105 }
1106
1107 return tmp_mode;
1108}
1109
1110static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001111drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001112static int
1113drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001114
1115static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001116drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1117{
1118 struct drm_output *output;
1119 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001120 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001121
1122 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001123 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001124 return -1;
1125 }
1126
1127 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001128 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001129 return -1;
1130 }
1131
1132 ec = (struct drm_compositor *)output_base->compositor;
1133 output = (struct drm_output *)output_base;
1134 drm_mode = choose_mode (output, mode);
1135
1136 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001137 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001138 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001139 }
1140
1141 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001142 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001143
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001144 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001145
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001146 output->base.current = &drm_mode->base;
1147 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001148 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1149
Alex Wub7b8bda2012-04-17 17:20:48 +08001150 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001151 drm_output_release_fb(output, output->current);
1152 drm_output_release_fb(output, output->next);
1153 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001154
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001155 if (ec->use_pixman) {
1156 drm_output_fini_pixman(output);
1157 if (drm_output_init_pixman(output, ec) < 0) {
1158 weston_log("failed to init output pixman state with "
1159 "new mode\n");
1160 return -1;
1161 }
1162 } else {
1163 gl_renderer_output_destroy(&output->base);
1164 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001165
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001166 if (drm_output_init_egl(output, ec) < 0) {
1167 weston_log("failed to init output egl state with "
1168 "new mode");
1169 return -1;
1170 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001171 }
1172
Alex Wub7b8bda2012-04-17 17:20:48 +08001173 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001174}
1175
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001176static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001177on_drm_input(int fd, uint32_t mask, void *data)
1178{
1179 drmEventContext evctx;
1180
1181 memset(&evctx, 0, sizeof evctx);
1182 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1183 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001184 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001185 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001186
1187 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001188}
1189
1190static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001191init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001192{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001193 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001194 uint64_t cap;
1195 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001196
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001197 sysnum = udev_device_get_sysnum(device);
1198 if (sysnum)
1199 ec->drm.id = atoi(sysnum);
1200 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001201 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001202 return -1;
1203 }
1204
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001205 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001206 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001207 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001208 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001209 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001210 udev_device_get_devnode(device));
1211 return -1;
1212 }
1213
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001214 weston_log("using %s\n", filename);
1215
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001216 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001217
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001218 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1219 if (ret == 0 && cap == 1)
1220 ec->clock = CLOCK_MONOTONIC;
1221 else
1222 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001223
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001224 return 0;
1225}
1226
1227static int
1228init_egl(struct drm_compositor *ec)
1229{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001230 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001231
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001232 if (!ec->gbm)
1233 return -1;
1234
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001235 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001236 NULL) < 0) {
1237 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001238 return -1;
1239 }
1240
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001241 return 0;
1242}
1243
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001244static int
1245init_pixman(struct drm_compositor *ec)
1246{
1247 return pixman_renderer_init(&ec->base);
1248}
1249
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001250static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001251drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001252{
1253 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001254 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001255
1256 mode = malloc(sizeof *mode);
1257 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001258 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001259
1260 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001261 mode->base.width = info->hdisplay;
1262 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001263
1264 /* Calculate higher precision (mHz) refresh rate */
1265 refresh = (info->clock * 1000000LL / info->htotal +
1266 info->vtotal / 2) / info->vtotal;
1267
1268 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1269 refresh *= 2;
1270 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1271 refresh /= 2;
1272 if (info->vscan > 1)
1273 refresh /= info->vscan;
1274
1275 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001276 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001277
1278 if (info->type & DRM_MODE_TYPE_PREFERRED)
1279 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1280
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001281 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1282
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001283 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001284}
1285
1286static int
1287drm_subpixel_to_wayland(int drm_value)
1288{
1289 switch (drm_value) {
1290 default:
1291 case DRM_MODE_SUBPIXEL_UNKNOWN:
1292 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1293 case DRM_MODE_SUBPIXEL_NONE:
1294 return WL_OUTPUT_SUBPIXEL_NONE;
1295 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1296 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1297 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1298 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1299 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1300 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1301 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1302 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1303 }
1304}
1305
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001306/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001307static uint32_t
1308drm_get_backlight(struct drm_output *output)
1309{
1310 long brightness, max_brightness, norm;
1311
1312 brightness = backlight_get_brightness(output->backlight);
1313 max_brightness = backlight_get_max_brightness(output->backlight);
1314
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001315 /* convert it on a scale of 0 to 255 */
1316 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001317
1318 return (uint32_t) norm;
1319}
1320
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001321/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001322static void
1323drm_set_backlight(struct weston_output *output_base, uint32_t value)
1324{
1325 struct drm_output *output = (struct drm_output *) output_base;
1326 long max_brightness, new_brightness;
1327
1328 if (!output->backlight)
1329 return;
1330
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001331 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001332 return;
1333
1334 max_brightness = backlight_get_max_brightness(output->backlight);
1335
1336 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001337 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001338
1339 backlight_set_brightness(output->backlight, new_brightness);
1340}
1341
1342static drmModePropertyPtr
1343drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1344{
1345 drmModePropertyPtr props;
1346 int i;
1347
1348 for (i = 0; i < connector->count_props; i++) {
1349 props = drmModeGetProperty(fd, connector->props[i]);
1350 if (!props)
1351 continue;
1352
1353 if (!strcmp(props->name, name))
1354 return props;
1355
1356 drmModeFreeProperty(props);
1357 }
1358
1359 return NULL;
1360}
1361
1362static void
1363drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1364{
1365 struct drm_output *output = (struct drm_output *) output_base;
1366 struct weston_compositor *ec = output_base->compositor;
1367 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001368
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001369 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001370 return;
1371
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001372 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1373 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001374}
1375
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001376static const char *connector_type_names[] = {
1377 "None",
1378 "VGA",
1379 "DVI",
1380 "DVI",
1381 "DVI",
1382 "Composite",
1383 "TV",
1384 "LVDS",
1385 "CTV",
1386 "DIN",
1387 "DP",
1388 "HDMI",
1389 "HDMI",
1390 "TV",
1391 "eDP",
1392};
1393
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001394static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001395find_crtc_for_connector(struct drm_compositor *ec,
1396 drmModeRes *resources, drmModeConnector *connector)
1397{
1398 drmModeEncoder *encoder;
1399 uint32_t possible_crtcs;
1400 int i, j;
1401
1402 for (j = 0; j < connector->count_encoders; j++) {
1403 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1404 if (encoder == NULL) {
1405 weston_log("Failed to get encoder.\n");
1406 return -1;
1407 }
1408 possible_crtcs = encoder->possible_crtcs;
1409 drmModeFreeEncoder(encoder);
1410
1411 for (i = 0; i < resources->count_crtcs; i++) {
1412 if (possible_crtcs & (1 << i) &&
1413 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1414 return i;
1415 }
1416 }
1417
1418 return -1;
1419}
1420
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001421/* Init output state that depends on gl or gbm */
1422static int
1423drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1424{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001425 int i, flags;
1426
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001427 output->surface = gbm_surface_create(ec->gbm,
Alexander Larsson0b135062013-05-28 16:23:36 +02001428 output->base.current->width,
1429 output->base.current->height,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001430 GBM_FORMAT_XRGB8888,
1431 GBM_BO_USE_SCANOUT |
1432 GBM_BO_USE_RENDERING);
1433 if (!output->surface) {
1434 weston_log("failed to create gbm surface\n");
1435 return -1;
1436 }
1437
1438 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001439 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001440 gbm_surface_destroy(output->surface);
1441 return -1;
1442 }
1443
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001444 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1445
1446 for (i = 0; i < 2; i++) {
1447 if (output->cursor_bo[i])
1448 continue;
1449
1450 output->cursor_bo[i] =
1451 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1452 flags);
1453 }
1454
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001455 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1456 weston_log("cursor buffers unavailable, using gl cursors\n");
1457 ec->cursors_are_broken = 1;
1458 }
1459
1460 return 0;
1461}
1462
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001463static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001464drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1465{
1466 int w = output->base.current->width;
1467 int h = output->base.current->height;
1468 unsigned int i;
1469
1470 /* FIXME error checking */
1471
1472 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001473 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001474 if (!output->dumb[i])
1475 goto err;
1476
1477 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001478 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001479 output->dumb[i]->map,
1480 output->dumb[i]->stride);
1481 if (!output->image[i])
1482 goto err;
1483 }
1484
1485 if (pixman_renderer_output_create(&output->base) < 0)
1486 goto err;
1487
1488 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001489 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001490
1491 return 0;
1492
1493err:
1494 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1495 if (output->dumb[i])
1496 drm_fb_destroy_dumb(output->dumb[i]);
1497 if (output->image[i])
1498 pixman_image_unref(output->image[i]);
1499
1500 output->dumb[i] = NULL;
1501 output->image[i] = NULL;
1502 }
1503
1504 return -1;
1505}
1506
1507static void
1508drm_output_fini_pixman(struct drm_output *output)
1509{
1510 unsigned int i;
1511
1512 pixman_renderer_output_destroy(&output->base);
1513 pixman_region32_fini(&output->previous_damage);
1514
1515 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1516 drm_fb_destroy_dumb(output->dumb[i]);
1517 pixman_image_unref(output->image[i]);
1518 output->dumb[i] = NULL;
1519 output->image[i] = NULL;
1520 }
1521}
1522
Richard Hughes2b2092a2013-04-24 14:58:02 +01001523static void
1524edid_parse_string(const uint8_t *data, char text[])
1525{
1526 int i;
1527 int replaced = 0;
1528
1529 /* this is always 12 bytes, but we can't guarantee it's null
1530 * terminated or not junk. */
1531 strncpy(text, (const char *) data, 12);
1532
1533 /* remove insane chars */
1534 for (i = 0; text[i] != '\0'; i++) {
1535 if (text[i] == '\n' ||
1536 text[i] == '\r') {
1537 text[i] = '\0';
1538 break;
1539 }
1540 }
1541
1542 /* ensure string is printable */
1543 for (i = 0; text[i] != '\0'; i++) {
1544 if (!isprint(text[i])) {
1545 text[i] = '-';
1546 replaced++;
1547 }
1548 }
1549
1550 /* if the string is random junk, ignore the string */
1551 if (replaced > 4)
1552 text[0] = '\0';
1553}
1554
1555#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1556#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1557#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1558#define EDID_OFFSET_DATA_BLOCKS 0x36
1559#define EDID_OFFSET_LAST_BLOCK 0x6c
1560#define EDID_OFFSET_PNPID 0x08
1561#define EDID_OFFSET_SERIAL 0x0c
1562
1563static int
1564edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1565{
1566 int i;
1567 uint32_t serial_number;
1568
1569 /* check header */
1570 if (length < 128)
1571 return -1;
1572 if (data[0] != 0x00 || data[1] != 0xff)
1573 return -1;
1574
1575 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1576 * /--08--\/--09--\
1577 * 7654321076543210
1578 * |\---/\---/\---/
1579 * R C1 C2 C3 */
1580 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1581 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1582 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1583 edid->pnp_id[3] = '\0';
1584
1585 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1586 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1587 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1588 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1589 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1590 if (serial_number > 0)
1591 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1592
1593 /* parse EDID data */
1594 for (i = EDID_OFFSET_DATA_BLOCKS;
1595 i <= EDID_OFFSET_LAST_BLOCK;
1596 i += 18) {
1597 /* ignore pixel clock data */
1598 if (data[i] != 0)
1599 continue;
1600 if (data[i+2] != 0)
1601 continue;
1602
1603 /* any useful blocks? */
1604 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1605 edid_parse_string(&data[i+5],
1606 edid->monitor_name);
1607 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1608 edid_parse_string(&data[i+5],
1609 edid->serial_number);
1610 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1611 edid_parse_string(&data[i+5],
1612 edid->eisa_id);
1613 }
1614 }
1615 return 0;
1616}
1617
1618static void
1619find_and_parse_output_edid(struct drm_compositor *ec,
1620 struct drm_output *output,
1621 drmModeConnector *connector)
1622{
1623 drmModePropertyBlobPtr edid_blob = NULL;
1624 drmModePropertyPtr property;
1625 int i;
1626 int rc;
1627
1628 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1629 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1630 if (!property)
1631 continue;
1632 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1633 !strcmp(property->name, "EDID")) {
1634 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1635 connector->prop_values[i]);
1636 }
1637 drmModeFreeProperty(property);
1638 }
1639 if (!edid_blob)
1640 return;
1641
1642 rc = edid_parse(&output->edid,
1643 edid_blob->data,
1644 edid_blob->length);
1645 if (!rc) {
1646 weston_log("EDID data '%s', '%s', '%s'\n",
1647 output->edid.pnp_id,
1648 output->edid.monitor_name,
1649 output->edid.serial_number);
1650 if (output->edid.pnp_id[0] != '\0')
1651 output->base.make = output->edid.pnp_id;
1652 if (output->edid.monitor_name[0] != '\0')
1653 output->base.model = output->edid.monitor_name;
1654 if (output->edid.serial_number[0] != '\0')
1655 output->base.serial_number = output->edid.serial_number;
1656 }
1657 drmModeFreePropertyBlob(edid_blob);
1658}
1659
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001660
1661
1662static int
1663parse_modeline(const char *s, drmModeModeInfo *mode)
1664{
1665 char hsync[16];
1666 char vsync[16];
1667 float fclock;
1668
1669 mode->type = DRM_MODE_TYPE_USERDEF;
1670 mode->hskew = 0;
1671 mode->vscan = 0;
1672 mode->vrefresh = 0;
1673 mode->flags = 0;
1674
Rob Bradford307e09e2013-07-26 16:29:40 +01001675 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001676 &fclock,
1677 &mode->hdisplay,
1678 &mode->hsync_start,
1679 &mode->hsync_end,
1680 &mode->htotal,
1681 &mode->vdisplay,
1682 &mode->vsync_start,
1683 &mode->vsync_end,
1684 &mode->vtotal, hsync, vsync) != 11)
1685 return -1;
1686
1687 mode->clock = fclock * 1000;
1688 if (strcmp(hsync, "+hsync") == 0)
1689 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1690 else if (strcmp(hsync, "-hsync") == 0)
1691 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1692 else
1693 return -1;
1694
1695 if (strcmp(vsync, "+vsync") == 0)
1696 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1697 else if (strcmp(vsync, "-vsync") == 0)
1698 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1699 else
1700 return -1;
1701
1702 return 0;
1703}
1704
1705static uint32_t
1706parse_transform(const char *transform, const char *output_name)
1707{
1708 static const struct { const char *name; uint32_t token; } names[] = {
1709 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1710 { "90", WL_OUTPUT_TRANSFORM_90 },
1711 { "180", WL_OUTPUT_TRANSFORM_180 },
1712 { "270", WL_OUTPUT_TRANSFORM_270 },
1713 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1714 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1715 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1716 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1717 };
1718 unsigned int i;
1719
1720 for (i = 0; i < ARRAY_LENGTH(names); i++)
1721 if (strcmp(names[i].name, transform) == 0)
1722 return names[i].token;
1723
1724 weston_log("Invalid transform \"%s\" for output %s\n",
1725 transform, output_name);
1726
1727 return WL_OUTPUT_TRANSFORM_NORMAL;
1728}
1729
Rob Bradford66bd9f52013-06-25 18:56:42 +01001730static void
1731setup_output_seat_constraint(struct drm_compositor *ec,
1732 struct weston_output *output,
1733 const char *s)
1734{
1735 if (strcmp(s, "") != 0) {
1736 struct udev_seat *seat;
1737
1738 seat = udev_seat_get_named(&ec->base, s);
1739 if (seat)
1740 seat->base.output = output;
1741
1742 if (seat && seat->base.pointer)
1743 weston_pointer_clamp(seat->base.pointer,
1744 &seat->base.pointer->x,
1745 &seat->base.pointer->y);
1746 }
1747}
1748
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001749static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001750create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001751 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001752 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001753 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001754{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001755 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001756 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1757 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001758 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001759 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001760 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001761 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001762 int i, width, height, scale;
1763 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001764 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001765 enum output_config config;
1766 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001767
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001768 i = find_crtc_for_connector(ec, resources, connector);
1769 if (i < 0) {
1770 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001771 return -1;
1772 }
1773
Peter Huttererf3d62272013-08-08 11:57:05 +10001774 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001775 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001776 return -1;
1777
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001778 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1779 output->base.make = "unknown";
1780 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001781 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001782 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001783
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001784 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1785 type_name = connector_type_names[connector->connector_type];
1786 else
1787 type_name = "UNKNOWN";
1788 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001789 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001790
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001791 section = weston_config_get_section(ec->base.config, "output", "name",
1792 output->base.name);
1793 weston_config_section_get_string(section, "mode", &s, "preferred");
1794 if (strcmp(s, "off") == 0)
1795 config = OUTPUT_CONFIG_OFF;
1796 else if (strcmp(s, "preferred") == 0)
1797 config = OUTPUT_CONFIG_PREFERRED;
1798 else if (strcmp(s, "current") == 0)
1799 config = OUTPUT_CONFIG_CURRENT;
1800 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1801 config = OUTPUT_CONFIG_MODE;
1802 else if (parse_modeline(s, &modeline) == 0)
1803 config = OUTPUT_CONFIG_MODELINE;
1804 else {
1805 weston_log("Invalid mode \"%s\" for output %s\n",
1806 s, output->base.name);
1807 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001808 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001809 free(s);
1810
1811 weston_config_section_get_int(section, "scale", &scale, 1);
1812 weston_config_section_get_string(section, "transform", &s, "normal");
1813 transform = parse_transform(s, output->base.name);
1814 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001815
Rob Bradford66bd9f52013-06-25 18:56:42 +01001816 weston_config_section_get_string(section, "seat", &s, "");
1817 setup_output_seat_constraint(ec, &output->base, s);
1818 free(s);
1819
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001820 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001821 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001822 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001823 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001824 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001825
Matt Roper361d2ad2011-08-29 13:52:23 -07001826 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001827 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001828
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001829 /* Get the current mode on the crtc that's currently driving
1830 * this connector. */
1831 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001832 memset(&crtc_mode, 0, sizeof crtc_mode);
1833 if (encoder != NULL) {
1834 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1835 drmModeFreeEncoder(encoder);
1836 if (crtc == NULL)
1837 goto err_free;
1838 if (crtc->mode_valid)
1839 crtc_mode = crtc->mode;
1840 drmModeFreeCrtc(crtc);
1841 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001842
David Herrmann0f0d54e2011-12-08 17:05:45 +01001843 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001844 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001845 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001846 goto err_free;
1847 }
1848
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001849 if (config == OUTPUT_CONFIG_OFF) {
1850 weston_log("Disabling output %s\n", output->base.name);
1851 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1852 0, 0, 0, 0, 0, NULL);
1853 goto err_free;
1854 }
1855
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001856 preferred = NULL;
1857 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001858 configured = NULL;
1859
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001860 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001861 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001862 width == drm_mode->base.width &&
1863 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001864 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001865 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001866 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001867 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001868 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001869 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001870
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001871 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001872 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001873 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001874 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001875 }
1876
Wang Quanxianacb805a2012-07-30 18:09:46 -04001877 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001878 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001879 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001880 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001881 }
1882
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001883 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001884 configured = current;
1885
Wang Quanxianacb805a2012-07-30 18:09:46 -04001886 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001887 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001888 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001889 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001890 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001891 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001892 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001893 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001894
1895 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001896 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001897 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001898 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001899
Wang Quanxianacb805a2012-07-30 18:09:46 -04001900 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1901
John Kåre Alsaker94659272012-11-13 19:10:18 +01001902 weston_output_init(&output->base, &ec->base, x, y,
1903 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001904 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001905
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001906 if (ec->use_pixman) {
1907 if (drm_output_init_pixman(output, ec) < 0) {
1908 weston_log("Failed to init output pixman state\n");
1909 goto err_output;
1910 }
1911 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001912 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001913 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001914 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001915
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001916 output->backlight = backlight_init(drm_device,
1917 connector->connector_type);
1918 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001919 weston_log("Initialized backlight, device %s\n",
1920 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001921 output->base.set_backlight = drm_set_backlight;
1922 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001923 } else {
1924 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001925 }
1926
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001927 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1928
Richard Hughes2b2092a2013-04-24 14:58:02 +01001929 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001930 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1931 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001932
Alex Wubd3354b2012-04-17 17:20:49 +08001933 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001934 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001935 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001936 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001937 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001938 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001939 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001940
Richard Hughese7299962013-05-01 21:52:12 +01001941 output->base.gamma_size = output->original_crtc->gamma_size;
1942 output->base.set_gamma = drm_output_set_gamma;
1943
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001944 weston_plane_init(&output->cursor_plane, 0, 0);
1945 weston_plane_init(&output->fb_plane, 0, 0);
1946
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001947 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1948 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1949 &ec->base.primary_plane);
1950
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001951 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001952 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001953 wl_list_for_each(m, &output->base.mode_list, link)
1954 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1955 m->width, m->height, m->refresh / 1000.0,
1956 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1957 ", preferred" : "",
1958 m->flags & WL_OUTPUT_MODE_CURRENT ?
1959 ", current" : "",
1960 connector->count_modes == 0 ?
1961 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001962
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001963 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001964
John Kåre Alsaker94659272012-11-13 19:10:18 +01001965err_output:
1966 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001967err_free:
1968 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1969 base.link) {
1970 wl_list_remove(&drm_mode->base.link);
1971 free(drm_mode);
1972 }
1973
1974 drmModeFreeCrtc(output->original_crtc);
1975 ec->crtc_allocator &= ~(1 << output->crtc_id);
1976 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001977 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001978
David Herrmann0f0d54e2011-12-08 17:05:45 +01001979 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001980}
1981
Jesse Barnes58ef3792012-02-23 09:45:49 -05001982static void
1983create_sprites(struct drm_compositor *ec)
1984{
1985 struct drm_sprite *sprite;
1986 drmModePlaneRes *plane_res;
1987 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001988 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001989
1990 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1991 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001992 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001993 strerror(errno));
1994 return;
1995 }
1996
1997 for (i = 0; i < plane_res->count_planes; i++) {
1998 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1999 if (!plane)
2000 continue;
2001
Peter Huttererf3d62272013-08-08 11:57:05 +10002002 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002003 plane->count_formats));
2004 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002005 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002006 __func__);
2007 free(plane);
2008 continue;
2009 }
2010
Jesse Barnes58ef3792012-02-23 09:45:49 -05002011 sprite->possible_crtcs = plane->possible_crtcs;
2012 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002013 sprite->current = NULL;
2014 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002015 sprite->compositor = ec;
2016 sprite->count_formats = plane->count_formats;
2017 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002018 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002019 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002020 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002021 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2022 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002023
2024 wl_list_insert(&ec->sprite_list, &sprite->link);
2025 }
2026
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002027 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002028}
2029
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002030static void
2031destroy_sprites(struct drm_compositor *compositor)
2032{
2033 struct drm_sprite *sprite, *next;
2034 struct drm_output *output;
2035
2036 output = container_of(compositor->base.output_list.next,
2037 struct drm_output, base.link);
2038
2039 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2040 drmModeSetPlane(compositor->drm.fd,
2041 sprite->plane_id,
2042 output->crtc_id, 0, 0,
2043 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002044 drm_output_release_fb(output, sprite->current);
2045 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002046 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002047 free(sprite);
2048 }
2049}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002050
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002051static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002052create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002053 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002054{
2055 drmModeConnector *connector;
2056 drmModeRes *resources;
2057 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002058 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002059
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002060 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002061 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002062 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002063 return -1;
2064 }
2065
Jesse Barnes58ef3792012-02-23 09:45:49 -05002066 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002067 if (!ec->crtcs) {
2068 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002069 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002070 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002071
Rob Clark4339add2012-08-09 14:18:28 -05002072 ec->min_width = resources->min_width;
2073 ec->max_width = resources->max_width;
2074 ec->min_height = resources->min_height;
2075 ec->max_height = resources->max_height;
2076
Jesse Barnes58ef3792012-02-23 09:45:49 -05002077 ec->num_crtcs = resources->count_crtcs;
2078 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2079
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002080 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002081 connector = drmModeGetConnector(ec->drm.fd,
2082 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002083 if (connector == NULL)
2084 continue;
2085
2086 if (connector->connection == DRM_MODE_CONNECTED &&
2087 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002088 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002089 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002090 connector, x, y,
2091 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002092 drmModeFreeConnector(connector);
2093 continue;
2094 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002095
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002096 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002097 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002098 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002099 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002100
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002101 drmModeFreeConnector(connector);
2102 }
2103
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002104 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002105 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002106 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002107 return -1;
2108 }
2109
2110 drmModeFreeResources(resources);
2111
2112 return 0;
2113}
2114
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002115static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002116update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002117{
2118 drmModeConnector *connector;
2119 drmModeRes *resources;
2120 struct drm_output *output, *next;
2121 int x = 0, y = 0;
2122 int x_offset = 0, y_offset = 0;
2123 uint32_t connected = 0, disconnects = 0;
2124 int i;
2125
2126 resources = drmModeGetResources(ec->drm.fd);
2127 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002128 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002129 return;
2130 }
2131
2132 /* collect new connects */
2133 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002134 int connector_id = resources->connectors[i];
2135
2136 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002137 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002138 continue;
2139
David Herrmann7551cff2011-12-08 17:05:43 +01002140 if (connector->connection != DRM_MODE_CONNECTED) {
2141 drmModeFreeConnector(connector);
2142 continue;
2143 }
2144
Benjamin Franzke117483d2011-08-30 11:38:26 +02002145 connected |= (1 << connector_id);
2146
2147 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002148 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002149 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002150 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002151
2152 /* XXX: not yet needed, we die with 0 outputs */
2153 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002154 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002155 else
2156 x = 0;
2157 y = 0;
2158 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002159 connector, x, y,
2160 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002161 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002162
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002163 }
2164 drmModeFreeConnector(connector);
2165 }
2166 drmModeFreeResources(resources);
2167
2168 disconnects = ec->connector_allocator & ~connected;
2169 if (disconnects) {
2170 wl_list_for_each_safe(output, next, &ec->base.output_list,
2171 base.link) {
2172 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002173 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002174 output->base.x - x_offset,
2175 output->base.y - y_offset);
2176 }
2177
2178 if (disconnects & (1 << output->connector_id)) {
2179 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002180 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002181 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002182 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002183 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002184 }
2185 }
2186 }
2187
2188 /* FIXME: handle zero outputs, without terminating */
2189 if (ec->connector_allocator == 0)
2190 wl_display_terminate(ec->base.wl_display);
2191}
2192
2193static int
David Herrmannd7488c22012-03-11 20:05:21 +01002194udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002195{
David Herrmannd7488c22012-03-11 20:05:21 +01002196 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002197 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002198
2199 sysnum = udev_device_get_sysnum(device);
2200 if (!sysnum || atoi(sysnum) != ec->drm.id)
2201 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002202
David Herrmann6ac52db2012-03-11 20:05:22 +01002203 val = udev_device_get_property_value(device, "HOTPLUG");
2204 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002205 return 0;
2206
David Herrmann6ac52db2012-03-11 20:05:22 +01002207 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002208}
2209
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002210static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002211udev_drm_event(int fd, uint32_t mask, void *data)
2212{
2213 struct drm_compositor *ec = data;
2214 struct udev_device *event;
2215
2216 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002217
David Herrmannd7488c22012-03-11 20:05:21 +01002218 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002219 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002220
2221 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002222
2223 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002224}
2225
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002226static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002227drm_restore(struct weston_compositor *ec)
2228{
2229 struct drm_compositor *d = (struct drm_compositor *) ec;
2230
2231 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2232 weston_log("failed to drop master: %m\n");
2233 tty_reset(d->tty);
2234}
2235
2236static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002237drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002238{
2239 struct drm_compositor *d = (struct drm_compositor *) ec;
2240
Rob Bradfordd355b802013-05-31 18:09:55 +01002241 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002242
2243 wl_event_source_remove(d->udev_drm_source);
2244 wl_event_source_remove(d->drm_source);
2245
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002246 destroy_sprites(d);
2247
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002248 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002249
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002250 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002251
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002252 if (d->gbm)
2253 gbm_device_destroy(d->gbm);
2254
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002255 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002256 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002257 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002258
Rob Bradford45c15b82013-07-26 16:29:35 +01002259 close(d->drm.fd);
2260
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002261 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002262}
2263
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002264static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002265drm_compositor_set_modes(struct drm_compositor *compositor)
2266{
2267 struct drm_output *output;
2268 struct drm_mode *drm_mode;
2269 int ret;
2270
2271 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002272 if (!output->current) {
2273 /* If something that would cause the output to
2274 * switch mode happened while in another vt, we
2275 * might not have a current drm_fb. In that case,
2276 * schedule a repaint and let drm_output_repaint
2277 * handle setting the mode. */
2278 weston_output_schedule_repaint(&output->base);
2279 continue;
2280 }
2281
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002282 drm_mode = (struct drm_mode *) output->base.current;
2283 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002284 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002285 &output->connector_id, 1,
2286 &drm_mode->mode_info);
2287 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002288 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002289 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002290 drm_mode->base.width, drm_mode->base.height,
2291 output->base.x, output->base.y);
2292 }
2293 }
2294}
2295
2296static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002297vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002298{
2299 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002300 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002301 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002302
2303 switch (event) {
2304 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002305 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002306 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002307 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002308 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002309 wl_display_terminate(compositor->wl_display);
2310 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002311 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002312 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002313 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002314 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002315 break;
2316 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002317 weston_log("leaving VT\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002318 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002319
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002320 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002321 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002322 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002323
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002324 /* If we have a repaint scheduled (either from a
2325 * pending pageflip or the idle handler), make sure we
2326 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002327 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002328 * further attemps at repainting. When we switch
2329 * back, we schedule a repaint, which will process
2330 * pending frame callbacks. */
2331
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002332 wl_list_for_each(output, &ec->base.output_list, base.link) {
2333 output->base.repaint_needed = 0;
2334 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002335 }
2336
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002337 output = container_of(ec->base.output_list.next,
2338 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002339
2340 wl_list_for_each(sprite, &ec->sprite_list, link)
2341 drmModeSetPlane(ec->drm.fd,
2342 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002343 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002344 0, 0, 0, 0, 0, 0, 0, 0);
2345
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002346 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002347 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002348
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002349 break;
2350 };
2351}
2352
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002353static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002354switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002355{
2356 struct drm_compositor *ec = data;
2357
Daniel Stone325fc2d2012-05-30 16:31:58 +01002358 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002359}
2360
David Herrmann0af066f2012-10-29 19:21:16 +01002361/*
2362 * Find primary GPU
2363 * Some systems may have multiple DRM devices attached to a single seat. This
2364 * function loops over all devices and tries to find a PCI device with the
2365 * boot_vga sysfs attribute set to 1.
2366 * If no such device is found, the first DRM device reported by udev is used.
2367 */
2368static struct udev_device*
2369find_primary_gpu(struct drm_compositor *ec, const char *seat)
2370{
2371 struct udev_enumerate *e;
2372 struct udev_list_entry *entry;
2373 const char *path, *device_seat, *id;
2374 struct udev_device *device, *drm_device, *pci;
2375
2376 e = udev_enumerate_new(ec->udev);
2377 udev_enumerate_add_match_subsystem(e, "drm");
2378 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2379
2380 udev_enumerate_scan_devices(e);
2381 drm_device = NULL;
2382 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2383 path = udev_list_entry_get_name(entry);
2384 device = udev_device_new_from_syspath(ec->udev, path);
2385 if (!device)
2386 continue;
2387 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2388 if (!device_seat)
2389 device_seat = default_seat;
2390 if (strcmp(device_seat, seat)) {
2391 udev_device_unref(device);
2392 continue;
2393 }
2394
2395 pci = udev_device_get_parent_with_subsystem_devtype(device,
2396 "pci", NULL);
2397 if (pci) {
2398 id = udev_device_get_sysattr_value(pci, "boot_vga");
2399 if (id && !strcmp(id, "1")) {
2400 if (drm_device)
2401 udev_device_unref(drm_device);
2402 drm_device = device;
2403 break;
2404 }
2405 }
2406
2407 if (!drm_device)
2408 drm_device = device;
2409 else
2410 udev_device_unref(device);
2411 }
2412
2413 udev_enumerate_unref(e);
2414 return drm_device;
2415}
2416
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002417static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002418planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002419{
2420 struct drm_compositor *c = data;
2421
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002422 switch (key) {
2423 case KEY_C:
2424 c->cursors_are_broken ^= 1;
2425 break;
2426 case KEY_V:
2427 c->sprites_are_broken ^= 1;
2428 break;
2429 case KEY_O:
2430 c->sprites_hidden ^= 1;
2431 break;
2432 default:
2433 break;
2434 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002435}
2436
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002437static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002438drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002439 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002440 int *argc, char *argv[],
2441 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002442{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002443 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002444 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002445 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002446 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002447 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002448
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002449 weston_log("initializing drm backend\n");
2450
Peter Huttererf3d62272013-08-08 11:57:05 +10002451 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002452 if (ec == NULL)
2453 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002454
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002455 /* KMS support for sprites is not complete yet, so disable the
2456 * functionality for now. */
2457 ec->sprites_are_broken = 1;
2458
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002459 ec->use_pixman = pixman;
2460
Daniel Stone725c2c32012-06-22 14:04:36 +01002461 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002462 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002463 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002464 goto err_base;
2465 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002466
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002467 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg3c95e702013-07-23 12:24:00 -07002468 ec->base.launcher_sock =
2469 weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002470 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002471 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002472 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002473 goto err_compositor;
2474 }
2475
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002476 ec->udev = udev_new();
2477 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002478 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002479 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002480 }
2481
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002482 ec->base.wl_display = display;
2483 ec->tty = tty_create(&ec->base, vt_func, tty);
2484 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002485 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002486 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002487 }
2488
Rob Bradford643641d2013-05-31 18:09:53 +01002489 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002490 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002491 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002492 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002493 }
David Herrmann0af066f2012-10-29 19:21:16 +01002494 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002495
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002496 if (init_drm(ec, drm_device) < 0) {
2497 weston_log("failed to initialize kms\n");
2498 goto err_udev_dev;
2499 }
2500
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002501 if (ec->use_pixman) {
2502 if (init_pixman(ec) < 0) {
2503 weston_log("failed to initialize pixman renderer\n");
2504 goto err_udev_dev;
2505 }
2506 } else {
2507 if (init_egl(ec) < 0) {
2508 weston_log("failed to initialize egl\n");
2509 goto err_udev_dev;
2510 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002511 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002512
2513 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002514 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002515
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002516 ec->base.focus = 1;
2517
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002518 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002519
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002520 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002521 weston_compositor_add_key_binding(&ec->base, key,
2522 MODIFIER_CTRL | MODIFIER_ALT,
2523 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002524
Jesse Barnes58ef3792012-02-23 09:45:49 -05002525 wl_list_init(&ec->sprite_list);
2526 create_sprites(ec);
2527
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002528 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002529 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002530 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002531 }
2532
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002533 path = NULL;
2534
Rob Bradfordd355b802013-05-31 18:09:55 +01002535 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002536 weston_log("failed to create input devices\n");
2537 goto err_sprite;
2538 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002539
2540 loop = wl_display_get_event_loop(ec->base.wl_display);
2541 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002542 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002543 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002544
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002545 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2546 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002547 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002548 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002549 }
2550 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2551 "drm", NULL);
2552 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002553 wl_event_loop_add_fd(loop,
2554 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002555 WL_EVENT_READABLE, udev_drm_event, ec);
2556
2557 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002558 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002559 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002560 }
2561
Daniel Stonea96b93c2012-06-22 14:04:37 +01002562 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002563
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002564 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002565 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002566 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002567 planes_binding, ec);
2568 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2569 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002570
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002571 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002572
2573err_udev_monitor:
2574 wl_event_source_remove(ec->udev_drm_source);
2575 udev_monitor_unref(ec->udev_monitor);
2576err_drm_source:
2577 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002578 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002579err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002580 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002581 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002582 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002583err_udev_dev:
2584 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002585err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002586 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2587 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002588 tty_destroy(ec->tty);
2589err_udev:
2590 udev_unref(ec->udev);
2591err_compositor:
2592 weston_compositor_shutdown(&ec->base);
2593err_base:
2594 free(ec);
2595 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002596}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002597
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002598WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002599backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002600 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002601{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002602 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002603 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002604
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002605 const struct weston_option drm_options[] = {
2606 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002607 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002608 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002609 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002610 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002611 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002612
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002613 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002614
Rob Bradford643641d2013-05-31 18:09:53 +01002615 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002616 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002617}