blob: 45e7e9b0721686b135a37b2f435e22d21c8642ea [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 Hughesb24e48e2013-05-09 20:31:09 +010028#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010029#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040030#include <string.h>
31#include <fcntl.h>
32#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040033#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030036#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040037
Benjamin Franzkec649a922011-03-02 11:56:04 +010038#include <xf86drm.h>
39#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050040#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010041
Benjamin Franzke060cf802011-04-30 09:32:11 +020042#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020043#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040044#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020045
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040046#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010047#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020048#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050049#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010050#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040051
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030052#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
53#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
54#endif
55
Kristian Høgsberg061c4252012-06-28 11:28:15 -040056static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060057
58enum output_config {
59 OUTPUT_CONFIG_INVALID = 0,
60 OUTPUT_CONFIG_OFF,
61 OUTPUT_CONFIG_PREFERRED,
62 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060063 OUTPUT_CONFIG_MODE,
64 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060065};
66
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040067struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050068 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069
70 struct udev *udev;
71 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040072
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010073 struct udev_monitor *udev_monitor;
74 struct wl_event_source *udev_drm_source;
75
Benjamin Franzke2af7f102011-03-02 11:14:59 +010076 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010077 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 int fd;
79 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020080 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050081 uint32_t *crtcs;
82 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050083 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010084 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050085 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020086
Rob Clark4339add2012-08-09 14:18:28 -050087 /* we need these parameters in order to not fail drmModeAddFB2()
88 * due to out of bounds dimensions, and then mistakenly set
89 * sprites_are_broken:
90 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020091 uint32_t min_width, max_width;
92 uint32_t min_height, max_height;
93 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050094
Jesse Barnes58ef3792012-02-23 09:45:49 -050095 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050096 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +020097 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -050098
Rob Clarkab5b1e32012-08-09 13:24:45 -050099 int cursors_are_broken;
100
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200101 int use_pixman;
102
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200103 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300104
105 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100106 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400107};
108
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500110 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400111 drmModeModeInfo mode_info;
112};
113
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300114struct drm_output;
115
116struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300117 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200118 uint32_t fb_id, stride, handle, size;
119 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300120 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200121 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200122
123 /* Used by gbm fbs */
124 struct gbm_bo *bo;
125
126 /* Used by dumb fbs */
127 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300128};
129
Richard Hughes2b2092a2013-04-24 14:58:02 +0100130struct drm_edid {
131 char eisa_id[13];
132 char monitor_name[13];
133 char pnp_id[5];
134 char serial_number[13];
135};
136
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400137struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500138 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400139
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400140 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500141 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400142 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700143 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100144 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300145 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200146
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300147 int vblank_pending;
148 int page_flip_pending;
149
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400150 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400151 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400152 struct weston_plane cursor_plane;
153 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400154 struct weston_surface *cursor_surface;
155 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300156 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200157 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200158
159 struct drm_fb *dumb[2];
160 pixman_image_t *image[2];
161 int current_image;
162 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400163};
164
Jesse Barnes58ef3792012-02-23 09:45:49 -0500165/*
166 * An output has a primary display plane plus zero or more sprites for
167 * blending display contents.
168 */
169struct drm_sprite {
170 struct wl_list link;
171
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400172 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500173
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200174 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300175 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500176 struct drm_compositor *compositor;
177
Jesse Barnes58ef3792012-02-23 09:45:49 -0500178 uint32_t possible_crtcs;
179 uint32_t plane_id;
180 uint32_t count_formats;
181
182 int32_t src_x, src_y;
183 uint32_t src_w, src_h;
184 uint32_t dest_x, dest_y;
185 uint32_t dest_w, dest_h;
186
187 uint32_t formats[];
188};
189
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500190static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400191
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400192static void
193drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400194
Jesse Barnes58ef3792012-02-23 09:45:49 -0500195static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500196drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
197{
198 struct weston_compositor *ec = output_base->compositor;
199 struct drm_compositor *c =(struct drm_compositor *) ec;
200 struct drm_output *output = (struct drm_output *) output_base;
201 int crtc;
202
203 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
204 if (c->crtcs[crtc] != output->crtc_id)
205 continue;
206
207 if (supported & (1 << crtc))
208 return -1;
209 }
210
211 return 0;
212}
213
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300214static void
215drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
216{
217 struct drm_fb *fb = data;
218 struct gbm_device *gbm = gbm_bo_get_device(bo);
219
220 if (fb->fb_id)
221 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
222
Pekka Paalanende685b82012-12-04 15:58:12 +0200223 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300224
225 free(data);
226}
227
228static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200229drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
230{
231 struct drm_fb *fb;
232 int ret;
233
234 struct drm_mode_create_dumb create_arg;
235 struct drm_mode_destroy_dumb destroy_arg;
236 struct drm_mode_map_dumb map_arg;
237
238 fb = calloc(1, sizeof *fb);
239 if (!fb)
240 return NULL;
241
242 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
260 memset(&map_arg, 0, sizeof(map_arg));
261 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
1676 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
1677 &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
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001775 output = malloc(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øgsbergce5325d2010-06-14 11:54:00 -04001779 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001780 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1781 output->base.make = "unknown";
1782 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001783 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001784 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001785
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001786 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1787 type_name = connector_type_names[connector->connector_type];
1788 else
1789 type_name = "UNKNOWN";
1790 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001791 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001792
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001793 section = weston_config_get_section(ec->base.config, "output", "name",
1794 output->base.name);
1795 weston_config_section_get_string(section, "mode", &s, "preferred");
1796 if (strcmp(s, "off") == 0)
1797 config = OUTPUT_CONFIG_OFF;
1798 else if (strcmp(s, "preferred") == 0)
1799 config = OUTPUT_CONFIG_PREFERRED;
1800 else if (strcmp(s, "current") == 0)
1801 config = OUTPUT_CONFIG_CURRENT;
1802 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1803 config = OUTPUT_CONFIG_MODE;
1804 else if (parse_modeline(s, &modeline) == 0)
1805 config = OUTPUT_CONFIG_MODELINE;
1806 else {
1807 weston_log("Invalid mode \"%s\" for output %s\n",
1808 s, output->base.name);
1809 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001810 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001811 free(s);
1812
1813 weston_config_section_get_int(section, "scale", &scale, 1);
1814 weston_config_section_get_string(section, "transform", &s, "normal");
1815 transform = parse_transform(s, output->base.name);
1816 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001817
Rob Bradford66bd9f52013-06-25 18:56:42 +01001818 weston_config_section_get_string(section, "seat", &s, "");
1819 setup_output_seat_constraint(ec, &output->base, s);
1820 free(s);
1821
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001822 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001823 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001824 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001825 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001826 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001827
Matt Roper361d2ad2011-08-29 13:52:23 -07001828 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001829 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001830
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001831 /* Get the current mode on the crtc that's currently driving
1832 * this connector. */
1833 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001834 memset(&crtc_mode, 0, sizeof crtc_mode);
1835 if (encoder != NULL) {
1836 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1837 drmModeFreeEncoder(encoder);
1838 if (crtc == NULL)
1839 goto err_free;
1840 if (crtc->mode_valid)
1841 crtc_mode = crtc->mode;
1842 drmModeFreeCrtc(crtc);
1843 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001844
David Herrmann0f0d54e2011-12-08 17:05:45 +01001845 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001846 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001847 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001848 goto err_free;
1849 }
1850
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001851 if (config == OUTPUT_CONFIG_OFF) {
1852 weston_log("Disabling output %s\n", output->base.name);
1853 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1854 0, 0, 0, 0, 0, NULL);
1855 goto err_free;
1856 }
1857
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001858 preferred = NULL;
1859 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001860 configured = NULL;
1861
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001862 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001863 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001864 width == drm_mode->base.width &&
1865 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001866 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001867 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001868 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001869 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001870 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001871 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001872
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001873 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001874 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001875 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001876 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001877 }
1878
Wang Quanxianacb805a2012-07-30 18:09:46 -04001879 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001880 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001881 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001882 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001883 }
1884
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001885 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001886 configured = current;
1887
Wang Quanxianacb805a2012-07-30 18:09:46 -04001888 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001889 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001890 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001891 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001892 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001893 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001894 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001895 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001896
1897 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001898 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001899 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001900 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001901
Wang Quanxianacb805a2012-07-30 18:09:46 -04001902 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1903
John Kåre Alsaker94659272012-11-13 19:10:18 +01001904 weston_output_init(&output->base, &ec->base, x, y,
1905 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001906 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001907
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001908 if (ec->use_pixman) {
1909 if (drm_output_init_pixman(output, ec) < 0) {
1910 weston_log("Failed to init output pixman state\n");
1911 goto err_output;
1912 }
1913 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001914 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001915 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001916 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001917
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001918 output->backlight = backlight_init(drm_device,
1919 connector->connector_type);
1920 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001921 weston_log("Initialized backlight, device %s\n",
1922 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001923 output->base.set_backlight = drm_set_backlight;
1924 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001925 } else {
1926 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001927 }
1928
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001929 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1930
Richard Hughes2b2092a2013-04-24 14:58:02 +01001931 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001932 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1933 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001934
Alex Wubd3354b2012-04-17 17:20:49 +08001935 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001936 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001937 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001938 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001939 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001940 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001941 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001942
Richard Hughese7299962013-05-01 21:52:12 +01001943 output->base.gamma_size = output->original_crtc->gamma_size;
1944 output->base.set_gamma = drm_output_set_gamma;
1945
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001946 weston_plane_init(&output->cursor_plane, 0, 0);
1947 weston_plane_init(&output->fb_plane, 0, 0);
1948
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001949 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1950 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1951 &ec->base.primary_plane);
1952
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001953 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001954 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001955 wl_list_for_each(m, &output->base.mode_list, link)
1956 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1957 m->width, m->height, m->refresh / 1000.0,
1958 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1959 ", preferred" : "",
1960 m->flags & WL_OUTPUT_MODE_CURRENT ?
1961 ", current" : "",
1962 connector->count_modes == 0 ?
1963 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001964
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001965 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001966
John Kåre Alsaker94659272012-11-13 19:10:18 +01001967err_output:
1968 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001969err_free:
1970 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1971 base.link) {
1972 wl_list_remove(&drm_mode->base.link);
1973 free(drm_mode);
1974 }
1975
1976 drmModeFreeCrtc(output->original_crtc);
1977 ec->crtc_allocator &= ~(1 << output->crtc_id);
1978 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001979 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001980
David Herrmann0f0d54e2011-12-08 17:05:45 +01001981 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001982}
1983
Jesse Barnes58ef3792012-02-23 09:45:49 -05001984static void
1985create_sprites(struct drm_compositor *ec)
1986{
1987 struct drm_sprite *sprite;
1988 drmModePlaneRes *plane_res;
1989 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001990 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001991
1992 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1993 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001994 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001995 strerror(errno));
1996 return;
1997 }
1998
1999 for (i = 0; i < plane_res->count_planes; i++) {
2000 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2001 if (!plane)
2002 continue;
2003
2004 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
2005 plane->count_formats));
2006 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002007 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002008 __func__);
2009 free(plane);
2010 continue;
2011 }
2012
2013 memset(sprite, 0, sizeof *sprite);
2014
2015 sprite->possible_crtcs = plane->possible_crtcs;
2016 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002017 sprite->current = NULL;
2018 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002019 sprite->compositor = ec;
2020 sprite->count_formats = plane->count_formats;
2021 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002022 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002023 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002024 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002025 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2026 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002027
2028 wl_list_insert(&ec->sprite_list, &sprite->link);
2029 }
2030
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002031 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002032}
2033
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002034static void
2035destroy_sprites(struct drm_compositor *compositor)
2036{
2037 struct drm_sprite *sprite, *next;
2038 struct drm_output *output;
2039
2040 output = container_of(compositor->base.output_list.next,
2041 struct drm_output, base.link);
2042
2043 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2044 drmModeSetPlane(compositor->drm.fd,
2045 sprite->plane_id,
2046 output->crtc_id, 0, 0,
2047 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002048 drm_output_release_fb(output, sprite->current);
2049 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002050 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002051 free(sprite);
2052 }
2053}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002054
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002055static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002056create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002057 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002058{
2059 drmModeConnector *connector;
2060 drmModeRes *resources;
2061 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002062 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002063
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002064 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002065 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002066 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002067 return -1;
2068 }
2069
Jesse Barnes58ef3792012-02-23 09:45:49 -05002070 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002071 if (!ec->crtcs) {
2072 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002073 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002074 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002075
Rob Clark4339add2012-08-09 14:18:28 -05002076 ec->min_width = resources->min_width;
2077 ec->max_width = resources->max_width;
2078 ec->min_height = resources->min_height;
2079 ec->max_height = resources->max_height;
2080
Jesse Barnes58ef3792012-02-23 09:45:49 -05002081 ec->num_crtcs = resources->count_crtcs;
2082 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2083
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002084 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002085 connector = drmModeGetConnector(ec->drm.fd,
2086 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002087 if (connector == NULL)
2088 continue;
2089
2090 if (connector->connection == DRM_MODE_CONNECTED &&
2091 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002092 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002093 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002094 connector, x, y,
2095 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002096 drmModeFreeConnector(connector);
2097 continue;
2098 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002099
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002100 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002101 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002102 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002103 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002104
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002105 drmModeFreeConnector(connector);
2106 }
2107
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002108 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002109 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002110 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002111 return -1;
2112 }
2113
2114 drmModeFreeResources(resources);
2115
2116 return 0;
2117}
2118
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002119static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002120update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002121{
2122 drmModeConnector *connector;
2123 drmModeRes *resources;
2124 struct drm_output *output, *next;
2125 int x = 0, y = 0;
2126 int x_offset = 0, y_offset = 0;
2127 uint32_t connected = 0, disconnects = 0;
2128 int i;
2129
2130 resources = drmModeGetResources(ec->drm.fd);
2131 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002132 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002133 return;
2134 }
2135
2136 /* collect new connects */
2137 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002138 int connector_id = resources->connectors[i];
2139
2140 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002141 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002142 continue;
2143
David Herrmann7551cff2011-12-08 17:05:43 +01002144 if (connector->connection != DRM_MODE_CONNECTED) {
2145 drmModeFreeConnector(connector);
2146 continue;
2147 }
2148
Benjamin Franzke117483d2011-08-30 11:38:26 +02002149 connected |= (1 << connector_id);
2150
2151 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002152 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002153 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002154 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002155
2156 /* XXX: not yet needed, we die with 0 outputs */
2157 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002158 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002159 else
2160 x = 0;
2161 y = 0;
2162 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002163 connector, x, y,
2164 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002165 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002166
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002167 }
2168 drmModeFreeConnector(connector);
2169 }
2170 drmModeFreeResources(resources);
2171
2172 disconnects = ec->connector_allocator & ~connected;
2173 if (disconnects) {
2174 wl_list_for_each_safe(output, next, &ec->base.output_list,
2175 base.link) {
2176 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002177 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002178 output->base.x - x_offset,
2179 output->base.y - y_offset);
2180 }
2181
2182 if (disconnects & (1 << output->connector_id)) {
2183 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002184 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002185 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002186 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002187 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002188 }
2189 }
2190 }
2191
2192 /* FIXME: handle zero outputs, without terminating */
2193 if (ec->connector_allocator == 0)
2194 wl_display_terminate(ec->base.wl_display);
2195}
2196
2197static int
David Herrmannd7488c22012-03-11 20:05:21 +01002198udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002199{
David Herrmannd7488c22012-03-11 20:05:21 +01002200 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002201 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002202
2203 sysnum = udev_device_get_sysnum(device);
2204 if (!sysnum || atoi(sysnum) != ec->drm.id)
2205 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002206
David Herrmann6ac52db2012-03-11 20:05:22 +01002207 val = udev_device_get_property_value(device, "HOTPLUG");
2208 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002209 return 0;
2210
David Herrmann6ac52db2012-03-11 20:05:22 +01002211 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002212}
2213
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002214static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002215udev_drm_event(int fd, uint32_t mask, void *data)
2216{
2217 struct drm_compositor *ec = data;
2218 struct udev_device *event;
2219
2220 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002221
David Herrmannd7488c22012-03-11 20:05:21 +01002222 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002223 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002224
2225 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002226
2227 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002228}
2229
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002230static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002231drm_restore(struct weston_compositor *ec)
2232{
2233 struct drm_compositor *d = (struct drm_compositor *) ec;
2234
2235 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2236 weston_log("failed to drop master: %m\n");
2237 tty_reset(d->tty);
2238}
2239
2240static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002241drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002242{
2243 struct drm_compositor *d = (struct drm_compositor *) ec;
2244
Rob Bradfordd355b802013-05-31 18:09:55 +01002245 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002246
2247 wl_event_source_remove(d->udev_drm_source);
2248 wl_event_source_remove(d->drm_source);
2249
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002250 destroy_sprites(d);
2251
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002252 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002253
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002254 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002255
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002256 if (d->gbm)
2257 gbm_device_destroy(d->gbm);
2258
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002259 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002260 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002261 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002262
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002263 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002264}
2265
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002266static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002267drm_compositor_set_modes(struct drm_compositor *compositor)
2268{
2269 struct drm_output *output;
2270 struct drm_mode *drm_mode;
2271 int ret;
2272
2273 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002274 if (!output->current) {
2275 /* If something that would cause the output to
2276 * switch mode happened while in another vt, we
2277 * might not have a current drm_fb. In that case,
2278 * schedule a repaint and let drm_output_repaint
2279 * handle setting the mode. */
2280 weston_output_schedule_repaint(&output->base);
2281 continue;
2282 }
2283
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002284 drm_mode = (struct drm_mode *) output->base.current;
2285 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002286 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002287 &output->connector_id, 1,
2288 &drm_mode->mode_info);
2289 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002290 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002291 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002292 drm_mode->base.width, drm_mode->base.height,
2293 output->base.x, output->base.y);
2294 }
2295 }
2296}
2297
2298static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002299vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002300{
2301 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002302 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002303 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002304
2305 switch (event) {
2306 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002307 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002308 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002309 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002310 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002311 wl_display_terminate(compositor->wl_display);
2312 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002313 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002314 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002315 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002316 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002317 break;
2318 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002319 weston_log("leaving VT\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002320 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002321
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002322 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002323 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002324 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002325
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002326 /* If we have a repaint scheduled (either from a
2327 * pending pageflip or the idle handler), make sure we
2328 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002329 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002330 * further attemps at repainting. When we switch
2331 * back, we schedule a repaint, which will process
2332 * pending frame callbacks. */
2333
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002334 wl_list_for_each(output, &ec->base.output_list, base.link) {
2335 output->base.repaint_needed = 0;
2336 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002337 }
2338
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002339 output = container_of(ec->base.output_list.next,
2340 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002341
2342 wl_list_for_each(sprite, &ec->sprite_list, link)
2343 drmModeSetPlane(ec->drm.fd,
2344 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002345 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002346 0, 0, 0, 0, 0, 0, 0, 0);
2347
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002348 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002349 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002350
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002351 break;
2352 };
2353}
2354
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002355static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002356switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002357{
2358 struct drm_compositor *ec = data;
2359
Daniel Stone325fc2d2012-05-30 16:31:58 +01002360 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002361}
2362
David Herrmann0af066f2012-10-29 19:21:16 +01002363/*
2364 * Find primary GPU
2365 * Some systems may have multiple DRM devices attached to a single seat. This
2366 * function loops over all devices and tries to find a PCI device with the
2367 * boot_vga sysfs attribute set to 1.
2368 * If no such device is found, the first DRM device reported by udev is used.
2369 */
2370static struct udev_device*
2371find_primary_gpu(struct drm_compositor *ec, const char *seat)
2372{
2373 struct udev_enumerate *e;
2374 struct udev_list_entry *entry;
2375 const char *path, *device_seat, *id;
2376 struct udev_device *device, *drm_device, *pci;
2377
2378 e = udev_enumerate_new(ec->udev);
2379 udev_enumerate_add_match_subsystem(e, "drm");
2380 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2381
2382 udev_enumerate_scan_devices(e);
2383 drm_device = NULL;
2384 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2385 path = udev_list_entry_get_name(entry);
2386 device = udev_device_new_from_syspath(ec->udev, path);
2387 if (!device)
2388 continue;
2389 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2390 if (!device_seat)
2391 device_seat = default_seat;
2392 if (strcmp(device_seat, seat)) {
2393 udev_device_unref(device);
2394 continue;
2395 }
2396
2397 pci = udev_device_get_parent_with_subsystem_devtype(device,
2398 "pci", NULL);
2399 if (pci) {
2400 id = udev_device_get_sysattr_value(pci, "boot_vga");
2401 if (id && !strcmp(id, "1")) {
2402 if (drm_device)
2403 udev_device_unref(drm_device);
2404 drm_device = device;
2405 break;
2406 }
2407 }
2408
2409 if (!drm_device)
2410 drm_device = device;
2411 else
2412 udev_device_unref(device);
2413 }
2414
2415 udev_enumerate_unref(e);
2416 return drm_device;
2417}
2418
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002419static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002420planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002421{
2422 struct drm_compositor *c = data;
2423
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002424 switch (key) {
2425 case KEY_C:
2426 c->cursors_are_broken ^= 1;
2427 break;
2428 case KEY_V:
2429 c->sprites_are_broken ^= 1;
2430 break;
2431 case KEY_O:
2432 c->sprites_hidden ^= 1;
2433 break;
2434 default:
2435 break;
2436 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002437}
2438
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002439static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002440drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002441 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002442 int *argc, char *argv[],
2443 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002444{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002445 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002446 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002447 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002448 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002449 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002450
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002451 weston_log("initializing drm backend\n");
2452
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002453 ec = malloc(sizeof *ec);
2454 if (ec == NULL)
2455 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002456 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002457
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002458 /* KMS support for sprites is not complete yet, so disable the
2459 * functionality for now. */
2460 ec->sprites_are_broken = 1;
2461
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002462 ec->use_pixman = pixman;
2463
Daniel Stone725c2c32012-06-22 14:04:36 +01002464 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002465 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002466 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002467 goto err_base;
2468 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002469
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002470 /* Check if we run drm-backend using weston-launch */
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}