blob: e704c9f253758ed9d1b4219ecc8069a326112175 [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
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001731static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001732create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001733 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001734 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001735 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001736{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001737 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001738 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1739 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001740 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001741 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001742 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001743 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001744 int i, width, height, scale;
1745 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001746 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001747 enum output_config config;
1748 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001749
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001750 i = find_crtc_for_connector(ec, resources, connector);
1751 if (i < 0) {
1752 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001753 return -1;
1754 }
1755
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001756 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001757 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001758 return -1;
1759
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001760 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001761 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1762 output->base.make = "unknown";
1763 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001764 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001765 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001766
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001767 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1768 type_name = connector_type_names[connector->connector_type];
1769 else
1770 type_name = "UNKNOWN";
1771 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001772 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001773
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001774 section = weston_config_get_section(ec->base.config, "output", "name",
1775 output->base.name);
1776 weston_config_section_get_string(section, "mode", &s, "preferred");
1777 if (strcmp(s, "off") == 0)
1778 config = OUTPUT_CONFIG_OFF;
1779 else if (strcmp(s, "preferred") == 0)
1780 config = OUTPUT_CONFIG_PREFERRED;
1781 else if (strcmp(s, "current") == 0)
1782 config = OUTPUT_CONFIG_CURRENT;
1783 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1784 config = OUTPUT_CONFIG_MODE;
1785 else if (parse_modeline(s, &modeline) == 0)
1786 config = OUTPUT_CONFIG_MODELINE;
1787 else {
1788 weston_log("Invalid mode \"%s\" for output %s\n",
1789 s, output->base.name);
1790 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001791 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001792 free(s);
1793
1794 weston_config_section_get_int(section, "scale", &scale, 1);
1795 weston_config_section_get_string(section, "transform", &s, "normal");
1796 transform = parse_transform(s, output->base.name);
1797 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001798
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001799 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001800 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001801 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001802 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001803 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001804
Matt Roper361d2ad2011-08-29 13:52:23 -07001805 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001806 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001807
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001808 /* Get the current mode on the crtc that's currently driving
1809 * this connector. */
1810 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001811 memset(&crtc_mode, 0, sizeof crtc_mode);
1812 if (encoder != NULL) {
1813 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1814 drmModeFreeEncoder(encoder);
1815 if (crtc == NULL)
1816 goto err_free;
1817 if (crtc->mode_valid)
1818 crtc_mode = crtc->mode;
1819 drmModeFreeCrtc(crtc);
1820 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001821
David Herrmann0f0d54e2011-12-08 17:05:45 +01001822 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001823 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001824 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001825 goto err_free;
1826 }
1827
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001828 if (config == OUTPUT_CONFIG_OFF) {
1829 weston_log("Disabling output %s\n", output->base.name);
1830 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1831 0, 0, 0, 0, 0, NULL);
1832 goto err_free;
1833 }
1834
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001835 preferred = NULL;
1836 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001837 configured = NULL;
1838
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001839 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001840 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001841 width == drm_mode->base.width &&
1842 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001843 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001844 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001845 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001846 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001847 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001848 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001849
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001850 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001851 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001852 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001853 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001854 }
1855
Wang Quanxianacb805a2012-07-30 18:09:46 -04001856 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001857 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001858 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001859 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001860 }
1861
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001862 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001863 configured = current;
1864
Wang Quanxianacb805a2012-07-30 18:09:46 -04001865 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001866 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001867 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001868 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001869 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001870 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001871 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001872 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001873
1874 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001875 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001876 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001877 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001878
Wang Quanxianacb805a2012-07-30 18:09:46 -04001879 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1880
John Kåre Alsaker94659272012-11-13 19:10:18 +01001881 weston_output_init(&output->base, &ec->base, x, y,
1882 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001883 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001884
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001885 if (ec->use_pixman) {
1886 if (drm_output_init_pixman(output, ec) < 0) {
1887 weston_log("Failed to init output pixman state\n");
1888 goto err_output;
1889 }
1890 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001891 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001892 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001893 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001894
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001895 output->backlight = backlight_init(drm_device,
1896 connector->connector_type);
1897 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001898 weston_log("Initialized backlight, device %s\n",
1899 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001900 output->base.set_backlight = drm_set_backlight;
1901 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001902 } else {
1903 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001904 }
1905
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001906 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1907
Richard Hughes2b2092a2013-04-24 14:58:02 +01001908 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001909 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1910 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001911
Alex Wubd3354b2012-04-17 17:20:49 +08001912 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001913 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001914 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001915 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001916 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001917 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001918 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001919
Richard Hughese7299962013-05-01 21:52:12 +01001920 output->base.gamma_size = output->original_crtc->gamma_size;
1921 output->base.set_gamma = drm_output_set_gamma;
1922
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001923 weston_plane_init(&output->cursor_plane, 0, 0);
1924 weston_plane_init(&output->fb_plane, 0, 0);
1925
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001926 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1927 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1928 &ec->base.primary_plane);
1929
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001930 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001931 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001932 wl_list_for_each(m, &output->base.mode_list, link)
1933 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1934 m->width, m->height, m->refresh / 1000.0,
1935 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1936 ", preferred" : "",
1937 m->flags & WL_OUTPUT_MODE_CURRENT ?
1938 ", current" : "",
1939 connector->count_modes == 0 ?
1940 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001941
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001942 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001943
John Kåre Alsaker94659272012-11-13 19:10:18 +01001944err_output:
1945 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001946err_free:
1947 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1948 base.link) {
1949 wl_list_remove(&drm_mode->base.link);
1950 free(drm_mode);
1951 }
1952
1953 drmModeFreeCrtc(output->original_crtc);
1954 ec->crtc_allocator &= ~(1 << output->crtc_id);
1955 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001956 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001957
David Herrmann0f0d54e2011-12-08 17:05:45 +01001958 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001959}
1960
Jesse Barnes58ef3792012-02-23 09:45:49 -05001961static void
1962create_sprites(struct drm_compositor *ec)
1963{
1964 struct drm_sprite *sprite;
1965 drmModePlaneRes *plane_res;
1966 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001967 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001968
1969 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1970 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001971 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001972 strerror(errno));
1973 return;
1974 }
1975
1976 for (i = 0; i < plane_res->count_planes; i++) {
1977 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1978 if (!plane)
1979 continue;
1980
1981 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1982 plane->count_formats));
1983 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001984 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001985 __func__);
1986 free(plane);
1987 continue;
1988 }
1989
1990 memset(sprite, 0, sizeof *sprite);
1991
1992 sprite->possible_crtcs = plane->possible_crtcs;
1993 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001994 sprite->current = NULL;
1995 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001996 sprite->compositor = ec;
1997 sprite->count_formats = plane->count_formats;
1998 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001999 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002000 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002001 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002002 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2003 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002004
2005 wl_list_insert(&ec->sprite_list, &sprite->link);
2006 }
2007
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002008 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002009}
2010
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002011static void
2012destroy_sprites(struct drm_compositor *compositor)
2013{
2014 struct drm_sprite *sprite, *next;
2015 struct drm_output *output;
2016
2017 output = container_of(compositor->base.output_list.next,
2018 struct drm_output, base.link);
2019
2020 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2021 drmModeSetPlane(compositor->drm.fd,
2022 sprite->plane_id,
2023 output->crtc_id, 0, 0,
2024 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002025 drm_output_release_fb(output, sprite->current);
2026 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002027 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002028 free(sprite);
2029 }
2030}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002031
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002032static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002033create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002034 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002035{
2036 drmModeConnector *connector;
2037 drmModeRes *resources;
2038 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002039 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002040
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002041 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002042 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002043 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002044 return -1;
2045 }
2046
Jesse Barnes58ef3792012-02-23 09:45:49 -05002047 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002048 if (!ec->crtcs) {
2049 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002050 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002051 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002052
Rob Clark4339add2012-08-09 14:18:28 -05002053 ec->min_width = resources->min_width;
2054 ec->max_width = resources->max_width;
2055 ec->min_height = resources->min_height;
2056 ec->max_height = resources->max_height;
2057
Jesse Barnes58ef3792012-02-23 09:45:49 -05002058 ec->num_crtcs = resources->count_crtcs;
2059 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2060
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002061 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002062 connector = drmModeGetConnector(ec->drm.fd,
2063 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002064 if (connector == NULL)
2065 continue;
2066
2067 if (connector->connection == DRM_MODE_CONNECTED &&
2068 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002069 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002070 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002071 connector, x, y,
2072 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002073 drmModeFreeConnector(connector);
2074 continue;
2075 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002076
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002077 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002078 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002079 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002080 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002081
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002082 drmModeFreeConnector(connector);
2083 }
2084
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002085 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002086 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002087 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002088 return -1;
2089 }
2090
2091 drmModeFreeResources(resources);
2092
2093 return 0;
2094}
2095
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002096static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002097update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002098{
2099 drmModeConnector *connector;
2100 drmModeRes *resources;
2101 struct drm_output *output, *next;
2102 int x = 0, y = 0;
2103 int x_offset = 0, y_offset = 0;
2104 uint32_t connected = 0, disconnects = 0;
2105 int i;
2106
2107 resources = drmModeGetResources(ec->drm.fd);
2108 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002109 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002110 return;
2111 }
2112
2113 /* collect new connects */
2114 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002115 int connector_id = resources->connectors[i];
2116
2117 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002118 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002119 continue;
2120
David Herrmann7551cff2011-12-08 17:05:43 +01002121 if (connector->connection != DRM_MODE_CONNECTED) {
2122 drmModeFreeConnector(connector);
2123 continue;
2124 }
2125
Benjamin Franzke117483d2011-08-30 11:38:26 +02002126 connected |= (1 << connector_id);
2127
2128 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002129 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002130 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002131 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002132
2133 /* XXX: not yet needed, we die with 0 outputs */
2134 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002135 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002136 else
2137 x = 0;
2138 y = 0;
2139 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002140 connector, x, y,
2141 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002142 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002143
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002144 }
2145 drmModeFreeConnector(connector);
2146 }
2147 drmModeFreeResources(resources);
2148
2149 disconnects = ec->connector_allocator & ~connected;
2150 if (disconnects) {
2151 wl_list_for_each_safe(output, next, &ec->base.output_list,
2152 base.link) {
2153 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002154 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002155 output->base.x - x_offset,
2156 output->base.y - y_offset);
2157 }
2158
2159 if (disconnects & (1 << output->connector_id)) {
2160 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002161 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002162 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002163 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002164 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002165 }
2166 }
2167 }
2168
2169 /* FIXME: handle zero outputs, without terminating */
2170 if (ec->connector_allocator == 0)
2171 wl_display_terminate(ec->base.wl_display);
2172}
2173
2174static int
David Herrmannd7488c22012-03-11 20:05:21 +01002175udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002176{
David Herrmannd7488c22012-03-11 20:05:21 +01002177 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002178 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002179
2180 sysnum = udev_device_get_sysnum(device);
2181 if (!sysnum || atoi(sysnum) != ec->drm.id)
2182 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002183
David Herrmann6ac52db2012-03-11 20:05:22 +01002184 val = udev_device_get_property_value(device, "HOTPLUG");
2185 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002186 return 0;
2187
David Herrmann6ac52db2012-03-11 20:05:22 +01002188 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002189}
2190
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002191static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002192udev_drm_event(int fd, uint32_t mask, void *data)
2193{
2194 struct drm_compositor *ec = data;
2195 struct udev_device *event;
2196
2197 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002198
David Herrmannd7488c22012-03-11 20:05:21 +01002199 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002200 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002201
2202 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002203
2204 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002205}
2206
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002207static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002208drm_restore(struct weston_compositor *ec)
2209{
2210 struct drm_compositor *d = (struct drm_compositor *) ec;
2211
2212 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2213 weston_log("failed to drop master: %m\n");
2214 tty_reset(d->tty);
2215}
2216
2217static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002218drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002219{
2220 struct drm_compositor *d = (struct drm_compositor *) ec;
2221
Rob Bradfordd355b802013-05-31 18:09:55 +01002222 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002223
2224 wl_event_source_remove(d->udev_drm_source);
2225 wl_event_source_remove(d->drm_source);
2226
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002227 destroy_sprites(d);
2228
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002229 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002230
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002231 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002232
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002233 if (d->gbm)
2234 gbm_device_destroy(d->gbm);
2235
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002236 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002237 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002238 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002239
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002240 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002241}
2242
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002243static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002244drm_compositor_set_modes(struct drm_compositor *compositor)
2245{
2246 struct drm_output *output;
2247 struct drm_mode *drm_mode;
2248 int ret;
2249
2250 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002251 if (!output->current) {
2252 /* If something that would cause the output to
2253 * switch mode happened while in another vt, we
2254 * might not have a current drm_fb. In that case,
2255 * schedule a repaint and let drm_output_repaint
2256 * handle setting the mode. */
2257 weston_output_schedule_repaint(&output->base);
2258 continue;
2259 }
2260
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002261 drm_mode = (struct drm_mode *) output->base.current;
2262 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002263 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002264 &output->connector_id, 1,
2265 &drm_mode->mode_info);
2266 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002267 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002268 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002269 drm_mode->base.width, drm_mode->base.height,
2270 output->base.x, output->base.y);
2271 }
2272 }
2273}
2274
2275static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002276vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002277{
2278 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002279 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002280 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002281
2282 switch (event) {
2283 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002284 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002285 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002286 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002287 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002288 wl_display_terminate(compositor->wl_display);
2289 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002290 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002291 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002292 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002293 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002294 break;
2295 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002296 weston_log("leaving VT\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002297 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002298
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002299 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002300 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002301 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002302
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002303 /* If we have a repaint scheduled (either from a
2304 * pending pageflip or the idle handler), make sure we
2305 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002306 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002307 * further attemps at repainting. When we switch
2308 * back, we schedule a repaint, which will process
2309 * pending frame callbacks. */
2310
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002311 wl_list_for_each(output, &ec->base.output_list, base.link) {
2312 output->base.repaint_needed = 0;
2313 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002314 }
2315
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002316 output = container_of(ec->base.output_list.next,
2317 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002318
2319 wl_list_for_each(sprite, &ec->sprite_list, link)
2320 drmModeSetPlane(ec->drm.fd,
2321 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002322 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002323 0, 0, 0, 0, 0, 0, 0, 0);
2324
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002325 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002326 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002327
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002328 break;
2329 };
2330}
2331
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002332static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002333switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002334{
2335 struct drm_compositor *ec = data;
2336
Daniel Stone325fc2d2012-05-30 16:31:58 +01002337 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002338}
2339
David Herrmann0af066f2012-10-29 19:21:16 +01002340/*
2341 * Find primary GPU
2342 * Some systems may have multiple DRM devices attached to a single seat. This
2343 * function loops over all devices and tries to find a PCI device with the
2344 * boot_vga sysfs attribute set to 1.
2345 * If no such device is found, the first DRM device reported by udev is used.
2346 */
2347static struct udev_device*
2348find_primary_gpu(struct drm_compositor *ec, const char *seat)
2349{
2350 struct udev_enumerate *e;
2351 struct udev_list_entry *entry;
2352 const char *path, *device_seat, *id;
2353 struct udev_device *device, *drm_device, *pci;
2354
2355 e = udev_enumerate_new(ec->udev);
2356 udev_enumerate_add_match_subsystem(e, "drm");
2357 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2358
2359 udev_enumerate_scan_devices(e);
2360 drm_device = NULL;
2361 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2362 path = udev_list_entry_get_name(entry);
2363 device = udev_device_new_from_syspath(ec->udev, path);
2364 if (!device)
2365 continue;
2366 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2367 if (!device_seat)
2368 device_seat = default_seat;
2369 if (strcmp(device_seat, seat)) {
2370 udev_device_unref(device);
2371 continue;
2372 }
2373
2374 pci = udev_device_get_parent_with_subsystem_devtype(device,
2375 "pci", NULL);
2376 if (pci) {
2377 id = udev_device_get_sysattr_value(pci, "boot_vga");
2378 if (id && !strcmp(id, "1")) {
2379 if (drm_device)
2380 udev_device_unref(drm_device);
2381 drm_device = device;
2382 break;
2383 }
2384 }
2385
2386 if (!drm_device)
2387 drm_device = device;
2388 else
2389 udev_device_unref(device);
2390 }
2391
2392 udev_enumerate_unref(e);
2393 return drm_device;
2394}
2395
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002396static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002397planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002398{
2399 struct drm_compositor *c = data;
2400
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002401 switch (key) {
2402 case KEY_C:
2403 c->cursors_are_broken ^= 1;
2404 break;
2405 case KEY_V:
2406 c->sprites_are_broken ^= 1;
2407 break;
2408 case KEY_O:
2409 c->sprites_hidden ^= 1;
2410 break;
2411 default:
2412 break;
2413 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002414}
2415
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002416static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002417drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002418 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002419 int *argc, char *argv[],
2420 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002421{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002422 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002423 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002424 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002425 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002426 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002427
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002428 weston_log("initializing drm backend\n");
2429
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002430 ec = malloc(sizeof *ec);
2431 if (ec == NULL)
2432 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002433 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002434
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002435 /* KMS support for sprites is not complete yet, so disable the
2436 * functionality for now. */
2437 ec->sprites_are_broken = 1;
2438
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002439 ec->use_pixman = pixman;
2440
Daniel Stone725c2c32012-06-22 14:04:36 +01002441 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002442 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002443 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002444 goto err_base;
2445 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002446
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002447 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002448 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002449 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002450 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002451 goto err_compositor;
2452 }
2453
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002454 ec->udev = udev_new();
2455 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002456 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002457 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002458 }
2459
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002460 ec->base.wl_display = display;
2461 ec->tty = tty_create(&ec->base, vt_func, tty);
2462 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002463 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002464 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002465 }
2466
Rob Bradford643641d2013-05-31 18:09:53 +01002467 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002468 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002469 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002470 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002471 }
David Herrmann0af066f2012-10-29 19:21:16 +01002472 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002473
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002474 if (init_drm(ec, drm_device) < 0) {
2475 weston_log("failed to initialize kms\n");
2476 goto err_udev_dev;
2477 }
2478
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002479 if (ec->use_pixman) {
2480 if (init_pixman(ec) < 0) {
2481 weston_log("failed to initialize pixman renderer\n");
2482 goto err_udev_dev;
2483 }
2484 } else {
2485 if (init_egl(ec) < 0) {
2486 weston_log("failed to initialize egl\n");
2487 goto err_udev_dev;
2488 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002489 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002490
2491 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002492 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002493
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002494 ec->base.focus = 1;
2495
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002496 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002497
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002498 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002499 weston_compositor_add_key_binding(&ec->base, key,
2500 MODIFIER_CTRL | MODIFIER_ALT,
2501 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002502
Jesse Barnes58ef3792012-02-23 09:45:49 -05002503 wl_list_init(&ec->sprite_list);
2504 create_sprites(ec);
2505
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002506 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002507 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002508 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002509 }
2510
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002511 path = NULL;
2512
Rob Bradfordd355b802013-05-31 18:09:55 +01002513 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002514 weston_log("failed to create input devices\n");
2515 goto err_sprite;
2516 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002517
2518 loop = wl_display_get_event_loop(ec->base.wl_display);
2519 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002520 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002521 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002522
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002523 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2524 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002525 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002526 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002527 }
2528 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2529 "drm", NULL);
2530 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002531 wl_event_loop_add_fd(loop,
2532 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002533 WL_EVENT_READABLE, udev_drm_event, ec);
2534
2535 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002536 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002537 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002538 }
2539
Daniel Stonea96b93c2012-06-22 14:04:37 +01002540 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002541
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002542 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002543 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002544 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002545 planes_binding, ec);
2546 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2547 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002548
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002549 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002550
2551err_udev_monitor:
2552 wl_event_source_remove(ec->udev_drm_source);
2553 udev_monitor_unref(ec->udev_monitor);
2554err_drm_source:
2555 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002556 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002557err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002558 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002559 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002560 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002561err_udev_dev:
2562 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002563err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002564 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2565 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002566 tty_destroy(ec->tty);
2567err_udev:
2568 udev_unref(ec->udev);
2569err_compositor:
2570 weston_compositor_shutdown(&ec->base);
2571err_base:
2572 free(ec);
2573 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002574}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002575
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002576WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002577backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002578 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002579{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002580 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002581 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002582
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002583 const struct weston_option drm_options[] = {
2584 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002585 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002586 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002587 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002588 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002589 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002590
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002591 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002592
Rob Bradford643641d2013-05-31 18:09:53 +01002593 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002594 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002595}