blob: ef2771fee2d1512670341245f4f2dc5135808a36 [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
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700241 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200242 create_arg.bpp = 32;
243 create_arg.width = width;
244 create_arg.height = height;
245
246 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
247 if (ret)
248 goto err_fb;
249
250 fb->handle = create_arg.handle;
251 fb->stride = create_arg.pitch;
252 fb->size = create_arg.size;
253 fb->fd = ec->drm.fd;
254
255 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
256 fb->stride, fb->handle, &fb->fb_id);
257 if (ret)
258 goto err_bo;
259
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700260 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200261 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400262 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200263 if (ret)
264 goto err_add_fb;
265
266 fb->map = mmap(0, fb->size, PROT_WRITE,
267 MAP_SHARED, ec->drm.fd, map_arg.offset);
268 if (fb->map == MAP_FAILED)
269 goto err_add_fb;
270
271 return fb;
272
273err_add_fb:
274 drmModeRmFB(ec->drm.fd, fb->fb_id);
275err_bo:
276 memset(&destroy_arg, 0, sizeof(destroy_arg));
277 destroy_arg.handle = create_arg.handle;
278 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
279err_fb:
280 free(fb);
281 return NULL;
282}
283
284static void
285drm_fb_destroy_dumb(struct drm_fb *fb)
286{
287 struct drm_mode_destroy_dumb destroy_arg;
288
289 if (!fb->map)
290 return;
291
292 if (fb->fb_id)
293 drmModeRmFB(fb->fd, fb->fb_id);
294
295 weston_buffer_reference(&fb->buffer_ref, NULL);
296
297 munmap(fb->map, fb->size);
298
299 memset(&destroy_arg, 0, sizeof(destroy_arg));
300 destroy_arg.handle = fb->handle;
301 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
302
303 free(fb);
304}
305
306static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500307drm_fb_get_from_bo(struct gbm_bo *bo,
308 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300309{
310 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200311 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200312 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300313 int ret;
314
315 if (fb)
316 return fb;
317
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200318 fb = calloc(1, sizeof *fb);
319 if (!fb)
320 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300321
322 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300323
324 width = gbm_bo_get_width(bo);
325 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200326 fb->stride = gbm_bo_get_stride(bo);
327 fb->handle = gbm_bo_get_handle(bo).u32;
328 fb->size = fb->stride * height;
329 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300330
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200331 if (compositor->min_width > width || width > compositor->max_width ||
332 compositor->min_height > height ||
333 height > compositor->max_height) {
334 weston_log("bo geometry out of bounds\n");
335 goto err_free;
336 }
337
338 ret = -1;
339
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200340 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200341 handles[0] = fb->handle;
342 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200343 offsets[0] = 0;
344
345 ret = drmModeAddFB2(compositor->drm.fd, width, height,
346 format, handles, pitches, offsets,
347 &fb->fb_id, 0);
348 if (ret) {
349 weston_log("addfb2 failed: %m\n");
350 compositor->no_addfb2 = 1;
351 compositor->sprites_are_broken = 1;
352 }
353 }
354
355 if (ret)
356 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200357 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200358
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200360 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362 }
363
364 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
365
366 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200367
368err_free:
369 free(fb);
370 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300371}
372
373static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500374drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200375{
Pekka Paalanende685b82012-12-04 15:58:12 +0200376 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200377
378 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379
Pekka Paalanende685b82012-12-04 15:58:12 +0200380 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200381}
382
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200383static void
384drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
385{
386 if (!fb)
387 return;
388
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200389 if (fb->map &&
390 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200391 drm_fb_destroy_dumb(fb);
392 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200393 if (fb->is_client_buffer)
394 gbm_bo_destroy(fb->bo);
395 else
396 gbm_surface_release_buffer(output->surface,
397 output->current->bo);
398 }
399}
400
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500401static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200402drm_output_check_scanout_format(struct drm_output *output,
403 struct weston_surface *es, struct gbm_bo *bo)
404{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200405 uint32_t format;
406 pixman_region32_t r;
407
408 format = gbm_bo_get_format(bo);
409
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500410 switch (format) {
411 case GBM_FORMAT_XRGB8888:
412 return format;
413 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200414 /* We can only scanout an ARGB buffer if the surface's
415 * opaque region covers the whole output */
416 pixman_region32_init(&r);
417 pixman_region32_subtract(&r, &output->base.region,
418 &es->opaque);
419
420 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500421 format = GBM_FORMAT_XRGB8888;
422 else
423 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200424
425 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200426
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500427 return format;
428 default:
429 return 0;
430 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200431}
432
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400433static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400434drm_output_prepare_scanout_surface(struct weston_output *_output,
435 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500436{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400437 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500438 struct drm_compositor *c =
439 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500440 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300441 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500442 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500443
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500444 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200445 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200446 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200447 buffer->width != output->base.current->width ||
448 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200449 output->base.transform != es->buffer_transform ||
450 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400451 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500452
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400453 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200454 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500455
Rob Bradford9b101872012-09-14 23:25:41 +0100456 /* Unable to use the buffer for scanout */
457 if (!bo)
458 return NULL;
459
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500460 format = drm_output_check_scanout_format(output, es, bo);
461 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300462 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400463 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300464 }
465
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500466 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300467 if (!output->next) {
468 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400469 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300470 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500471
Pekka Paalanende685b82012-12-04 15:58:12 +0200472 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500473
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400474 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500475}
476
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500477static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200478drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400479{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200480 struct drm_compositor *c =
481 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300482 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400483
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200484 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400485
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300486 bo = gbm_surface_lock_front_buffer(output->surface);
487 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200488 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400489 return;
490 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300491
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500492 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300493 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200494 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300495 gbm_surface_release_buffer(output->surface, bo);
496 return;
497 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400498}
499
500static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200501drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
502{
503 struct weston_compositor *ec = output->base.compositor;
504 pixman_region32_t total_damage, previous_damage;
505
506 pixman_region32_init(&total_damage);
507 pixman_region32_init(&previous_damage);
508
509 pixman_region32_copy(&previous_damage, damage);
510
511 pixman_region32_union(&total_damage, damage, &output->previous_damage);
512 pixman_region32_copy(&output->previous_damage, &previous_damage);
513
514 output->current_image ^= 1;
515
516 output->next = output->dumb[output->current_image];
517 pixman_renderer_output_set_buffer(&output->base,
518 output->image[output->current_image]);
519
520 ec->renderer->repaint_output(&output->base, &total_damage);
521
522 pixman_region32_fini(&total_damage);
523 pixman_region32_fini(&previous_damage);
524}
525
526static void
527drm_output_render(struct drm_output *output, pixman_region32_t *damage)
528{
529 struct drm_compositor *c =
530 (struct drm_compositor *) output->base.compositor;
531
532 if (c->use_pixman)
533 drm_output_render_pixman(output, damage);
534 else
535 drm_output_render_gl(output, damage);
536
537 pixman_region32_subtract(&c->base.primary_plane.damage,
538 &c->base.primary_plane.damage, damage);
539}
540
541static void
Richard Hughese7299962013-05-01 21:52:12 +0100542drm_output_set_gamma(struct weston_output *output_base,
543 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
544{
545 int rc;
546 struct drm_output *output = (struct drm_output *) output_base;
547 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
548
549 /* check */
550 if (output_base->gamma_size != size)
551 return;
552 if (!output->original_crtc)
553 return;
554
555 rc = drmModeCrtcSetGamma(compositor->drm.fd,
556 output->crtc_id,
557 size, r, g, b);
558 if (rc)
559 weston_log("set gamma failed: %m\n");
560}
561
562static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500563drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400564 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100565{
566 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500567 struct drm_compositor *compositor =
568 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500569 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400570 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500571 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100572
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300573 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400574 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300575 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400576 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100577
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400578 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300579 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400580 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300581 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400582 &output->connector_id, 1,
583 &mode->mode_info);
584 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200585 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400586 return;
587 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300588 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200589 }
590
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500591 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300592 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500593 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200594 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500595 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500596 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100597
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300598 output->page_flip_pending = 1;
599
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400600 drm_output_set_cursor(output);
601
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602 /*
603 * Now, update all the sprite surfaces
604 */
605 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200606 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500607 drmVBlank vbl = {
608 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
609 .request.sequence = 1,
610 };
611
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200612 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200613 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500614 continue;
615
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200616 if (s->next && !compositor->sprites_hidden)
617 fb_id = s->next->fb_id;
618
Jesse Barnes58ef3792012-02-23 09:45:49 -0500619 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200620 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 s->dest_x, s->dest_y,
622 s->dest_w, s->dest_h,
623 s->src_x, s->src_y,
624 s->src_w, s->src_h);
625 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200626 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 ret, strerror(errno));
628
Rob Clark5ca1a472012-08-08 20:27:37 -0500629 if (output->pipe > 0)
630 vbl.request.type |= DRM_VBLANK_SECONDARY;
631
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 /*
633 * Queue a vblank signal so we know when the surface
634 * becomes active on the display or has been replaced.
635 */
636 vbl.request.signal = (unsigned long)s;
637 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
638 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200639 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640 ret, strerror(errno));
641 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300642
643 s->output = output;
644 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 }
646
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500647 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400648}
649
650static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200651drm_output_start_repaint_loop(struct weston_output *output_base)
652{
653 struct drm_output *output = (struct drm_output *) output_base;
654 struct drm_compositor *compositor = (struct drm_compositor *)
655 output_base->compositor;
656 uint32_t fb_id;
657
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300658 struct timespec ts;
659
660 if (!output->current) {
661 /* We can't page flip if there's no mode set */
662 uint32_t msec;
663
664 clock_gettime(compositor->clock, &ts);
665 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
666 weston_output_finish_frame(output_base, msec);
667 return;
668 }
669
670 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200671
672 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
673 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
674 weston_log("queueing pageflip failed: %m\n");
675 return;
676 }
677}
678
679static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500680vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
681 void *data)
682{
683 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300684 struct drm_output *output = s->output;
685 uint32_t msecs;
686
687 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500688
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200689 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200690 s->current = s->next;
691 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300692
693 if (!output->page_flip_pending) {
694 msecs = sec * 1000 + usec / 1000;
695 weston_output_finish_frame(&output->base, msecs);
696 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500697}
698
699static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400700page_flip_handler(int fd, unsigned int frame,
701 unsigned int sec, unsigned int usec, void *data)
702{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200703 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400704 uint32_t msecs;
705
Jonas Ådahle5a12252013-04-05 23:07:11 +0200706 /* We don't set page_flip_pending on start_repaint_loop, in that case
707 * we just want to page flip to the current buffer to get an accurate
708 * timestamp */
709 if (output->page_flip_pending) {
710 drm_output_release_fb(output, output->current);
711 output->current = output->next;
712 output->next = NULL;
713 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300714
Jonas Ådahle5a12252013-04-05 23:07:11 +0200715 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400716
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300717 if (!output->vblank_pending) {
718 msecs = sec * 1000 + usec / 1000;
719 weston_output_finish_frame(&output->base, msecs);
720 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200721}
722
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500723static uint32_t
724drm_output_check_sprite_format(struct drm_sprite *s,
725 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500726{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500727 uint32_t i, format;
728
729 format = gbm_bo_get_format(bo);
730
731 if (format == GBM_FORMAT_ARGB8888) {
732 pixman_region32_t r;
733
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500734 pixman_region32_init_rect(&r, 0, 0,
735 es->geometry.width,
736 es->geometry.height);
737 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500738
739 if (!pixman_region32_not_empty(&r))
740 format = GBM_FORMAT_XRGB8888;
741
742 pixman_region32_fini(&r);
743 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500744
745 for (i = 0; i < s->count_formats; i++)
746 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500747 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500748
749 return 0;
750}
751
752static int
753drm_surface_transform_supported(struct weston_surface *es)
754{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500755 return !es->transform.enabled ||
756 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500757}
758
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400759static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500760drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400761 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500762{
763 struct weston_compositor *ec = output_base->compositor;
764 struct drm_compositor *c =(struct drm_compositor *) ec;
765 struct drm_sprite *s;
766 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500767 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200769 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400771 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200773 if (c->gbm == NULL)
774 return NULL;
775
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200776 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200777 return NULL;
778
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200779 if (es->buffer_scale != output_base->scale)
780 return NULL;
781
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500782 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400783 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500784
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300785 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400786 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300787
Pekka Paalanende685b82012-12-04 15:58:12 +0200788 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400789 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500790
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200791 if (es->alpha != 1.0f)
792 return NULL;
793
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500794 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500795 return NULL;
796
Jesse Barnes58ef3792012-02-23 09:45:49 -0500797 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400798 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799
Jesse Barnes58ef3792012-02-23 09:45:49 -0500800 wl_list_for_each(s, &c->sprite_list, link) {
801 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
802 continue;
803
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200804 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500805 found = 1;
806 break;
807 }
808 }
809
810 /* No sprites available */
811 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400812 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500813
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400814 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200815 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400816 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400817 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400818
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500819 format = drm_output_check_sprite_format(s, es, bo);
820 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200821 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400822 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823 }
824
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200825 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200826 if (!s->next) {
827 gbm_bo_destroy(bo);
828 return NULL;
829 }
830
Pekka Paalanende685b82012-12-04 15:58:12 +0200831 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500832
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400833 box = pixman_region32_extents(&es->transform.boundingbox);
834 s->plane.x = box->x1;
835 s->plane.y = box->y1;
836
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837 /*
838 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200839 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500840 * for us already).
841 */
842 pixman_region32_init(&dest_rect);
843 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
844 &output_base->region);
845 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
846 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200847 tbox = weston_transformed_rect(output_base->width,
848 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200849 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200850 output_base->scale,
851 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200852 s->dest_x = tbox.x1;
853 s->dest_y = tbox.y1;
854 s->dest_w = tbox.x2 - tbox.x1;
855 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500856 pixman_region32_fini(&dest_rect);
857
858 pixman_region32_init(&src_rect);
859 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
860 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500861 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400862
863 weston_surface_from_global_fixed(es,
864 wl_fixed_from_int(box->x1),
865 wl_fixed_from_int(box->y1),
866 &sx1, &sy1);
867 weston_surface_from_global_fixed(es,
868 wl_fixed_from_int(box->x2),
869 wl_fixed_from_int(box->y2),
870 &sx2, &sy2);
871
872 if (sx1 < 0)
873 sx1 = 0;
874 if (sy1 < 0)
875 sy1 = 0;
876 if (sx2 > wl_fixed_from_int(es->geometry.width))
877 sx2 = wl_fixed_from_int(es->geometry.width);
878 if (sy2 > wl_fixed_from_int(es->geometry.height))
879 sy2 = wl_fixed_from_int(es->geometry.height);
880
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200881 tbox.x1 = sx1;
882 tbox.y1 = sy1;
883 tbox.x2 = sx2;
884 tbox.y2 = sy2;
885
886 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
887 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200888 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200889
890 s->src_x = tbox.x1 << 8;
891 s->src_y = tbox.y1 << 8;
892 s->src_w = (tbox.x2 - tbox.x1) << 8;
893 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500894 pixman_region32_fini(&src_rect);
895
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400896 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500897}
898
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400899static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400900drm_output_prepare_cursor_surface(struct weston_output *output_base,
901 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500902{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400903 struct drm_compositor *c =
904 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400905 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400906
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200907 if (c->gbm == NULL)
908 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200909 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
910 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400911 if (output->cursor_surface)
912 return NULL;
913 if (es->output_mask != (1u << output_base->id))
914 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500915 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400916 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200917 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500918 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400919 es->geometry.width > 64 || es->geometry.height > 64)
920 return NULL;
921
922 output->cursor_surface = es;
923
924 return &output->cursor_plane;
925}
926
927static void
928drm_output_set_cursor(struct drm_output *output)
929{
930 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400931 struct drm_compositor *c =
932 (struct drm_compositor *) output->base.compositor;
933 EGLint handle, stride;
934 struct gbm_bo *bo;
935 uint32_t buf[64 * 64];
936 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400937 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500938
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400939 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400940 if (es == NULL) {
941 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
942 return;
943 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500944
Pekka Paalanende685b82012-12-04 15:58:12 +0200945 if (es->buffer_ref.buffer &&
946 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400947 pixman_region32_fini(&output->cursor_plane.damage);
948 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400949 output->current_cursor ^= 1;
950 bo = output->cursor_bo[output->current_cursor];
951 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500952 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
953 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400954 for (i = 0; i < es->geometry.height; i++)
955 memcpy(buf + i * 64, s + i * stride,
956 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500957
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400958 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300959 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400960
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400961 handle = gbm_bo_get_handle(bo).s32;
962 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500963 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300964 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500965 c->cursors_are_broken = 1;
966 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400967 }
968
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200969 x = (es->geometry.x - output->base.x) * output->base.scale;
970 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400971 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500972 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400973 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500974 c->cursors_are_broken = 1;
975 }
976
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400977 output->cursor_plane.x = x;
978 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400979 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500980}
981
Jesse Barnes58ef3792012-02-23 09:45:49 -0500982static void
983drm_assign_planes(struct weston_output *output)
984{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400985 struct drm_compositor *c =
986 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400987 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500988 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400989 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500990
991 /*
992 * Find a surface for each sprite in the output using some heuristics:
993 * 1) size
994 * 2) frequency of update
995 * 3) opacity (though some hw might support alpha blending)
996 * 4) clipping (this can be fixed with color keys)
997 *
998 * The idea is to save on blitting since this should save power.
999 * If we can get a large video surface on the sprite for example,
1000 * the main display surface may not need to update at all, and
1001 * the client buffer can be used directly for the sprite surface
1002 * as we do for flipping full screen surfaces.
1003 */
1004 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001005 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001006 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001007 /* test whether this buffer can ever go into a plane:
1008 * non-shm, or small enough to be a cursor
1009 */
1010 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001011 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001012 (es->geometry.width <= 64 && es->geometry.height <= 64))
1013 es->keep_buffer = 1;
1014 else
1015 es->keep_buffer = 0;
1016
Jesse Barnes58ef3792012-02-23 09:45:49 -05001017 pixman_region32_init(&surface_overlap);
1018 pixman_region32_intersect(&surface_overlap, &overlap,
1019 &es->transform.boundingbox);
1020
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001021 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001022 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001023 next_plane = primary;
1024 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001025 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001026 if (next_plane == NULL)
1027 next_plane = drm_output_prepare_scanout_surface(output, es);
1028 if (next_plane == NULL)
1029 next_plane = drm_output_prepare_overlay_surface(output, es);
1030 if (next_plane == NULL)
1031 next_plane = primary;
1032 weston_surface_move_to_plane(es, next_plane);
1033 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001034 pixman_region32_union(&overlap, &overlap,
1035 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001036
Jesse Barnes58ef3792012-02-23 09:45:49 -05001037 pixman_region32_fini(&surface_overlap);
1038 }
1039 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001040}
1041
Matt Roper361d2ad2011-08-29 13:52:23 -07001042static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001043drm_output_fini_pixman(struct drm_output *output);
1044
1045static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001046drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001047{
1048 struct drm_output *output = (struct drm_output *) output_base;
1049 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001050 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001051 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001052
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001053 if (output->backlight)
1054 backlight_destroy(output->backlight);
1055
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001056 drmModeFreeProperty(output->dpms_prop);
1057
Matt Roper361d2ad2011-08-29 13:52:23 -07001058 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001059 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001060
1061 /* Restore original CRTC state */
1062 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001063 origcrtc->x, origcrtc->y,
1064 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001065 drmModeFreeCrtc(origcrtc);
1066
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001067 c->crtc_allocator &= ~(1 << output->crtc_id);
1068 c->connector_allocator &= ~(1 << output->connector_id);
1069
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001070 if (c->use_pixman) {
1071 drm_output_fini_pixman(output);
1072 } else {
1073 gl_renderer_output_destroy(output_base);
1074 gbm_surface_destroy(output->surface);
1075 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001076
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001077 weston_plane_release(&output->fb_plane);
1078 weston_plane_release(&output->cursor_plane);
1079
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001080 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001081 wl_list_remove(&output->base.link);
1082
Matt Roper361d2ad2011-08-29 13:52:23 -07001083 free(output);
1084}
1085
Alex Wub7b8bda2012-04-17 17:20:48 +08001086static struct drm_mode *
1087choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1088{
1089 struct drm_mode *tmp_mode = NULL, *mode;
1090
1091 if (output->base.current->width == target_mode->width &&
1092 output->base.current->height == target_mode->height &&
1093 (output->base.current->refresh == target_mode->refresh ||
1094 target_mode->refresh == 0))
1095 return (struct drm_mode *)output->base.current;
1096
1097 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1098 if (mode->mode_info.hdisplay == target_mode->width &&
1099 mode->mode_info.vdisplay == target_mode->height) {
1100 if (mode->mode_info.vrefresh == target_mode->refresh ||
1101 target_mode->refresh == 0) {
1102 return mode;
1103 } else if (!tmp_mode)
1104 tmp_mode = mode;
1105 }
1106 }
1107
1108 return tmp_mode;
1109}
1110
1111static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001112drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001113static int
1114drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001115
1116static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001117drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1118{
1119 struct drm_output *output;
1120 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001121 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001122
1123 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001124 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001125 return -1;
1126 }
1127
1128 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001129 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001130 return -1;
1131 }
1132
1133 ec = (struct drm_compositor *)output_base->compositor;
1134 output = (struct drm_output *)output_base;
1135 drm_mode = choose_mode (output, mode);
1136
1137 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001138 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001139 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001140 }
1141
1142 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001143 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001144
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001145 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001146
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001147 output->base.current = &drm_mode->base;
1148 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001149 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1150
Alex Wub7b8bda2012-04-17 17:20:48 +08001151 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001152 drm_output_release_fb(output, output->current);
1153 drm_output_release_fb(output, output->next);
1154 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001155
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001156 if (ec->use_pixman) {
1157 drm_output_fini_pixman(output);
1158 if (drm_output_init_pixman(output, ec) < 0) {
1159 weston_log("failed to init output pixman state with "
1160 "new mode\n");
1161 return -1;
1162 }
1163 } else {
1164 gl_renderer_output_destroy(&output->base);
1165 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001166
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001167 if (drm_output_init_egl(output, ec) < 0) {
1168 weston_log("failed to init output egl state with "
1169 "new mode");
1170 return -1;
1171 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001172 }
1173
Alex Wub7b8bda2012-04-17 17:20:48 +08001174 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001175}
1176
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001177static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001178on_drm_input(int fd, uint32_t mask, void *data)
1179{
1180 drmEventContext evctx;
1181
1182 memset(&evctx, 0, sizeof evctx);
1183 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1184 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001185 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001186 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001187
1188 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001189}
1190
1191static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001192init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001193{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001194 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001195 uint64_t cap;
1196 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001197
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001198 sysnum = udev_device_get_sysnum(device);
1199 if (sysnum)
1200 ec->drm.id = atoi(sysnum);
1201 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001202 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001203 return -1;
1204 }
1205
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001206 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001207 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001208 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001209 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001210 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001211 udev_device_get_devnode(device));
1212 return -1;
1213 }
1214
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001215 weston_log("using %s\n", filename);
1216
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001217 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001218
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001219 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1220 if (ret == 0 && cap == 1)
1221 ec->clock = CLOCK_MONOTONIC;
1222 else
1223 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001224
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001225 return 0;
1226}
1227
1228static int
1229init_egl(struct drm_compositor *ec)
1230{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001231 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001232
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001233 if (!ec->gbm)
1234 return -1;
1235
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001236 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001237 NULL) < 0) {
1238 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001239 return -1;
1240 }
1241
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001242 return 0;
1243}
1244
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001245static int
1246init_pixman(struct drm_compositor *ec)
1247{
1248 return pixman_renderer_init(&ec->base);
1249}
1250
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001251static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001252drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001253{
1254 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001255 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001256
1257 mode = malloc(sizeof *mode);
1258 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001259 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001260
1261 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001262 mode->base.width = info->hdisplay;
1263 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001264
1265 /* Calculate higher precision (mHz) refresh rate */
1266 refresh = (info->clock * 1000000LL / info->htotal +
1267 info->vtotal / 2) / info->vtotal;
1268
1269 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1270 refresh *= 2;
1271 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1272 refresh /= 2;
1273 if (info->vscan > 1)
1274 refresh /= info->vscan;
1275
1276 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001277 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001278
1279 if (info->type & DRM_MODE_TYPE_PREFERRED)
1280 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1281
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001282 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1283
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001284 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001285}
1286
1287static int
1288drm_subpixel_to_wayland(int drm_value)
1289{
1290 switch (drm_value) {
1291 default:
1292 case DRM_MODE_SUBPIXEL_UNKNOWN:
1293 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1294 case DRM_MODE_SUBPIXEL_NONE:
1295 return WL_OUTPUT_SUBPIXEL_NONE;
1296 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1297 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1298 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1299 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1300 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1301 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1302 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1303 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1304 }
1305}
1306
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001307/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001308static uint32_t
1309drm_get_backlight(struct drm_output *output)
1310{
1311 long brightness, max_brightness, norm;
1312
1313 brightness = backlight_get_brightness(output->backlight);
1314 max_brightness = backlight_get_max_brightness(output->backlight);
1315
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001316 /* convert it on a scale of 0 to 255 */
1317 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001318
1319 return (uint32_t) norm;
1320}
1321
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001322/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001323static void
1324drm_set_backlight(struct weston_output *output_base, uint32_t value)
1325{
1326 struct drm_output *output = (struct drm_output *) output_base;
1327 long max_brightness, new_brightness;
1328
1329 if (!output->backlight)
1330 return;
1331
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001332 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001333 return;
1334
1335 max_brightness = backlight_get_max_brightness(output->backlight);
1336
1337 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001338 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001339
1340 backlight_set_brightness(output->backlight, new_brightness);
1341}
1342
1343static drmModePropertyPtr
1344drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1345{
1346 drmModePropertyPtr props;
1347 int i;
1348
1349 for (i = 0; i < connector->count_props; i++) {
1350 props = drmModeGetProperty(fd, connector->props[i]);
1351 if (!props)
1352 continue;
1353
1354 if (!strcmp(props->name, name))
1355 return props;
1356
1357 drmModeFreeProperty(props);
1358 }
1359
1360 return NULL;
1361}
1362
1363static void
1364drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1365{
1366 struct drm_output *output = (struct drm_output *) output_base;
1367 struct weston_compositor *ec = output_base->compositor;
1368 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001369
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001370 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001371 return;
1372
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001373 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1374 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001375}
1376
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001377static const char *connector_type_names[] = {
1378 "None",
1379 "VGA",
1380 "DVI",
1381 "DVI",
1382 "DVI",
1383 "Composite",
1384 "TV",
1385 "LVDS",
1386 "CTV",
1387 "DIN",
1388 "DP",
1389 "HDMI",
1390 "HDMI",
1391 "TV",
1392 "eDP",
1393};
1394
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001395static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001396find_crtc_for_connector(struct drm_compositor *ec,
1397 drmModeRes *resources, drmModeConnector *connector)
1398{
1399 drmModeEncoder *encoder;
1400 uint32_t possible_crtcs;
1401 int i, j;
1402
1403 for (j = 0; j < connector->count_encoders; j++) {
1404 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1405 if (encoder == NULL) {
1406 weston_log("Failed to get encoder.\n");
1407 return -1;
1408 }
1409 possible_crtcs = encoder->possible_crtcs;
1410 drmModeFreeEncoder(encoder);
1411
1412 for (i = 0; i < resources->count_crtcs; i++) {
1413 if (possible_crtcs & (1 << i) &&
1414 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1415 return i;
1416 }
1417 }
1418
1419 return -1;
1420}
1421
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001422/* Init output state that depends on gl or gbm */
1423static int
1424drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1425{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001426 int i, flags;
1427
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001428 output->surface = gbm_surface_create(ec->gbm,
Alexander Larsson0b135062013-05-28 16:23:36 +02001429 output->base.current->width,
1430 output->base.current->height,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001431 GBM_FORMAT_XRGB8888,
1432 GBM_BO_USE_SCANOUT |
1433 GBM_BO_USE_RENDERING);
1434 if (!output->surface) {
1435 weston_log("failed to create gbm surface\n");
1436 return -1;
1437 }
1438
1439 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001440 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001441 gbm_surface_destroy(output->surface);
1442 return -1;
1443 }
1444
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001445 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1446
1447 for (i = 0; i < 2; i++) {
1448 if (output->cursor_bo[i])
1449 continue;
1450
1451 output->cursor_bo[i] =
1452 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1453 flags);
1454 }
1455
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001456 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1457 weston_log("cursor buffers unavailable, using gl cursors\n");
1458 ec->cursors_are_broken = 1;
1459 }
1460
1461 return 0;
1462}
1463
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001464static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001465drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1466{
1467 int w = output->base.current->width;
1468 int h = output->base.current->height;
1469 unsigned int i;
1470
1471 /* FIXME error checking */
1472
1473 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001474 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001475 if (!output->dumb[i])
1476 goto err;
1477
1478 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001479 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001480 output->dumb[i]->map,
1481 output->dumb[i]->stride);
1482 if (!output->image[i])
1483 goto err;
1484 }
1485
1486 if (pixman_renderer_output_create(&output->base) < 0)
1487 goto err;
1488
1489 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001490 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001491
1492 return 0;
1493
1494err:
1495 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1496 if (output->dumb[i])
1497 drm_fb_destroy_dumb(output->dumb[i]);
1498 if (output->image[i])
1499 pixman_image_unref(output->image[i]);
1500
1501 output->dumb[i] = NULL;
1502 output->image[i] = NULL;
1503 }
1504
1505 return -1;
1506}
1507
1508static void
1509drm_output_fini_pixman(struct drm_output *output)
1510{
1511 unsigned int i;
1512
1513 pixman_renderer_output_destroy(&output->base);
1514 pixman_region32_fini(&output->previous_damage);
1515
1516 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1517 drm_fb_destroy_dumb(output->dumb[i]);
1518 pixman_image_unref(output->image[i]);
1519 output->dumb[i] = NULL;
1520 output->image[i] = NULL;
1521 }
1522}
1523
Richard Hughes2b2092a2013-04-24 14:58:02 +01001524static void
1525edid_parse_string(const uint8_t *data, char text[])
1526{
1527 int i;
1528 int replaced = 0;
1529
1530 /* this is always 12 bytes, but we can't guarantee it's null
1531 * terminated or not junk. */
1532 strncpy(text, (const char *) data, 12);
1533
1534 /* remove insane chars */
1535 for (i = 0; text[i] != '\0'; i++) {
1536 if (text[i] == '\n' ||
1537 text[i] == '\r') {
1538 text[i] = '\0';
1539 break;
1540 }
1541 }
1542
1543 /* ensure string is printable */
1544 for (i = 0; text[i] != '\0'; i++) {
1545 if (!isprint(text[i])) {
1546 text[i] = '-';
1547 replaced++;
1548 }
1549 }
1550
1551 /* if the string is random junk, ignore the string */
1552 if (replaced > 4)
1553 text[0] = '\0';
1554}
1555
1556#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1557#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1558#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1559#define EDID_OFFSET_DATA_BLOCKS 0x36
1560#define EDID_OFFSET_LAST_BLOCK 0x6c
1561#define EDID_OFFSET_PNPID 0x08
1562#define EDID_OFFSET_SERIAL 0x0c
1563
1564static int
1565edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1566{
1567 int i;
1568 uint32_t serial_number;
1569
1570 /* check header */
1571 if (length < 128)
1572 return -1;
1573 if (data[0] != 0x00 || data[1] != 0xff)
1574 return -1;
1575
1576 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1577 * /--08--\/--09--\
1578 * 7654321076543210
1579 * |\---/\---/\---/
1580 * R C1 C2 C3 */
1581 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1582 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1583 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1584 edid->pnp_id[3] = '\0';
1585
1586 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1587 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1588 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1589 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1590 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1591 if (serial_number > 0)
1592 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1593
1594 /* parse EDID data */
1595 for (i = EDID_OFFSET_DATA_BLOCKS;
1596 i <= EDID_OFFSET_LAST_BLOCK;
1597 i += 18) {
1598 /* ignore pixel clock data */
1599 if (data[i] != 0)
1600 continue;
1601 if (data[i+2] != 0)
1602 continue;
1603
1604 /* any useful blocks? */
1605 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1606 edid_parse_string(&data[i+5],
1607 edid->monitor_name);
1608 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1609 edid_parse_string(&data[i+5],
1610 edid->serial_number);
1611 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1612 edid_parse_string(&data[i+5],
1613 edid->eisa_id);
1614 }
1615 }
1616 return 0;
1617}
1618
1619static void
1620find_and_parse_output_edid(struct drm_compositor *ec,
1621 struct drm_output *output,
1622 drmModeConnector *connector)
1623{
1624 drmModePropertyBlobPtr edid_blob = NULL;
1625 drmModePropertyPtr property;
1626 int i;
1627 int rc;
1628
1629 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1630 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1631 if (!property)
1632 continue;
1633 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1634 !strcmp(property->name, "EDID")) {
1635 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1636 connector->prop_values[i]);
1637 }
1638 drmModeFreeProperty(property);
1639 }
1640 if (!edid_blob)
1641 return;
1642
1643 rc = edid_parse(&output->edid,
1644 edid_blob->data,
1645 edid_blob->length);
1646 if (!rc) {
1647 weston_log("EDID data '%s', '%s', '%s'\n",
1648 output->edid.pnp_id,
1649 output->edid.monitor_name,
1650 output->edid.serial_number);
1651 if (output->edid.pnp_id[0] != '\0')
1652 output->base.make = output->edid.pnp_id;
1653 if (output->edid.monitor_name[0] != '\0')
1654 output->base.model = output->edid.monitor_name;
1655 if (output->edid.serial_number[0] != '\0')
1656 output->base.serial_number = output->edid.serial_number;
1657 }
1658 drmModeFreePropertyBlob(edid_blob);
1659}
1660
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001661
1662
1663static int
1664parse_modeline(const char *s, drmModeModeInfo *mode)
1665{
1666 char hsync[16];
1667 char vsync[16];
1668 float fclock;
1669
1670 mode->type = DRM_MODE_TYPE_USERDEF;
1671 mode->hskew = 0;
1672 mode->vscan = 0;
1673 mode->vrefresh = 0;
1674 mode->flags = 0;
1675
Rob Bradford307e09e2013-07-26 16:29:40 +01001676 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001677 &fclock,
1678 &mode->hdisplay,
1679 &mode->hsync_start,
1680 &mode->hsync_end,
1681 &mode->htotal,
1682 &mode->vdisplay,
1683 &mode->vsync_start,
1684 &mode->vsync_end,
1685 &mode->vtotal, hsync, vsync) != 11)
1686 return -1;
1687
1688 mode->clock = fclock * 1000;
1689 if (strcmp(hsync, "+hsync") == 0)
1690 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1691 else if (strcmp(hsync, "-hsync") == 0)
1692 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1693 else
1694 return -1;
1695
1696 if (strcmp(vsync, "+vsync") == 0)
1697 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1698 else if (strcmp(vsync, "-vsync") == 0)
1699 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1700 else
1701 return -1;
1702
1703 return 0;
1704}
1705
1706static uint32_t
1707parse_transform(const char *transform, const char *output_name)
1708{
1709 static const struct { const char *name; uint32_t token; } names[] = {
1710 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1711 { "90", WL_OUTPUT_TRANSFORM_90 },
1712 { "180", WL_OUTPUT_TRANSFORM_180 },
1713 { "270", WL_OUTPUT_TRANSFORM_270 },
1714 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1715 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1716 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1717 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1718 };
1719 unsigned int i;
1720
1721 for (i = 0; i < ARRAY_LENGTH(names); i++)
1722 if (strcmp(names[i].name, transform) == 0)
1723 return names[i].token;
1724
1725 weston_log("Invalid transform \"%s\" for output %s\n",
1726 transform, output_name);
1727
1728 return WL_OUTPUT_TRANSFORM_NORMAL;
1729}
1730
Rob Bradford66bd9f52013-06-25 18:56:42 +01001731static void
1732setup_output_seat_constraint(struct drm_compositor *ec,
1733 struct weston_output *output,
1734 const char *s)
1735{
1736 if (strcmp(s, "") != 0) {
1737 struct udev_seat *seat;
1738
1739 seat = udev_seat_get_named(&ec->base, s);
1740 if (seat)
1741 seat->base.output = output;
1742
1743 if (seat && seat->base.pointer)
1744 weston_pointer_clamp(seat->base.pointer,
1745 &seat->base.pointer->x,
1746 &seat->base.pointer->y);
1747 }
1748}
1749
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001750static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001751create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001752 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001753 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001754 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001755{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001756 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001757 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1758 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001759 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001760 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001761 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001762 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001763 int i, width, height, scale;
1764 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001765 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001766 enum output_config config;
1767 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001768
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001769 i = find_crtc_for_connector(ec, resources, connector);
1770 if (i < 0) {
1771 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001772 return -1;
1773 }
1774
Peter Huttererf3d62272013-08-08 11:57:05 +10001775 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001776 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001777 return -1;
1778
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001779 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1780 output->base.make = "unknown";
1781 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001782 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001783 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001784
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001785 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1786 type_name = connector_type_names[connector->connector_type];
1787 else
1788 type_name = "UNKNOWN";
1789 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001790 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001791
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001792 section = weston_config_get_section(ec->base.config, "output", "name",
1793 output->base.name);
1794 weston_config_section_get_string(section, "mode", &s, "preferred");
1795 if (strcmp(s, "off") == 0)
1796 config = OUTPUT_CONFIG_OFF;
1797 else if (strcmp(s, "preferred") == 0)
1798 config = OUTPUT_CONFIG_PREFERRED;
1799 else if (strcmp(s, "current") == 0)
1800 config = OUTPUT_CONFIG_CURRENT;
1801 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1802 config = OUTPUT_CONFIG_MODE;
1803 else if (parse_modeline(s, &modeline) == 0)
1804 config = OUTPUT_CONFIG_MODELINE;
1805 else {
1806 weston_log("Invalid mode \"%s\" for output %s\n",
1807 s, output->base.name);
1808 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001809 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001810 free(s);
1811
1812 weston_config_section_get_int(section, "scale", &scale, 1);
1813 weston_config_section_get_string(section, "transform", &s, "normal");
1814 transform = parse_transform(s, output->base.name);
1815 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001816
Rob Bradford66bd9f52013-06-25 18:56:42 +01001817 weston_config_section_get_string(section, "seat", &s, "");
1818 setup_output_seat_constraint(ec, &output->base, s);
1819 free(s);
1820
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001821 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001822 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001823 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001824 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001825 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001826
Matt Roper361d2ad2011-08-29 13:52:23 -07001827 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001828 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001829
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001830 /* Get the current mode on the crtc that's currently driving
1831 * this connector. */
1832 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001833 memset(&crtc_mode, 0, sizeof crtc_mode);
1834 if (encoder != NULL) {
1835 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1836 drmModeFreeEncoder(encoder);
1837 if (crtc == NULL)
1838 goto err_free;
1839 if (crtc->mode_valid)
1840 crtc_mode = crtc->mode;
1841 drmModeFreeCrtc(crtc);
1842 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001843
David Herrmann0f0d54e2011-12-08 17:05:45 +01001844 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001845 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001846 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001847 goto err_free;
1848 }
1849
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001850 if (config == OUTPUT_CONFIG_OFF) {
1851 weston_log("Disabling output %s\n", output->base.name);
1852 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1853 0, 0, 0, 0, 0, NULL);
1854 goto err_free;
1855 }
1856
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001857 preferred = NULL;
1858 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001859 configured = NULL;
1860
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001861 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001862 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001863 width == drm_mode->base.width &&
1864 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001865 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001866 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001867 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001868 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001869 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001870 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001871
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001872 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001873 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001874 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001875 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001876 }
1877
Wang Quanxianacb805a2012-07-30 18:09:46 -04001878 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001879 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001880 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001881 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001882 }
1883
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001884 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001885 configured = current;
1886
Wang Quanxianacb805a2012-07-30 18:09:46 -04001887 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001888 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001889 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001890 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001891 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001892 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001893 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001894 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001895
1896 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001897 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001898 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001899 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001900
Wang Quanxianacb805a2012-07-30 18:09:46 -04001901 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1902
John Kåre Alsaker94659272012-11-13 19:10:18 +01001903 weston_output_init(&output->base, &ec->base, x, y,
1904 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001905 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001906
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001907 if (ec->use_pixman) {
1908 if (drm_output_init_pixman(output, ec) < 0) {
1909 weston_log("Failed to init output pixman state\n");
1910 goto err_output;
1911 }
1912 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001913 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001914 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001915 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001916
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001917 output->backlight = backlight_init(drm_device,
1918 connector->connector_type);
1919 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001920 weston_log("Initialized backlight, device %s\n",
1921 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001922 output->base.set_backlight = drm_set_backlight;
1923 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001924 } else {
1925 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001926 }
1927
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001928 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1929
Richard Hughes2b2092a2013-04-24 14:58:02 +01001930 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001931 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1932 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001933
Alex Wubd3354b2012-04-17 17:20:49 +08001934 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001935 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001936 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001937 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001938 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001939 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001940 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001941
Richard Hughese7299962013-05-01 21:52:12 +01001942 output->base.gamma_size = output->original_crtc->gamma_size;
1943 output->base.set_gamma = drm_output_set_gamma;
1944
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001945 weston_plane_init(&output->cursor_plane, 0, 0);
1946 weston_plane_init(&output->fb_plane, 0, 0);
1947
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001948 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1949 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1950 &ec->base.primary_plane);
1951
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001952 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001953 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001954 wl_list_for_each(m, &output->base.mode_list, link)
1955 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1956 m->width, m->height, m->refresh / 1000.0,
1957 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1958 ", preferred" : "",
1959 m->flags & WL_OUTPUT_MODE_CURRENT ?
1960 ", current" : "",
1961 connector->count_modes == 0 ?
1962 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001963
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001964 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001965
John Kåre Alsaker94659272012-11-13 19:10:18 +01001966err_output:
1967 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001968err_free:
1969 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1970 base.link) {
1971 wl_list_remove(&drm_mode->base.link);
1972 free(drm_mode);
1973 }
1974
1975 drmModeFreeCrtc(output->original_crtc);
1976 ec->crtc_allocator &= ~(1 << output->crtc_id);
1977 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001978 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001979
David Herrmann0f0d54e2011-12-08 17:05:45 +01001980 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001981}
1982
Jesse Barnes58ef3792012-02-23 09:45:49 -05001983static void
1984create_sprites(struct drm_compositor *ec)
1985{
1986 struct drm_sprite *sprite;
1987 drmModePlaneRes *plane_res;
1988 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001989 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001990
1991 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1992 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001993 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001994 strerror(errno));
1995 return;
1996 }
1997
1998 for (i = 0; i < plane_res->count_planes; i++) {
1999 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2000 if (!plane)
2001 continue;
2002
Peter Huttererf3d62272013-08-08 11:57:05 +10002003 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002004 plane->count_formats));
2005 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002006 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002007 __func__);
2008 free(plane);
2009 continue;
2010 }
2011
Jesse Barnes58ef3792012-02-23 09:45:49 -05002012 sprite->possible_crtcs = plane->possible_crtcs;
2013 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002014 sprite->current = NULL;
2015 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002016 sprite->compositor = ec;
2017 sprite->count_formats = plane->count_formats;
2018 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002019 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002020 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002021 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002022 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2023 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002024
2025 wl_list_insert(&ec->sprite_list, &sprite->link);
2026 }
2027
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002028 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002029}
2030
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002031static void
2032destroy_sprites(struct drm_compositor *compositor)
2033{
2034 struct drm_sprite *sprite, *next;
2035 struct drm_output *output;
2036
2037 output = container_of(compositor->base.output_list.next,
2038 struct drm_output, base.link);
2039
2040 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2041 drmModeSetPlane(compositor->drm.fd,
2042 sprite->plane_id,
2043 output->crtc_id, 0, 0,
2044 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002045 drm_output_release_fb(output, sprite->current);
2046 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002047 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002048 free(sprite);
2049 }
2050}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002051
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002052static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002053create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002054 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002055{
2056 drmModeConnector *connector;
2057 drmModeRes *resources;
2058 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002059 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002060
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002061 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002062 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002063 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002064 return -1;
2065 }
2066
Jesse Barnes58ef3792012-02-23 09:45:49 -05002067 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002068 if (!ec->crtcs) {
2069 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002070 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002071 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002072
Rob Clark4339add2012-08-09 14:18:28 -05002073 ec->min_width = resources->min_width;
2074 ec->max_width = resources->max_width;
2075 ec->min_height = resources->min_height;
2076 ec->max_height = resources->max_height;
2077
Jesse Barnes58ef3792012-02-23 09:45:49 -05002078 ec->num_crtcs = resources->count_crtcs;
2079 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2080
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002081 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002082 connector = drmModeGetConnector(ec->drm.fd,
2083 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002084 if (connector == NULL)
2085 continue;
2086
2087 if (connector->connection == DRM_MODE_CONNECTED &&
2088 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002089 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002090 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002091 connector, x, y,
2092 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002093 drmModeFreeConnector(connector);
2094 continue;
2095 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002096
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002097 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002098 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002099 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002100 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002101
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002102 drmModeFreeConnector(connector);
2103 }
2104
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002105 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002106 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002107 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002108 return -1;
2109 }
2110
2111 drmModeFreeResources(resources);
2112
2113 return 0;
2114}
2115
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002116static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002117update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002118{
2119 drmModeConnector *connector;
2120 drmModeRes *resources;
2121 struct drm_output *output, *next;
2122 int x = 0, y = 0;
2123 int x_offset = 0, y_offset = 0;
2124 uint32_t connected = 0, disconnects = 0;
2125 int i;
2126
2127 resources = drmModeGetResources(ec->drm.fd);
2128 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002129 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002130 return;
2131 }
2132
2133 /* collect new connects */
2134 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002135 int connector_id = resources->connectors[i];
2136
2137 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002138 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002139 continue;
2140
David Herrmann7551cff2011-12-08 17:05:43 +01002141 if (connector->connection != DRM_MODE_CONNECTED) {
2142 drmModeFreeConnector(connector);
2143 continue;
2144 }
2145
Benjamin Franzke117483d2011-08-30 11:38:26 +02002146 connected |= (1 << connector_id);
2147
2148 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002149 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002150 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002151 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002152
2153 /* XXX: not yet needed, we die with 0 outputs */
2154 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002155 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002156 else
2157 x = 0;
2158 y = 0;
2159 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002160 connector, x, y,
2161 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002162 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002163
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002164 }
2165 drmModeFreeConnector(connector);
2166 }
2167 drmModeFreeResources(resources);
2168
2169 disconnects = ec->connector_allocator & ~connected;
2170 if (disconnects) {
2171 wl_list_for_each_safe(output, next, &ec->base.output_list,
2172 base.link) {
2173 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002174 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002175 output->base.x - x_offset,
2176 output->base.y - y_offset);
2177 }
2178
2179 if (disconnects & (1 << output->connector_id)) {
2180 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002181 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002182 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002183 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002184 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002185 }
2186 }
2187 }
2188
2189 /* FIXME: handle zero outputs, without terminating */
2190 if (ec->connector_allocator == 0)
2191 wl_display_terminate(ec->base.wl_display);
2192}
2193
2194static int
David Herrmannd7488c22012-03-11 20:05:21 +01002195udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002196{
David Herrmannd7488c22012-03-11 20:05:21 +01002197 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002198 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002199
2200 sysnum = udev_device_get_sysnum(device);
2201 if (!sysnum || atoi(sysnum) != ec->drm.id)
2202 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002203
David Herrmann6ac52db2012-03-11 20:05:22 +01002204 val = udev_device_get_property_value(device, "HOTPLUG");
2205 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002206 return 0;
2207
David Herrmann6ac52db2012-03-11 20:05:22 +01002208 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002209}
2210
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002211static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002212udev_drm_event(int fd, uint32_t mask, void *data)
2213{
2214 struct drm_compositor *ec = data;
2215 struct udev_device *event;
2216
2217 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002218
David Herrmannd7488c22012-03-11 20:05:21 +01002219 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002220 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002221
2222 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002223
2224 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002225}
2226
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002227static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002228drm_restore(struct weston_compositor *ec)
2229{
2230 struct drm_compositor *d = (struct drm_compositor *) ec;
2231
2232 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2233 weston_log("failed to drop master: %m\n");
2234 tty_reset(d->tty);
2235}
2236
2237static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002238drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002239{
2240 struct drm_compositor *d = (struct drm_compositor *) ec;
2241
Rob Bradfordd355b802013-05-31 18:09:55 +01002242 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002243
2244 wl_event_source_remove(d->udev_drm_source);
2245 wl_event_source_remove(d->drm_source);
2246
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002247 destroy_sprites(d);
2248
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002249 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002250
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002251 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002252
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002253 if (d->gbm)
2254 gbm_device_destroy(d->gbm);
2255
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002256 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002257 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002258 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002259
Rob Bradford45c15b82013-07-26 16:29:35 +01002260 close(d->drm.fd);
2261
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002262 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002263}
2264
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002265static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002266drm_compositor_set_modes(struct drm_compositor *compositor)
2267{
2268 struct drm_output *output;
2269 struct drm_mode *drm_mode;
2270 int ret;
2271
2272 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002273 if (!output->current) {
2274 /* If something that would cause the output to
2275 * switch mode happened while in another vt, we
2276 * might not have a current drm_fb. In that case,
2277 * schedule a repaint and let drm_output_repaint
2278 * handle setting the mode. */
2279 weston_output_schedule_repaint(&output->base);
2280 continue;
2281 }
2282
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002283 drm_mode = (struct drm_mode *) output->base.current;
2284 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002285 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002286 &output->connector_id, 1,
2287 &drm_mode->mode_info);
2288 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002289 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002290 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002291 drm_mode->base.width, drm_mode->base.height,
2292 output->base.x, output->base.y);
2293 }
2294 }
2295}
2296
2297static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002298vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002299{
2300 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002301 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002302 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002303
2304 switch (event) {
2305 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002306 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002307 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002308 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002309 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002310 wl_display_terminate(compositor->wl_display);
2311 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002312 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002313 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002314 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002315 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002316 break;
2317 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002318 weston_log("leaving VT\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002319 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002320
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002321 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002322 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002323 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002324
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002325 /* If we have a repaint scheduled (either from a
2326 * pending pageflip or the idle handler), make sure we
2327 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002328 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002329 * further attemps at repainting. When we switch
2330 * back, we schedule a repaint, which will process
2331 * pending frame callbacks. */
2332
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002333 wl_list_for_each(output, &ec->base.output_list, base.link) {
2334 output->base.repaint_needed = 0;
2335 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002336 }
2337
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002338 output = container_of(ec->base.output_list.next,
2339 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002340
2341 wl_list_for_each(sprite, &ec->sprite_list, link)
2342 drmModeSetPlane(ec->drm.fd,
2343 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002344 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002345 0, 0, 0, 0, 0, 0, 0, 0);
2346
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002347 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002348 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002349
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002350 break;
2351 };
2352}
2353
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002354static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002355switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002356{
2357 struct drm_compositor *ec = data;
2358
Daniel Stone325fc2d2012-05-30 16:31:58 +01002359 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002360}
2361
David Herrmann0af066f2012-10-29 19:21:16 +01002362/*
2363 * Find primary GPU
2364 * Some systems may have multiple DRM devices attached to a single seat. This
2365 * function loops over all devices and tries to find a PCI device with the
2366 * boot_vga sysfs attribute set to 1.
2367 * If no such device is found, the first DRM device reported by udev is used.
2368 */
2369static struct udev_device*
2370find_primary_gpu(struct drm_compositor *ec, const char *seat)
2371{
2372 struct udev_enumerate *e;
2373 struct udev_list_entry *entry;
2374 const char *path, *device_seat, *id;
2375 struct udev_device *device, *drm_device, *pci;
2376
2377 e = udev_enumerate_new(ec->udev);
2378 udev_enumerate_add_match_subsystem(e, "drm");
2379 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2380
2381 udev_enumerate_scan_devices(e);
2382 drm_device = NULL;
2383 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2384 path = udev_list_entry_get_name(entry);
2385 device = udev_device_new_from_syspath(ec->udev, path);
2386 if (!device)
2387 continue;
2388 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2389 if (!device_seat)
2390 device_seat = default_seat;
2391 if (strcmp(device_seat, seat)) {
2392 udev_device_unref(device);
2393 continue;
2394 }
2395
2396 pci = udev_device_get_parent_with_subsystem_devtype(device,
2397 "pci", NULL);
2398 if (pci) {
2399 id = udev_device_get_sysattr_value(pci, "boot_vga");
2400 if (id && !strcmp(id, "1")) {
2401 if (drm_device)
2402 udev_device_unref(drm_device);
2403 drm_device = device;
2404 break;
2405 }
2406 }
2407
2408 if (!drm_device)
2409 drm_device = device;
2410 else
2411 udev_device_unref(device);
2412 }
2413
2414 udev_enumerate_unref(e);
2415 return drm_device;
2416}
2417
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002418static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002419planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002420{
2421 struct drm_compositor *c = data;
2422
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002423 switch (key) {
2424 case KEY_C:
2425 c->cursors_are_broken ^= 1;
2426 break;
2427 case KEY_V:
2428 c->sprites_are_broken ^= 1;
2429 break;
2430 case KEY_O:
2431 c->sprites_hidden ^= 1;
2432 break;
2433 default:
2434 break;
2435 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002436}
2437
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002438static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002439drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002440 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002441 int *argc, char *argv[],
2442 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002443{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002444 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002445 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002446 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002447 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002448 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002449
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002450 weston_log("initializing drm backend\n");
2451
Peter Huttererf3d62272013-08-08 11:57:05 +10002452 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002453 if (ec == NULL)
2454 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002455
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002456 /* KMS support for sprites is not complete yet, so disable the
2457 * functionality for now. */
2458 ec->sprites_are_broken = 1;
2459
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002460 ec->use_pixman = pixman;
2461
Daniel Stone725c2c32012-06-22 14:04:36 +01002462 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002463 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002464 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002465 goto err_base;
2466 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002467
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002468 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg3c95e702013-07-23 12:24:00 -07002469 ec->base.launcher_sock =
2470 weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002471 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002472 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002473 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002474 goto err_compositor;
2475 }
2476
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002477 ec->udev = udev_new();
2478 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002479 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002480 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002481 }
2482
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002483 ec->base.wl_display = display;
2484 ec->tty = tty_create(&ec->base, vt_func, tty);
2485 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002486 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002487 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002488 }
2489
Rob Bradford643641d2013-05-31 18:09:53 +01002490 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002491 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002492 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002493 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002494 }
David Herrmann0af066f2012-10-29 19:21:16 +01002495 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002496
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002497 if (init_drm(ec, drm_device) < 0) {
2498 weston_log("failed to initialize kms\n");
2499 goto err_udev_dev;
2500 }
2501
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002502 if (ec->use_pixman) {
2503 if (init_pixman(ec) < 0) {
2504 weston_log("failed to initialize pixman renderer\n");
2505 goto err_udev_dev;
2506 }
2507 } else {
2508 if (init_egl(ec) < 0) {
2509 weston_log("failed to initialize egl\n");
2510 goto err_udev_dev;
2511 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002512 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002513
2514 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002515 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002516
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002517 ec->base.focus = 1;
2518
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002519 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002520
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002521 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002522 weston_compositor_add_key_binding(&ec->base, key,
2523 MODIFIER_CTRL | MODIFIER_ALT,
2524 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002525
Jesse Barnes58ef3792012-02-23 09:45:49 -05002526 wl_list_init(&ec->sprite_list);
2527 create_sprites(ec);
2528
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002529 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002530 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002531 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002532 }
2533
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002534 path = NULL;
2535
Rob Bradfordd355b802013-05-31 18:09:55 +01002536 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002537 weston_log("failed to create input devices\n");
2538 goto err_sprite;
2539 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002540
2541 loop = wl_display_get_event_loop(ec->base.wl_display);
2542 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002543 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002544 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002545
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002546 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2547 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002548 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002549 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002550 }
2551 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2552 "drm", NULL);
2553 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002554 wl_event_loop_add_fd(loop,
2555 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002556 WL_EVENT_READABLE, udev_drm_event, ec);
2557
2558 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002559 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002560 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002561 }
2562
Daniel Stonea96b93c2012-06-22 14:04:37 +01002563 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002564
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002565 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002566 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002567 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002568 planes_binding, ec);
2569 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2570 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002571
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002572 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002573
2574err_udev_monitor:
2575 wl_event_source_remove(ec->udev_drm_source);
2576 udev_monitor_unref(ec->udev_monitor);
2577err_drm_source:
2578 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002579 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002580err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002581 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002582 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002583 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002584err_udev_dev:
2585 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002586err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002587 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2588 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002589 tty_destroy(ec->tty);
2590err_udev:
2591 udev_unref(ec->udev);
2592err_compositor:
2593 weston_compositor_shutdown(&ec->base);
2594err_base:
2595 free(ec);
2596 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002597}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002598
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002599WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002600backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002601 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002602{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002603 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002604 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002605
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002606 const struct weston_option drm_options[] = {
2607 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002608 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002609 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002610 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002611 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002612 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002613
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002614 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002615
Rob Bradford643641d2013-05-31 18:09:53 +01002616 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002617 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002618}