blob: bee41efeeb635fffcb1cfd90920be317f756771a [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.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 Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040044#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020045
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080046#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Jonas Ådahle0de3c22014-03-12 22:08:42 +010050#include "udev-input.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030054#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
55#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
56#endif
57
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030058#ifndef DRM_CAP_CURSOR_WIDTH
59#define DRM_CAP_CURSOR_WIDTH 0x8
60#endif
61
62#ifndef DRM_CAP_CURSOR_HEIGHT
63#define DRM_CAP_CURSOR_HEIGHT 0x9
64#endif
65
66#ifndef GBM_BO_USE_CURSOR
67#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
68#endif
69
Kristian Høgsberg061c4252012-06-28 11:28:15 -040070static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060071
72enum output_config {
73 OUTPUT_CONFIG_INVALID = 0,
74 OUTPUT_CONFIG_OFF,
75 OUTPUT_CONFIG_PREFERRED,
76 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060077 OUTPUT_CONFIG_MODE,
78 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060079};
80
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040081struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050082 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040083
84 struct udev *udev;
85 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040086
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010087 struct udev_monitor *udev_monitor;
88 struct wl_event_source *udev_drm_source;
89
Benjamin Franzke2af7f102011-03-02 11:14:59 +010090 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010091 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010092 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030093 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010094 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020095 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050096 uint32_t *crtcs;
97 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050098 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010099 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700100 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700101 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200102
Rob Clark4339add2012-08-09 14:18:28 -0500103 /* we need these parameters in order to not fail drmModeAddFB2()
104 * due to out of bounds dimensions, and then mistakenly set
105 * sprites_are_broken:
106 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200107 uint32_t min_width, max_width;
108 uint32_t min_height, max_height;
109 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500110
Jesse Barnes58ef3792012-02-23 09:45:49 -0500111 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500112 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200113 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500114
Rob Clarkab5b1e32012-08-09 13:24:45 -0500115 int cursors_are_broken;
116
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200117 int use_pixman;
118
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200119 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300120
Rob Bradfordd355b802013-05-31 18:09:55 +0100121 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300122
123 uint32_t cursor_width;
124 uint32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400125};
126
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400127struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500128 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400129 drmModeModeInfo mode_info;
130};
131
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132struct drm_output;
133
134struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300135 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200136 uint32_t fb_id, stride, handle, size;
137 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300138 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200139 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200140
141 /* Used by gbm fbs */
142 struct gbm_bo *bo;
143
144 /* Used by dumb fbs */
145 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300146};
147
Richard Hughes2b2092a2013-04-24 14:58:02 +0100148struct drm_edid {
149 char eisa_id[13];
150 char monitor_name[13];
151 char pnp_id[5];
152 char serial_number[13];
153};
154
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400155struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500156 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400157
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400158 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500159 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400160 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700161 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100162 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300163 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000164 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200165
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300166 int vblank_pending;
167 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800168 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300169
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400170 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400171 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400172 struct weston_plane cursor_plane;
173 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500174 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400175 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300176 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200177 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200178
179 struct drm_fb *dumb[2];
180 pixman_image_t *image[2];
181 int current_image;
182 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300183
184 struct vaapi_recorder *recorder;
185 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400186};
187
Jesse Barnes58ef3792012-02-23 09:45:49 -0500188/*
189 * An output has a primary display plane plus zero or more sprites for
190 * blending display contents.
191 */
192struct drm_sprite {
193 struct wl_list link;
194
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400195 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500196
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200197 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300198 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500199 struct drm_compositor *compositor;
200
Jesse Barnes58ef3792012-02-23 09:45:49 -0500201 uint32_t possible_crtcs;
202 uint32_t plane_id;
203 uint32_t count_formats;
204
205 int32_t src_x, src_y;
206 uint32_t src_w, src_h;
207 uint32_t dest_x, dest_y;
208 uint32_t dest_w, dest_h;
209
210 uint32_t formats[];
211};
212
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700213struct drm_parameters {
214 int connector;
215 int tty;
216 int use_pixman;
217 const char *seat_id;
218};
219
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300220static struct gl_renderer_interface *gl_renderer;
221
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500222static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400223
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400224static void
225drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400226
Jesse Barnes58ef3792012-02-23 09:45:49 -0500227static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500228drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
229{
230 struct weston_compositor *ec = output_base->compositor;
231 struct drm_compositor *c =(struct drm_compositor *) ec;
232 struct drm_output *output = (struct drm_output *) output_base;
233 int crtc;
234
235 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
236 if (c->crtcs[crtc] != output->crtc_id)
237 continue;
238
239 if (supported & (1 << crtc))
240 return -1;
241 }
242
243 return 0;
244}
245
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300246static void
247drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
248{
249 struct drm_fb *fb = data;
250 struct gbm_device *gbm = gbm_bo_get_device(bo);
251
252 if (fb->fb_id)
253 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
254
Pekka Paalanende685b82012-12-04 15:58:12 +0200255 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300256
257 free(data);
258}
259
260static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200261drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
262{
263 struct drm_fb *fb;
264 int ret;
265
266 struct drm_mode_create_dumb create_arg;
267 struct drm_mode_destroy_dumb destroy_arg;
268 struct drm_mode_map_dumb map_arg;
269
Peter Huttererf3d62272013-08-08 11:57:05 +1000270 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200271 if (!fb)
272 return NULL;
273
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700274 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200275 create_arg.bpp = 32;
276 create_arg.width = width;
277 create_arg.height = height;
278
279 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
280 if (ret)
281 goto err_fb;
282
283 fb->handle = create_arg.handle;
284 fb->stride = create_arg.pitch;
285 fb->size = create_arg.size;
286 fb->fd = ec->drm.fd;
287
288 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
289 fb->stride, fb->handle, &fb->fb_id);
290 if (ret)
291 goto err_bo;
292
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700293 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200294 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400295 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200296 if (ret)
297 goto err_add_fb;
298
299 fb->map = mmap(0, fb->size, PROT_WRITE,
300 MAP_SHARED, ec->drm.fd, map_arg.offset);
301 if (fb->map == MAP_FAILED)
302 goto err_add_fb;
303
304 return fb;
305
306err_add_fb:
307 drmModeRmFB(ec->drm.fd, fb->fb_id);
308err_bo:
309 memset(&destroy_arg, 0, sizeof(destroy_arg));
310 destroy_arg.handle = create_arg.handle;
311 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
312err_fb:
313 free(fb);
314 return NULL;
315}
316
317static void
318drm_fb_destroy_dumb(struct drm_fb *fb)
319{
320 struct drm_mode_destroy_dumb destroy_arg;
321
322 if (!fb->map)
323 return;
324
325 if (fb->fb_id)
326 drmModeRmFB(fb->fd, fb->fb_id);
327
328 weston_buffer_reference(&fb->buffer_ref, NULL);
329
330 munmap(fb->map, fb->size);
331
332 memset(&destroy_arg, 0, sizeof(destroy_arg));
333 destroy_arg.handle = fb->handle;
334 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
335
336 free(fb);
337}
338
339static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500340drm_fb_get_from_bo(struct gbm_bo *bo,
341 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300342{
343 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200345 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300346 int ret;
347
348 if (fb)
349 return fb;
350
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200351 fb = calloc(1, sizeof *fb);
352 if (!fb)
353 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354
355 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356
357 width = gbm_bo_get_width(bo);
358 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 fb->stride = gbm_bo_get_stride(bo);
360 fb->handle = gbm_bo_get_handle(bo).u32;
361 fb->size = fb->stride * height;
362 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300363
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 if (compositor->min_width > width || width > compositor->max_width ||
365 compositor->min_height > height ||
366 height > compositor->max_height) {
367 weston_log("bo geometry out of bounds\n");
368 goto err_free;
369 }
370
371 ret = -1;
372
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200373 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200374 handles[0] = fb->handle;
375 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376 offsets[0] = 0;
377
378 ret = drmModeAddFB2(compositor->drm.fd, width, height,
379 format, handles, pitches, offsets,
380 &fb->fb_id, 0);
381 if (ret) {
382 weston_log("addfb2 failed: %m\n");
383 compositor->no_addfb2 = 1;
384 compositor->sprites_are_broken = 1;
385 }
386 }
387
388 if (ret)
389 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200390 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200391
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300392 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200393 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200394 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300395 }
396
397 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
398
399 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200400
401err_free:
402 free(fb);
403 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404}
405
406static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500407drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200408{
Pekka Paalanende685b82012-12-04 15:58:12 +0200409 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200410
411 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200412
Pekka Paalanende685b82012-12-04 15:58:12 +0200413 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200414}
415
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200416static void
417drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
418{
419 if (!fb)
420 return;
421
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200422 if (fb->map &&
423 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200424 drm_fb_destroy_dumb(fb);
425 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200426 if (fb->is_client_buffer)
427 gbm_bo_destroy(fb->bo);
428 else
429 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600430 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200431 }
432}
433
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500434static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200435drm_output_check_scanout_format(struct drm_output *output,
436 struct weston_surface *es, struct gbm_bo *bo)
437{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200438 uint32_t format;
439 pixman_region32_t r;
440
441 format = gbm_bo_get_format(bo);
442
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700443 if (format == GBM_FORMAT_ARGB8888) {
444 /* We can scanout an ARGB buffer if the surface's
445 * opaque region covers the whole output, but we have
446 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800447 pixman_region32_init_rect(&r, 0, 0,
448 output->base.width,
449 output->base.height);
450 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200451
452 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500453 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200454
455 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500456 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700457
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000458 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700459 return format;
460
461 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200462}
463
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400464static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500465drm_output_prepare_scanout_view(struct weston_output *_output,
466 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500467{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400468 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500469 struct drm_compositor *c =
470 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500471 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200472 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300473 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500474 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500475
Jason Ekstranda7af7042013-10-12 22:38:11 -0500476 if (ev->geometry.x != output->base.x ||
477 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200478 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200479 buffer->width != output->base.current_mode->width ||
480 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200481 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500482 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400483 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500484
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400485 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700486 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500487
Rob Bradford9b101872012-09-14 23:25:41 +0100488 /* Unable to use the buffer for scanout */
489 if (!bo)
490 return NULL;
491
Jason Ekstranda7af7042013-10-12 22:38:11 -0500492 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500493 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300494 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400495 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300496 }
497
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500498 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 if (!output->next) {
500 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400501 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300502 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500503
Pekka Paalanende685b82012-12-04 15:58:12 +0200504 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500505
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400506 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500507}
508
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500509static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200510drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400511{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200512 struct drm_compositor *c =
513 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300514 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200516 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400517
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300518 bo = gbm_surface_lock_front_buffer(output->surface);
519 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200520 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400521 return;
522 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300523
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000524 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300525 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200526 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300527 gbm_surface_release_buffer(output->surface, bo);
528 return;
529 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400530}
531
532static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200533drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
534{
535 struct weston_compositor *ec = output->base.compositor;
536 pixman_region32_t total_damage, previous_damage;
537
538 pixman_region32_init(&total_damage);
539 pixman_region32_init(&previous_damage);
540
541 pixman_region32_copy(&previous_damage, damage);
542
543 pixman_region32_union(&total_damage, damage, &output->previous_damage);
544 pixman_region32_copy(&output->previous_damage, &previous_damage);
545
546 output->current_image ^= 1;
547
548 output->next = output->dumb[output->current_image];
549 pixman_renderer_output_set_buffer(&output->base,
550 output->image[output->current_image]);
551
552 ec->renderer->repaint_output(&output->base, &total_damage);
553
554 pixman_region32_fini(&total_damage);
555 pixman_region32_fini(&previous_damage);
556}
557
558static void
559drm_output_render(struct drm_output *output, pixman_region32_t *damage)
560{
561 struct drm_compositor *c =
562 (struct drm_compositor *) output->base.compositor;
563
564 if (c->use_pixman)
565 drm_output_render_pixman(output, damage);
566 else
567 drm_output_render_gl(output, damage);
568
569 pixman_region32_subtract(&c->base.primary_plane.damage,
570 &c->base.primary_plane.damage, damage);
571}
572
573static void
Richard Hughese7299962013-05-01 21:52:12 +0100574drm_output_set_gamma(struct weston_output *output_base,
575 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
576{
577 int rc;
578 struct drm_output *output = (struct drm_output *) output_base;
579 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
580
581 /* check */
582 if (output_base->gamma_size != size)
583 return;
584 if (!output->original_crtc)
585 return;
586
587 rc = drmModeCrtcSetGamma(compositor->drm.fd,
588 output->crtc_id,
589 size, r, g, b);
590 if (rc)
591 weston_log("set gamma failed: %m\n");
592}
593
David Herrmann1edf44c2013-10-22 17:11:26 +0200594static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500595drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400596 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100597{
598 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500599 struct drm_compositor *compositor =
600 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400602 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100604
Xiong Zhangabd5d472013-10-11 14:43:07 +0800605 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200606 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800607
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300608 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400609 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300610 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200611 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100612
Hardeningff39efa2013-09-18 23:56:35 +0200613 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200614 if (!output->current ||
615 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400616 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300617 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400618 &output->connector_id, 1,
619 &mode->mode_info);
620 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200621 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200622 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400623 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300624 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200625 }
626
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500627 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300628 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500629 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200630 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200631 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500632 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100633
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300634 output->page_flip_pending = 1;
635
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400636 drm_output_set_cursor(output);
637
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638 /*
639 * Now, update all the sprite surfaces
640 */
641 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 drmVBlank vbl = {
644 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
645 .request.sequence = 1,
646 };
647
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200648 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200649 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650 continue;
651
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200652 if (s->next && !compositor->sprites_hidden)
653 fb_id = s->next->fb_id;
654
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200656 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 s->dest_x, s->dest_y,
658 s->dest_w, s->dest_h,
659 s->src_x, s->src_y,
660 s->src_w, s->src_h);
661 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200662 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500663 ret, strerror(errno));
664
Rob Clark5ca1a472012-08-08 20:27:37 -0500665 if (output->pipe > 0)
666 vbl.request.type |= DRM_VBLANK_SECONDARY;
667
Jesse Barnes58ef3792012-02-23 09:45:49 -0500668 /*
669 * Queue a vblank signal so we know when the surface
670 * becomes active on the display or has been replaced.
671 */
672 vbl.request.signal = (unsigned long)s;
673 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
674 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200675 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500676 ret, strerror(errno));
677 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300678
679 s->output = output;
680 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681 }
682
David Herrmann1edf44c2013-10-22 17:11:26 +0200683 return 0;
684
685err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800686 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200687 if (output->next) {
688 drm_output_release_fb(output, output->next);
689 output->next = NULL;
690 }
691
692 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400693}
694
695static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200696drm_output_start_repaint_loop(struct weston_output *output_base)
697{
698 struct drm_output *output = (struct drm_output *) output_base;
699 struct drm_compositor *compositor = (struct drm_compositor *)
700 output_base->compositor;
701 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300702 struct timespec ts;
703
Xiong Zhangabd5d472013-10-11 14:43:07 +0800704 if (output->destroy_pending)
705 return;
706
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300707 if (!output->current) {
708 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200709 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300710 }
711
712 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200713
714 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
715 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
716 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200717 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200718 }
David Herrmann3c688c52013-10-22 17:11:25 +0200719
720 return;
721
722finish_frame:
723 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400724 clock_gettime(compositor->base.presentation_clock, &ts);
725 weston_output_finish_frame(output_base, &ts);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200726}
727
728static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400729drm_output_update_msc(struct drm_output *output, unsigned int seq)
730{
731 uint64_t msc_hi = output->base.msc >> 32;
732
733 if (seq < (output->base.msc & 0xffffffff))
734 msc_hi++;
735
736 output->base.msc = (msc_hi << 32) + seq;
737}
738
739static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500740vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
741 void *data)
742{
743 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300744 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400745 struct timespec ts;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300746
Pekka Paalanen641307c2014-09-23 22:08:47 -0400747 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300748 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500749
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200750 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200751 s->current = s->next;
752 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300753
754 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400755 ts.tv_sec = sec;
756 ts.tv_nsec = usec * 1000;
757 weston_output_finish_frame(&output->base, &ts);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300758 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500759}
760
761static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800762drm_output_destroy(struct weston_output *output_base);
763
764static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400765page_flip_handler(int fd, unsigned int frame,
766 unsigned int sec, unsigned int usec, void *data)
767{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200768 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400769 struct timespec ts;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400770
Pekka Paalanen641307c2014-09-23 22:08:47 -0400771 drm_output_update_msc(output, frame);
772
Jonas Ådahle5a12252013-04-05 23:07:11 +0200773 /* We don't set page_flip_pending on start_repaint_loop, in that case
774 * we just want to page flip to the current buffer to get an accurate
775 * timestamp */
776 if (output->page_flip_pending) {
777 drm_output_release_fb(output, output->current);
778 output->current = output->next;
779 output->next = NULL;
780 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300781
Jonas Ådahle5a12252013-04-05 23:07:11 +0200782 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400783
Xiong Zhangabd5d472013-10-11 14:43:07 +0800784 if (output->destroy_pending)
785 drm_output_destroy(&output->base);
786 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400787 ts.tv_sec = sec;
788 ts.tv_nsec = usec * 1000;
789 weston_output_finish_frame(&output->base, &ts);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300790
791 /* We can't call this from frame_notify, because the output's
792 * repaint needed flag is cleared just after that */
793 if (output->recorder)
794 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300795 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200796}
797
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500798static uint32_t
799drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500800 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500802 uint32_t i, format;
803
804 format = gbm_bo_get_format(bo);
805
806 if (format == GBM_FORMAT_ARGB8888) {
807 pixman_region32_t r;
808
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500809 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600810 ev->surface->width,
811 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500812 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500813
814 if (!pixman_region32_not_empty(&r))
815 format = GBM_FORMAT_XRGB8888;
816
817 pixman_region32_fini(&r);
818 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500819
820 for (i = 0; i < s->count_formats; i++)
821 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500822 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823
824 return 0;
825}
826
827static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500828drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500829{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500830 return !ev->transform.enabled ||
831 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500832}
833
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500835drm_output_prepare_overlay_view(struct weston_output *output_base,
836 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837{
838 struct weston_compositor *ec = output_base->compositor;
839 struct drm_compositor *c =(struct drm_compositor *) ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200840 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 struct drm_sprite *s;
842 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500843 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200845 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500846 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400847 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500848
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200849 if (c->gbm == NULL)
850 return NULL;
851
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200852 if (viewport->buffer.transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200853 return NULL;
854
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200855 if (viewport->buffer.scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200856 return NULL;
857
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500858 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400859 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500860
Jason Ekstranda7af7042013-10-12 22:38:11 -0500861 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400862 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300863
Jason Ekstranda7af7042013-10-12 22:38:11 -0500864 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400865 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500866
Jason Ekstranda7af7042013-10-12 22:38:11 -0500867 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200868 return NULL;
869
Jason Ekstranda7af7042013-10-12 22:38:11 -0500870 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500871 return NULL;
872
Jason Ekstranda7af7042013-10-12 22:38:11 -0500873 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400874 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500875
Jesse Barnes58ef3792012-02-23 09:45:49 -0500876 wl_list_for_each(s, &c->sprite_list, link) {
877 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
878 continue;
879
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200880 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500881 found = 1;
882 break;
883 }
884 }
885
886 /* No sprites available */
887 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400888 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500889
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400890 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500891 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700892 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400893 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400894 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400895
Jason Ekstranda7af7042013-10-12 22:38:11 -0500896 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500897 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200898 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400899 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500900 }
901
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200902 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200903 if (!s->next) {
904 gbm_bo_destroy(bo);
905 return NULL;
906 }
907
Jason Ekstranda7af7042013-10-12 22:38:11 -0500908 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500909
Jason Ekstranda7af7042013-10-12 22:38:11 -0500910 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400911 s->plane.x = box->x1;
912 s->plane.y = box->y1;
913
Jesse Barnes58ef3792012-02-23 09:45:49 -0500914 /*
915 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500916 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500917 * for us already).
918 */
919 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500920 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500921 &output_base->region);
922 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
923 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200924 tbox = weston_transformed_rect(output_base->width,
925 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200926 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200927 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200928 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200929 s->dest_x = tbox.x1;
930 s->dest_y = tbox.y1;
931 s->dest_w = tbox.x2 - tbox.x1;
932 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500933 pixman_region32_fini(&dest_rect);
934
935 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500936 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500937 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500938 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400939
Jason Ekstranda7af7042013-10-12 22:38:11 -0500940 weston_view_from_global_fixed(ev,
941 wl_fixed_from_int(box->x1),
942 wl_fixed_from_int(box->y1),
943 &sx1, &sy1);
944 weston_view_from_global_fixed(ev,
945 wl_fixed_from_int(box->x2),
946 wl_fixed_from_int(box->y2),
947 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400948
949 if (sx1 < 0)
950 sx1 = 0;
951 if (sy1 < 0)
952 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600953 if (sx2 > wl_fixed_from_int(ev->surface->width))
954 sx2 = wl_fixed_from_int(ev->surface->width);
955 if (sy2 > wl_fixed_from_int(ev->surface->height))
956 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400957
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200958 tbox.x1 = sx1;
959 tbox.y1 = sy1;
960 tbox.x2 = sx2;
961 tbox.y2 = sy2;
962
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600963 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
964 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200965 viewport->buffer.transform,
966 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100967 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200968
969 s->src_x = tbox.x1 << 8;
970 s->src_y = tbox.y1 << 8;
971 s->src_w = (tbox.x2 - tbox.x1) << 8;
972 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500973 pixman_region32_fini(&src_rect);
974
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400975 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500976}
977
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400978static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500979drm_output_prepare_cursor_view(struct weston_output *output_base,
980 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500981{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400982 struct drm_compositor *c =
983 (struct drm_compositor *) output_base->compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100984 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400985 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400986
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200987 if (c->gbm == NULL)
988 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200989 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
990 return NULL;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100991 if (viewport->buffer.scale != output_base->current_scale)
992 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500993 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400994 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500995 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400996 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500997 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400998 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500999 if (ev->surface->buffer_ref.buffer == NULL ||
1000 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001001 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001002 return NULL;
1003
Jason Ekstranda7af7042013-10-12 22:38:11 -05001004 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001005
1006 return &output->cursor_plane;
1007}
1008
1009static void
1010drm_output_set_cursor(struct drm_output *output)
1011{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001012 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001013 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001014 struct drm_compositor *c =
1015 (struct drm_compositor *) output->base.compositor;
1016 EGLint handle, stride;
1017 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001018 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001019 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001020 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001021
Jason Ekstranda7af7042013-10-12 22:38:11 -05001022 output->cursor_view = NULL;
1023 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001024 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1025 return;
1026 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001027
Neil Robertse5051712013-11-13 15:44:06 +00001028 buffer = ev->surface->buffer_ref.buffer;
1029
1030 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001031 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001032 pixman_region32_fini(&output->cursor_plane.damage);
1033 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001034 output->current_cursor ^= 1;
1035 bo = output->cursor_bo[output->current_cursor];
1036 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001037 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1038 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1039 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001040 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001041 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001042 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001043 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001044
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001045 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001046 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001047
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001048 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001049 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1050 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001051 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001052 c->cursors_are_broken = 1;
1053 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001054 }
1055
Jason Ekstranda7af7042013-10-12 22:38:11 -05001056 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1057 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001058 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001059 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001060 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001061 c->cursors_are_broken = 1;
1062 }
1063
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001064 output->cursor_plane.x = x;
1065 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001066 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001067}
1068
Jesse Barnes58ef3792012-02-23 09:45:49 -05001069static void
1070drm_assign_planes(struct weston_output *output)
1071{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001072 struct drm_compositor *c =
1073 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001074 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001075 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001076 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001077
1078 /*
1079 * Find a surface for each sprite in the output using some heuristics:
1080 * 1) size
1081 * 2) frequency of update
1082 * 3) opacity (though some hw might support alpha blending)
1083 * 4) clipping (this can be fixed with color keys)
1084 *
1085 * The idea is to save on blitting since this should save power.
1086 * If we can get a large video surface on the sprite for example,
1087 * the main display surface may not need to update at all, and
1088 * the client buffer can be used directly for the sprite surface
1089 * as we do for flipping full screen surfaces.
1090 */
1091 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001092 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001093
Jason Ekstranda7af7042013-10-12 22:38:11 -05001094 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001095 struct weston_surface *es = ev->surface;
1096
1097 /* Test whether this buffer can ever go into a plane:
1098 * non-shm, or small enough to be a cursor.
1099 *
1100 * Also, keep a reference when using the pixman renderer.
1101 * That makes it possible to do a seamless switch to the GL
1102 * renderer and since the pixman renderer keeps a reference
1103 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001104 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001105 if (c->use_pixman ||
1106 (es->buffer_ref.buffer &&
1107 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001108 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001109 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001110 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001111 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001112
Jesse Barnes58ef3792012-02-23 09:45:49 -05001113 pixman_region32_init(&surface_overlap);
1114 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001115 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001116
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001117 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001118 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001119 next_plane = primary;
1120 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001121 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001122 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001123 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001124 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001125 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001126 if (next_plane == NULL)
1127 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001128 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001129 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001130 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001131 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001132
Jesse Barnes58ef3792012-02-23 09:45:49 -05001133 pixman_region32_fini(&surface_overlap);
1134 }
1135 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001136}
1137
Matt Roper361d2ad2011-08-29 13:52:23 -07001138static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001139drm_output_fini_pixman(struct drm_output *output);
1140
1141static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001142drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001143{
1144 struct drm_output *output = (struct drm_output *) output_base;
1145 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001146 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001147 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001148
Xiong Zhangabd5d472013-10-11 14:43:07 +08001149 if (output->page_flip_pending) {
1150 output->destroy_pending = 1;
1151 weston_log("destroy output while page flip pending\n");
1152 return;
1153 }
1154
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001155 if (output->backlight)
1156 backlight_destroy(output->backlight);
1157
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001158 drmModeFreeProperty(output->dpms_prop);
1159
Matt Roper361d2ad2011-08-29 13:52:23 -07001160 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001161 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001162
1163 /* Restore original CRTC state */
1164 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001165 origcrtc->x, origcrtc->y,
1166 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001167 drmModeFreeCrtc(origcrtc);
1168
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001169 c->crtc_allocator &= ~(1 << output->crtc_id);
1170 c->connector_allocator &= ~(1 << output->connector_id);
1171
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001172 if (c->use_pixman) {
1173 drm_output_fini_pixman(output);
1174 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001175 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001176 gbm_surface_destroy(output->surface);
1177 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001178
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001179 weston_plane_release(&output->fb_plane);
1180 weston_plane_release(&output->cursor_plane);
1181
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001182 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001183
Matt Roper361d2ad2011-08-29 13:52:23 -07001184 free(output);
1185}
1186
Alex Wub7b8bda2012-04-17 17:20:48 +08001187static struct drm_mode *
1188choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1189{
1190 struct drm_mode *tmp_mode = NULL, *mode;
1191
Hardeningff39efa2013-09-18 23:56:35 +02001192 if (output->base.current_mode->width == target_mode->width &&
1193 output->base.current_mode->height == target_mode->height &&
1194 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001195 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001196 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001197
1198 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1199 if (mode->mode_info.hdisplay == target_mode->width &&
1200 mode->mode_info.vdisplay == target_mode->height) {
1201 if (mode->mode_info.vrefresh == target_mode->refresh ||
1202 target_mode->refresh == 0) {
1203 return mode;
1204 } else if (!tmp_mode)
1205 tmp_mode = mode;
1206 }
1207 }
1208
1209 return tmp_mode;
1210}
1211
1212static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001213drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001214static int
1215drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001216
1217static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001218drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1219{
1220 struct drm_output *output;
1221 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001222 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001223
1224 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001225 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001226 return -1;
1227 }
1228
1229 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001230 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001231 return -1;
1232 }
1233
1234 ec = (struct drm_compositor *)output_base->compositor;
1235 output = (struct drm_output *)output_base;
1236 drm_mode = choose_mode (output, mode);
1237
1238 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001239 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001240 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001241 }
1242
Hardeningff39efa2013-09-18 23:56:35 +02001243 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001244 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001245
Hardeningff39efa2013-09-18 23:56:35 +02001246 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001247
Hardeningff39efa2013-09-18 23:56:35 +02001248 output->base.current_mode = &drm_mode->base;
1249 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001250 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1251
Alex Wub7b8bda2012-04-17 17:20:48 +08001252 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001253 drm_output_release_fb(output, output->current);
1254 drm_output_release_fb(output, output->next);
1255 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001256
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001257 if (ec->use_pixman) {
1258 drm_output_fini_pixman(output);
1259 if (drm_output_init_pixman(output, ec) < 0) {
1260 weston_log("failed to init output pixman state with "
1261 "new mode\n");
1262 return -1;
1263 }
1264 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001265 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001266 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001267
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001268 if (drm_output_init_egl(output, ec) < 0) {
1269 weston_log("failed to init output egl state with "
1270 "new mode");
1271 return -1;
1272 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001273 }
1274
Alex Wub7b8bda2012-04-17 17:20:48 +08001275 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001276}
1277
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001278static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001279on_drm_input(int fd, uint32_t mask, void *data)
1280{
1281 drmEventContext evctx;
1282
1283 memset(&evctx, 0, sizeof evctx);
1284 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1285 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001286 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001287 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001288
1289 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001290}
1291
1292static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001293init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001294{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001295 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001296 uint64_t cap;
1297 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001298 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001299
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001300 sysnum = udev_device_get_sysnum(device);
1301 if (sysnum)
1302 ec->drm.id = atoi(sysnum);
1303 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001304 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001305 return -1;
1306 }
1307
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001308 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001309 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001310 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001311 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001312 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001313 udev_device_get_devnode(device));
1314 return -1;
1315 }
1316
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001317 weston_log("using %s\n", filename);
1318
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001319 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001320 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001321
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001322 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1323 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001324 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001325 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001326 clk_id = CLOCK_REALTIME;
1327
1328 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1329 weston_log("Error: failed to set presentation clock %d.\n",
1330 clk_id);
1331 return -1;
1332 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001333
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001334 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1335 if (ret == 0)
1336 ec->cursor_width = cap;
1337 else
1338 ec->cursor_width = 64;
1339
1340 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1341 if (ret == 0)
1342 ec->cursor_height = cap;
1343 else
1344 ec->cursor_height = 64;
1345
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001346 return 0;
1347}
1348
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001349static struct gbm_device *
1350create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001351{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001352 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001353
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001354 gl_renderer = weston_load_module("gl-renderer.so",
1355 "gl_renderer_interface");
1356 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001357 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001358
1359 /* GBM will load a dri driver, but even though they need symbols from
1360 * libglapi, in some version of Mesa they are not linked to it. Since
1361 * only the gl-renderer module links to it, the call above won't make
1362 * these symbols globally available, and loading the DRI driver fails.
1363 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1364 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1365
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001366 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001367
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001368 return gbm;
1369}
1370
1371static int
1372drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1373{
1374 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001375
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001376 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001377 if (gl_renderer->create(&ec->base, ec->gbm,
1378 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001379 return -1;
1380 }
1381
1382 return 0;
1383}
1384
1385static int
1386init_egl(struct drm_compositor *ec)
1387{
1388 ec->gbm = create_gbm_device(ec->drm.fd);
1389
1390 if (!ec->gbm)
1391 return -1;
1392
1393 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001394 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001395 return -1;
1396 }
1397
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001398 return 0;
1399}
1400
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001401static int
1402init_pixman(struct drm_compositor *ec)
1403{
1404 return pixman_renderer_init(&ec->base);
1405}
1406
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001407static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001408drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001409{
1410 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001411 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001412
1413 mode = malloc(sizeof *mode);
1414 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001415 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001416
1417 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001418 mode->base.width = info->hdisplay;
1419 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001420
1421 /* Calculate higher precision (mHz) refresh rate */
1422 refresh = (info->clock * 1000000LL / info->htotal +
1423 info->vtotal / 2) / info->vtotal;
1424
1425 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1426 refresh *= 2;
1427 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1428 refresh /= 2;
1429 if (info->vscan > 1)
1430 refresh /= info->vscan;
1431
1432 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001433 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001434
1435 if (info->type & DRM_MODE_TYPE_PREFERRED)
1436 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1437
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001438 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1439
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001440 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001441}
1442
1443static int
1444drm_subpixel_to_wayland(int drm_value)
1445{
1446 switch (drm_value) {
1447 default:
1448 case DRM_MODE_SUBPIXEL_UNKNOWN:
1449 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1450 case DRM_MODE_SUBPIXEL_NONE:
1451 return WL_OUTPUT_SUBPIXEL_NONE;
1452 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1453 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1454 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1455 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1456 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1457 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1458 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1459 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1460 }
1461}
1462
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001463/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001464static uint32_t
1465drm_get_backlight(struct drm_output *output)
1466{
1467 long brightness, max_brightness, norm;
1468
1469 brightness = backlight_get_brightness(output->backlight);
1470 max_brightness = backlight_get_max_brightness(output->backlight);
1471
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001472 /* convert it on a scale of 0 to 255 */
1473 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001474
1475 return (uint32_t) norm;
1476}
1477
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001478/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001479static void
1480drm_set_backlight(struct weston_output *output_base, uint32_t value)
1481{
1482 struct drm_output *output = (struct drm_output *) output_base;
1483 long max_brightness, new_brightness;
1484
1485 if (!output->backlight)
1486 return;
1487
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001488 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001489 return;
1490
1491 max_brightness = backlight_get_max_brightness(output->backlight);
1492
1493 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001494 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001495
1496 backlight_set_brightness(output->backlight, new_brightness);
1497}
1498
1499static drmModePropertyPtr
1500drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1501{
1502 drmModePropertyPtr props;
1503 int i;
1504
1505 for (i = 0; i < connector->count_props; i++) {
1506 props = drmModeGetProperty(fd, connector->props[i]);
1507 if (!props)
1508 continue;
1509
1510 if (!strcmp(props->name, name))
1511 return props;
1512
1513 drmModeFreeProperty(props);
1514 }
1515
1516 return NULL;
1517}
1518
1519static void
1520drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1521{
1522 struct drm_output *output = (struct drm_output *) output_base;
1523 struct weston_compositor *ec = output_base->compositor;
1524 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001525
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001526 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001527 return;
1528
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001529 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1530 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001531}
1532
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001533static const char *connector_type_names[] = {
1534 "None",
1535 "VGA",
1536 "DVI",
1537 "DVI",
1538 "DVI",
1539 "Composite",
1540 "TV",
1541 "LVDS",
1542 "CTV",
1543 "DIN",
1544 "DP",
1545 "HDMI",
1546 "HDMI",
1547 "TV",
1548 "eDP",
1549};
1550
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001551static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001552find_crtc_for_connector(struct drm_compositor *ec,
1553 drmModeRes *resources, drmModeConnector *connector)
1554{
1555 drmModeEncoder *encoder;
1556 uint32_t possible_crtcs;
1557 int i, j;
1558
1559 for (j = 0; j < connector->count_encoders; j++) {
1560 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1561 if (encoder == NULL) {
1562 weston_log("Failed to get encoder.\n");
1563 return -1;
1564 }
1565 possible_crtcs = encoder->possible_crtcs;
1566 drmModeFreeEncoder(encoder);
1567
1568 for (i = 0; i < resources->count_crtcs; i++) {
1569 if (possible_crtcs & (1 << i) &&
1570 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1571 return i;
1572 }
1573 }
1574
1575 return -1;
1576}
1577
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001578/* Init output state that depends on gl or gbm */
1579static int
1580drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1581{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001582 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001583 int i, flags;
1584
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001585 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001586 output->base.current_mode->width,
1587 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001588 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001589 GBM_BO_USE_SCANOUT |
1590 GBM_BO_USE_RENDERING);
1591 if (!output->surface) {
1592 weston_log("failed to create gbm surface\n");
1593 return -1;
1594 }
1595
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001596 if (gl_renderer->output_create(&output->base, output->surface,
1597 gl_renderer->opaque_attribs,
1598 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001599 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001600 gbm_surface_destroy(output->surface);
1601 return -1;
1602 }
1603
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001604 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001605
1606 for (i = 0; i < 2; i++) {
1607 if (output->cursor_bo[i])
1608 continue;
1609
1610 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001611 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1612 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001613 }
1614
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001615 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1616 weston_log("cursor buffers unavailable, using gl cursors\n");
1617 ec->cursors_are_broken = 1;
1618 }
1619
1620 return 0;
1621}
1622
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001623static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001624drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1625{
Hardeningff39efa2013-09-18 23:56:35 +02001626 int w = output->base.current_mode->width;
1627 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001628 unsigned int i;
1629
1630 /* FIXME error checking */
1631
1632 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001633 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001634 if (!output->dumb[i])
1635 goto err;
1636
1637 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001638 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001639 output->dumb[i]->map,
1640 output->dumb[i]->stride);
1641 if (!output->image[i])
1642 goto err;
1643 }
1644
1645 if (pixman_renderer_output_create(&output->base) < 0)
1646 goto err;
1647
1648 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001649 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001650
1651 return 0;
1652
1653err:
1654 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1655 if (output->dumb[i])
1656 drm_fb_destroy_dumb(output->dumb[i]);
1657 if (output->image[i])
1658 pixman_image_unref(output->image[i]);
1659
1660 output->dumb[i] = NULL;
1661 output->image[i] = NULL;
1662 }
1663
1664 return -1;
1665}
1666
1667static void
1668drm_output_fini_pixman(struct drm_output *output)
1669{
1670 unsigned int i;
1671
1672 pixman_renderer_output_destroy(&output->base);
1673 pixman_region32_fini(&output->previous_damage);
1674
1675 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1676 drm_fb_destroy_dumb(output->dumb[i]);
1677 pixman_image_unref(output->image[i]);
1678 output->dumb[i] = NULL;
1679 output->image[i] = NULL;
1680 }
1681}
1682
Richard Hughes2b2092a2013-04-24 14:58:02 +01001683static void
1684edid_parse_string(const uint8_t *data, char text[])
1685{
1686 int i;
1687 int replaced = 0;
1688
1689 /* this is always 12 bytes, but we can't guarantee it's null
1690 * terminated or not junk. */
1691 strncpy(text, (const char *) data, 12);
1692
1693 /* remove insane chars */
1694 for (i = 0; text[i] != '\0'; i++) {
1695 if (text[i] == '\n' ||
1696 text[i] == '\r') {
1697 text[i] = '\0';
1698 break;
1699 }
1700 }
1701
1702 /* ensure string is printable */
1703 for (i = 0; text[i] != '\0'; i++) {
1704 if (!isprint(text[i])) {
1705 text[i] = '-';
1706 replaced++;
1707 }
1708 }
1709
1710 /* if the string is random junk, ignore the string */
1711 if (replaced > 4)
1712 text[0] = '\0';
1713}
1714
1715#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1716#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1717#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1718#define EDID_OFFSET_DATA_BLOCKS 0x36
1719#define EDID_OFFSET_LAST_BLOCK 0x6c
1720#define EDID_OFFSET_PNPID 0x08
1721#define EDID_OFFSET_SERIAL 0x0c
1722
1723static int
1724edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1725{
1726 int i;
1727 uint32_t serial_number;
1728
1729 /* check header */
1730 if (length < 128)
1731 return -1;
1732 if (data[0] != 0x00 || data[1] != 0xff)
1733 return -1;
1734
1735 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1736 * /--08--\/--09--\
1737 * 7654321076543210
1738 * |\---/\---/\---/
1739 * R C1 C2 C3 */
1740 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1741 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1742 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1743 edid->pnp_id[3] = '\0';
1744
1745 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1746 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1747 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1748 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1749 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1750 if (serial_number > 0)
1751 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1752
1753 /* parse EDID data */
1754 for (i = EDID_OFFSET_DATA_BLOCKS;
1755 i <= EDID_OFFSET_LAST_BLOCK;
1756 i += 18) {
1757 /* ignore pixel clock data */
1758 if (data[i] != 0)
1759 continue;
1760 if (data[i+2] != 0)
1761 continue;
1762
1763 /* any useful blocks? */
1764 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1765 edid_parse_string(&data[i+5],
1766 edid->monitor_name);
1767 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1768 edid_parse_string(&data[i+5],
1769 edid->serial_number);
1770 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1771 edid_parse_string(&data[i+5],
1772 edid->eisa_id);
1773 }
1774 }
1775 return 0;
1776}
1777
1778static void
1779find_and_parse_output_edid(struct drm_compositor *ec,
1780 struct drm_output *output,
1781 drmModeConnector *connector)
1782{
1783 drmModePropertyBlobPtr edid_blob = NULL;
1784 drmModePropertyPtr property;
1785 int i;
1786 int rc;
1787
1788 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1789 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1790 if (!property)
1791 continue;
1792 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1793 !strcmp(property->name, "EDID")) {
1794 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1795 connector->prop_values[i]);
1796 }
1797 drmModeFreeProperty(property);
1798 }
1799 if (!edid_blob)
1800 return;
1801
1802 rc = edid_parse(&output->edid,
1803 edid_blob->data,
1804 edid_blob->length);
1805 if (!rc) {
1806 weston_log("EDID data '%s', '%s', '%s'\n",
1807 output->edid.pnp_id,
1808 output->edid.monitor_name,
1809 output->edid.serial_number);
1810 if (output->edid.pnp_id[0] != '\0')
1811 output->base.make = output->edid.pnp_id;
1812 if (output->edid.monitor_name[0] != '\0')
1813 output->base.model = output->edid.monitor_name;
1814 if (output->edid.serial_number[0] != '\0')
1815 output->base.serial_number = output->edid.serial_number;
1816 }
1817 drmModeFreePropertyBlob(edid_blob);
1818}
1819
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001820
1821
1822static int
1823parse_modeline(const char *s, drmModeModeInfo *mode)
1824{
1825 char hsync[16];
1826 char vsync[16];
1827 float fclock;
1828
1829 mode->type = DRM_MODE_TYPE_USERDEF;
1830 mode->hskew = 0;
1831 mode->vscan = 0;
1832 mode->vrefresh = 0;
1833 mode->flags = 0;
1834
Rob Bradford307e09e2013-07-26 16:29:40 +01001835 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001836 &fclock,
1837 &mode->hdisplay,
1838 &mode->hsync_start,
1839 &mode->hsync_end,
1840 &mode->htotal,
1841 &mode->vdisplay,
1842 &mode->vsync_start,
1843 &mode->vsync_end,
1844 &mode->vtotal, hsync, vsync) != 11)
1845 return -1;
1846
1847 mode->clock = fclock * 1000;
1848 if (strcmp(hsync, "+hsync") == 0)
1849 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1850 else if (strcmp(hsync, "-hsync") == 0)
1851 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1852 else
1853 return -1;
1854
1855 if (strcmp(vsync, "+vsync") == 0)
1856 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1857 else if (strcmp(vsync, "-vsync") == 0)
1858 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1859 else
1860 return -1;
1861
1862 return 0;
1863}
1864
1865static uint32_t
1866parse_transform(const char *transform, const char *output_name)
1867{
1868 static const struct { const char *name; uint32_t token; } names[] = {
1869 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1870 { "90", WL_OUTPUT_TRANSFORM_90 },
1871 { "180", WL_OUTPUT_TRANSFORM_180 },
1872 { "270", WL_OUTPUT_TRANSFORM_270 },
1873 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1874 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1875 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1876 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1877 };
1878 unsigned int i;
1879
1880 for (i = 0; i < ARRAY_LENGTH(names); i++)
1881 if (strcmp(names[i].name, transform) == 0)
1882 return names[i].token;
1883
1884 weston_log("Invalid transform \"%s\" for output %s\n",
1885 transform, output_name);
1886
1887 return WL_OUTPUT_TRANSFORM_NORMAL;
1888}
1889
Rob Bradford66bd9f52013-06-25 18:56:42 +01001890static void
1891setup_output_seat_constraint(struct drm_compositor *ec,
1892 struct weston_output *output,
1893 const char *s)
1894{
1895 if (strcmp(s, "") != 0) {
1896 struct udev_seat *seat;
1897
Jonas Ådahl58e15862014-03-12 22:08:40 +01001898 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001899 if (seat)
1900 seat->base.output = output;
1901
1902 if (seat && seat->base.pointer)
1903 weston_pointer_clamp(seat->base.pointer,
1904 &seat->base.pointer->x,
1905 &seat->base.pointer->y);
1906 }
1907}
1908
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001909static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001910get_gbm_format_from_section(struct weston_config_section *section,
1911 uint32_t default_value,
1912 uint32_t *format)
1913{
1914 char *s;
1915 int ret = 0;
1916
1917 weston_config_section_get_string(section,
1918 "gbm-format", &s, NULL);
1919
1920 if (s == NULL)
1921 *format = default_value;
1922 else if (strcmp(s, "xrgb8888") == 0)
1923 *format = GBM_FORMAT_XRGB8888;
1924 else if (strcmp(s, "rgb565") == 0)
1925 *format = GBM_FORMAT_RGB565;
1926 else if (strcmp(s, "xrgb2101010") == 0)
1927 *format = GBM_FORMAT_XRGB2101010;
1928 else {
1929 weston_log("fatal: unrecognized pixel format: %s\n", s);
1930 ret = -1;
1931 }
1932
1933 free(s);
1934
1935 return ret;
1936}
1937
1938static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001939create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001940 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001941 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001942 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001943{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001944 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001945 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001946 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001947 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001948 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001949 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001950 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001951 int i, width, height, scale;
1952 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001953 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001954 enum output_config config;
1955 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001956
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001957 i = find_crtc_for_connector(ec, resources, connector);
1958 if (i < 0) {
1959 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001960 return -1;
1961 }
1962
Peter Huttererf3d62272013-08-08 11:57:05 +10001963 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001964 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001965 return -1;
1966
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001967 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1968 output->base.make = "unknown";
1969 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001970 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001971 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001972
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001973 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1974 type_name = connector_type_names[connector->connector_type];
1975 else
1976 type_name = "UNKNOWN";
1977 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001978 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001979
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001980 section = weston_config_get_section(ec->base.config, "output", "name",
1981 output->base.name);
1982 weston_config_section_get_string(section, "mode", &s, "preferred");
1983 if (strcmp(s, "off") == 0)
1984 config = OUTPUT_CONFIG_OFF;
1985 else if (strcmp(s, "preferred") == 0)
1986 config = OUTPUT_CONFIG_PREFERRED;
1987 else if (strcmp(s, "current") == 0)
1988 config = OUTPUT_CONFIG_CURRENT;
1989 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1990 config = OUTPUT_CONFIG_MODE;
1991 else if (parse_modeline(s, &modeline) == 0)
1992 config = OUTPUT_CONFIG_MODELINE;
1993 else {
1994 weston_log("Invalid mode \"%s\" for output %s\n",
1995 s, output->base.name);
1996 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001997 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001998 free(s);
1999
2000 weston_config_section_get_int(section, "scale", &scale, 1);
2001 weston_config_section_get_string(section, "transform", &s, "normal");
2002 transform = parse_transform(s, output->base.name);
2003 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002004
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002005 if (get_gbm_format_from_section(section,
2006 ec->format,
2007 &output->format) == -1)
2008 output->format = ec->format;
2009
Rob Bradford66bd9f52013-06-25 18:56:42 +01002010 weston_config_section_get_string(section, "seat", &s, "");
2011 setup_output_seat_constraint(ec, &output->base, s);
2012 free(s);
2013
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002014 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002015 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002016 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002017 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002018 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002019
Matt Roper361d2ad2011-08-29 13:52:23 -07002020 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002021 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002022
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002023 /* Get the current mode on the crtc that's currently driving
2024 * this connector. */
2025 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002026 memset(&crtc_mode, 0, sizeof crtc_mode);
2027 if (encoder != NULL) {
2028 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2029 drmModeFreeEncoder(encoder);
2030 if (crtc == NULL)
2031 goto err_free;
2032 if (crtc->mode_valid)
2033 crtc_mode = crtc->mode;
2034 drmModeFreeCrtc(crtc);
2035 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002036
David Herrmann0f0d54e2011-12-08 17:05:45 +01002037 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002038 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002039 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002040 goto err_free;
2041 }
2042
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002043 if (config == OUTPUT_CONFIG_OFF) {
2044 weston_log("Disabling output %s\n", output->base.name);
2045 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2046 0, 0, 0, 0, 0, NULL);
2047 goto err_free;
2048 }
2049
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002050 preferred = NULL;
2051 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002052 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002053 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002054
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002055 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002056 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002057 width == drm_mode->base.width &&
2058 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002059 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002060 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002061 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002062 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002063 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002064 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002065 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002066
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002067 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002068 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002069 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002070 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002071 }
2072
Wang Quanxianacb805a2012-07-30 18:09:46 -04002073 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002074 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002075 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002076 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002077 }
2078
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002079 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002080 configured = current;
2081
Wang Quanxianacb805a2012-07-30 18:09:46 -04002082 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002083 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002084 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002085 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002086 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002087 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002088 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002089 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002090 else if (best)
2091 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002092
Hardeningff39efa2013-09-18 23:56:35 +02002093 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002094 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002095 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002096 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002097
Hardeningff39efa2013-09-18 23:56:35 +02002098 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002099
John Kåre Alsaker94659272012-11-13 19:10:18 +01002100 weston_output_init(&output->base, &ec->base, x, y,
2101 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002102 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002103
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002104 if (ec->use_pixman) {
2105 if (drm_output_init_pixman(output, ec) < 0) {
2106 weston_log("Failed to init output pixman state\n");
2107 goto err_output;
2108 }
2109 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002110 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002111 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002112 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002113
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002114 output->backlight = backlight_init(drm_device,
2115 connector->connector_type);
2116 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002117 weston_log("Initialized backlight, device %s\n",
2118 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002119 output->base.set_backlight = drm_set_backlight;
2120 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002121 } else {
2122 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002123 }
2124
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002125 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2126
Richard Hughes2b2092a2013-04-24 14:58:02 +01002127 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002128 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2129 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002130
Jonas Ådahle5a12252013-04-05 23:07:11 +02002131 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002132 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002133 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002134 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002135 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002136 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002137
Richard Hughese7299962013-05-01 21:52:12 +01002138 output->base.gamma_size = output->original_crtc->gamma_size;
2139 output->base.set_gamma = drm_output_set_gamma;
2140
Xiong Zhang97116532013-10-23 13:58:31 +08002141 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2142 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002143
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002144 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2145 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2146 &ec->base.primary_plane);
2147
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002148 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002149 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002150 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002151 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002152 m->width, m->height, m->refresh / 1000.0,
2153 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2154 ", preferred" : "",
2155 m->flags & WL_OUTPUT_MODE_CURRENT ?
2156 ", current" : "",
2157 connector->count_modes == 0 ?
2158 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002159
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002160 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002161
John Kåre Alsaker94659272012-11-13 19:10:18 +01002162err_output:
2163 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002164err_free:
2165 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2166 base.link) {
2167 wl_list_remove(&drm_mode->base.link);
2168 free(drm_mode);
2169 }
2170
2171 drmModeFreeCrtc(output->original_crtc);
2172 ec->crtc_allocator &= ~(1 << output->crtc_id);
2173 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002174 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002175
David Herrmann0f0d54e2011-12-08 17:05:45 +01002176 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002177}
2178
Jesse Barnes58ef3792012-02-23 09:45:49 -05002179static void
2180create_sprites(struct drm_compositor *ec)
2181{
2182 struct drm_sprite *sprite;
2183 drmModePlaneRes *plane_res;
2184 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002185 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002186
2187 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2188 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002189 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002190 strerror(errno));
2191 return;
2192 }
2193
2194 for (i = 0; i < plane_res->count_planes; i++) {
2195 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2196 if (!plane)
2197 continue;
2198
Peter Huttererf3d62272013-08-08 11:57:05 +10002199 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002200 plane->count_formats));
2201 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002202 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002203 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002204 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002205 continue;
2206 }
2207
Jesse Barnes58ef3792012-02-23 09:45:49 -05002208 sprite->possible_crtcs = plane->possible_crtcs;
2209 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002210 sprite->current = NULL;
2211 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002212 sprite->compositor = ec;
2213 sprite->count_formats = plane->count_formats;
2214 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002215 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002216 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002217 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002218 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2219 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002220
2221 wl_list_insert(&ec->sprite_list, &sprite->link);
2222 }
2223
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002224 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002225}
2226
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002227static void
2228destroy_sprites(struct drm_compositor *compositor)
2229{
2230 struct drm_sprite *sprite, *next;
2231 struct drm_output *output;
2232
2233 output = container_of(compositor->base.output_list.next,
2234 struct drm_output, base.link);
2235
2236 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2237 drmModeSetPlane(compositor->drm.fd,
2238 sprite->plane_id,
2239 output->crtc_id, 0, 0,
2240 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002241 drm_output_release_fb(output, sprite->current);
2242 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002243 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002244 free(sprite);
2245 }
2246}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002247
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002248static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002249create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002250 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002251{
2252 drmModeConnector *connector;
2253 drmModeRes *resources;
2254 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002255 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002256
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002257 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002258 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002259 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002260 return -1;
2261 }
2262
Jesse Barnes58ef3792012-02-23 09:45:49 -05002263 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002264 if (!ec->crtcs) {
2265 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002266 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002267 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002268
Rob Clark4339add2012-08-09 14:18:28 -05002269 ec->min_width = resources->min_width;
2270 ec->max_width = resources->max_width;
2271 ec->min_height = resources->min_height;
2272 ec->max_height = resources->max_height;
2273
Jesse Barnes58ef3792012-02-23 09:45:49 -05002274 ec->num_crtcs = resources->count_crtcs;
2275 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2276
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002277 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002278 connector = drmModeGetConnector(ec->drm.fd,
2279 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002280 if (connector == NULL)
2281 continue;
2282
2283 if (connector->connection == DRM_MODE_CONNECTED &&
2284 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002285 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002286 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002287 connector, x, y,
2288 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002289 drmModeFreeConnector(connector);
2290 continue;
2291 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002292
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002293 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002294 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002295 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002296 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002297
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002298 drmModeFreeConnector(connector);
2299 }
2300
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002301 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002302 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002303 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002304 return -1;
2305 }
2306
2307 drmModeFreeResources(resources);
2308
2309 return 0;
2310}
2311
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002312static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002313update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002314{
2315 drmModeConnector *connector;
2316 drmModeRes *resources;
2317 struct drm_output *output, *next;
2318 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002319 uint32_t connected = 0, disconnects = 0;
2320 int i;
2321
2322 resources = drmModeGetResources(ec->drm.fd);
2323 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002324 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002325 return;
2326 }
2327
2328 /* collect new connects */
2329 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002330 int connector_id = resources->connectors[i];
2331
2332 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002333 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002334 continue;
2335
David Herrmann7551cff2011-12-08 17:05:43 +01002336 if (connector->connection != DRM_MODE_CONNECTED) {
2337 drmModeFreeConnector(connector);
2338 continue;
2339 }
2340
Benjamin Franzke117483d2011-08-30 11:38:26 +02002341 connected |= (1 << connector_id);
2342
2343 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002344 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002345 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002346 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002347
2348 /* XXX: not yet needed, we die with 0 outputs */
2349 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002350 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002351 else
2352 x = 0;
2353 y = 0;
2354 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002355 connector, x, y,
2356 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002357 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002358
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002359 }
2360 drmModeFreeConnector(connector);
2361 }
2362 drmModeFreeResources(resources);
2363
2364 disconnects = ec->connector_allocator & ~connected;
2365 if (disconnects) {
2366 wl_list_for_each_safe(output, next, &ec->base.output_list,
2367 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002368 if (disconnects & (1 << output->connector_id)) {
2369 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002370 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002371 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002372 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002373 }
2374 }
2375 }
2376
2377 /* FIXME: handle zero outputs, without terminating */
2378 if (ec->connector_allocator == 0)
2379 wl_display_terminate(ec->base.wl_display);
2380}
2381
2382static int
David Herrmannd7488c22012-03-11 20:05:21 +01002383udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002384{
David Herrmannd7488c22012-03-11 20:05:21 +01002385 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002386 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002387
2388 sysnum = udev_device_get_sysnum(device);
2389 if (!sysnum || atoi(sysnum) != ec->drm.id)
2390 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002391
David Herrmann6ac52db2012-03-11 20:05:22 +01002392 val = udev_device_get_property_value(device, "HOTPLUG");
2393 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002394 return 0;
2395
David Herrmann6ac52db2012-03-11 20:05:22 +01002396 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002397}
2398
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002399static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002400udev_drm_event(int fd, uint32_t mask, void *data)
2401{
2402 struct drm_compositor *ec = data;
2403 struct udev_device *event;
2404
2405 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002406
David Herrmannd7488c22012-03-11 20:05:21 +01002407 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002408 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002409
2410 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002411
2412 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002413}
2414
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002415static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002416drm_restore(struct weston_compositor *ec)
2417{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002418 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002419}
2420
2421static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002422drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002423{
2424 struct drm_compositor *d = (struct drm_compositor *) ec;
2425
Rob Bradfordd355b802013-05-31 18:09:55 +01002426 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002427
2428 wl_event_source_remove(d->udev_drm_source);
2429 wl_event_source_remove(d->drm_source);
2430
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002431 destroy_sprites(d);
2432
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002433 weston_compositor_shutdown(ec);
2434
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002435 if (d->gbm)
2436 gbm_device_destroy(d->gbm);
2437
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002438 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002439
Rob Bradford45c15b82013-07-26 16:29:35 +01002440 close(d->drm.fd);
2441
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002442 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002443}
2444
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002445static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002446drm_compositor_set_modes(struct drm_compositor *compositor)
2447{
2448 struct drm_output *output;
2449 struct drm_mode *drm_mode;
2450 int ret;
2451
2452 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002453 if (!output->current) {
2454 /* If something that would cause the output to
2455 * switch mode happened while in another vt, we
2456 * might not have a current drm_fb. In that case,
2457 * schedule a repaint and let drm_output_repaint
2458 * handle setting the mode. */
2459 weston_output_schedule_repaint(&output->base);
2460 continue;
2461 }
2462
Hardeningff39efa2013-09-18 23:56:35 +02002463 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002464 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002465 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002466 &output->connector_id, 1,
2467 &drm_mode->mode_info);
2468 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002469 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002470 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002471 drm_mode->base.width, drm_mode->base.height,
2472 output->base.x, output->base.y);
2473 }
2474 }
2475}
2476
2477static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002478session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002479{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002480 struct weston_compositor *compositor = data;
2481 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002482 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002483 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002484
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002485 if (ec->base.session_active) {
2486 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002487 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002488 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002489 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002490 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002491 } else {
2492 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002493 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002494
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002495 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002496 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002497
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002498 /* If we have a repaint scheduled (either from a
2499 * pending pageflip or the idle handler), make sure we
2500 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002501 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002502 * further attemps at repainting. When we switch
2503 * back, we schedule a repaint, which will process
2504 * pending frame callbacks. */
2505
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002506 wl_list_for_each(output, &ec->base.output_list, base.link) {
2507 output->base.repaint_needed = 0;
2508 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002509 }
2510
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002511 output = container_of(ec->base.output_list.next,
2512 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002513
2514 wl_list_for_each(sprite, &ec->sprite_list, link)
2515 drmModeSetPlane(ec->drm.fd,
2516 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002517 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002518 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002519 };
2520}
2521
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002522static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002523switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002524{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002525 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002526
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002527 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002528}
2529
David Herrmann0af066f2012-10-29 19:21:16 +01002530/*
2531 * Find primary GPU
2532 * Some systems may have multiple DRM devices attached to a single seat. This
2533 * function loops over all devices and tries to find a PCI device with the
2534 * boot_vga sysfs attribute set to 1.
2535 * If no such device is found, the first DRM device reported by udev is used.
2536 */
2537static struct udev_device*
2538find_primary_gpu(struct drm_compositor *ec, const char *seat)
2539{
2540 struct udev_enumerate *e;
2541 struct udev_list_entry *entry;
2542 const char *path, *device_seat, *id;
2543 struct udev_device *device, *drm_device, *pci;
2544
2545 e = udev_enumerate_new(ec->udev);
2546 udev_enumerate_add_match_subsystem(e, "drm");
2547 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2548
2549 udev_enumerate_scan_devices(e);
2550 drm_device = NULL;
2551 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2552 path = udev_list_entry_get_name(entry);
2553 device = udev_device_new_from_syspath(ec->udev, path);
2554 if (!device)
2555 continue;
2556 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2557 if (!device_seat)
2558 device_seat = default_seat;
2559 if (strcmp(device_seat, seat)) {
2560 udev_device_unref(device);
2561 continue;
2562 }
2563
2564 pci = udev_device_get_parent_with_subsystem_devtype(device,
2565 "pci", NULL);
2566 if (pci) {
2567 id = udev_device_get_sysattr_value(pci, "boot_vga");
2568 if (id && !strcmp(id, "1")) {
2569 if (drm_device)
2570 udev_device_unref(drm_device);
2571 drm_device = device;
2572 break;
2573 }
2574 }
2575
2576 if (!drm_device)
2577 drm_device = device;
2578 else
2579 udev_device_unref(device);
2580 }
2581
2582 udev_enumerate_unref(e);
2583 return drm_device;
2584}
2585
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002586static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002587planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002588{
2589 struct drm_compositor *c = data;
2590
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002591 switch (key) {
2592 case KEY_C:
2593 c->cursors_are_broken ^= 1;
2594 break;
2595 case KEY_V:
2596 c->sprites_are_broken ^= 1;
2597 break;
2598 case KEY_O:
2599 c->sprites_hidden ^= 1;
2600 break;
2601 default:
2602 break;
2603 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002604}
2605
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002606#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002607static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002608recorder_destroy(struct drm_output *output)
2609{
2610 vaapi_recorder_destroy(output->recorder);
2611 output->recorder = NULL;
2612
2613 output->base.disable_planes--;
2614
2615 wl_list_remove(&output->recorder_frame_listener.link);
2616 weston_log("[libva recorder] done\n");
2617}
2618
2619static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002620recorder_frame_notify(struct wl_listener *listener, void *data)
2621{
2622 struct drm_output *output;
2623 struct drm_compositor *c;
2624 int fd, ret;
2625
2626 output = container_of(listener, struct drm_output,
2627 recorder_frame_listener);
2628 c = (struct drm_compositor *) output->base.compositor;
2629
2630 if (!output->recorder)
2631 return;
2632
2633 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2634 DRM_CLOEXEC, &fd);
2635 if (ret) {
2636 weston_log("[libva recorder] "
2637 "failed to create prime fd for front buffer\n");
2638 return;
2639 }
2640
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002641 ret = vaapi_recorder_frame(output->recorder, fd,
2642 output->current->stride);
2643 if (ret < 0) {
2644 weston_log("[libva recorder] aborted: %m\n");
2645 recorder_destroy(output);
2646 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002647}
2648
2649static void *
2650create_recorder(struct drm_compositor *c, int width, int height,
2651 const char *filename)
2652{
2653 int fd;
2654 drm_magic_t magic;
2655
2656 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2657 if (fd < 0)
2658 return NULL;
2659
2660 drmGetMagic(fd, &magic);
2661 drmAuthMagic(c->drm.fd, magic);
2662
2663 return vaapi_recorder_create(fd, width, height, filename);
2664}
2665
2666static void
2667recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2668 void *data)
2669{
2670 struct drm_compositor *c = data;
2671 struct drm_output *output;
2672 int width, height;
2673
2674 output = container_of(c->base.output_list.next,
2675 struct drm_output, base.link);
2676
2677 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002678 if (output->format != GBM_FORMAT_XRGB8888) {
2679 weston_log("failed to start vaapi recorder: "
2680 "output format not supported\n");
2681 return;
2682 }
2683
Hardeningff39efa2013-09-18 23:56:35 +02002684 width = output->base.current_mode->width;
2685 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002686
2687 output->recorder =
2688 create_recorder(c, width, height, "capture.h264");
2689 if (!output->recorder) {
2690 weston_log("failed to create vaapi recorder\n");
2691 return;
2692 }
2693
2694 output->base.disable_planes++;
2695
2696 output->recorder_frame_listener.notify = recorder_frame_notify;
2697 wl_signal_add(&output->base.frame_signal,
2698 &output->recorder_frame_listener);
2699
2700 weston_output_schedule_repaint(&output->base);
2701
2702 weston_log("[libva recorder] initialized\n");
2703 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002704 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002705 }
2706}
2707#else
2708static void
2709recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2710 void *data)
2711{
2712 weston_log("Compiled without libva support\n");
2713}
2714#endif
2715
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002716static void
2717switch_to_gl_renderer(struct drm_compositor *c)
2718{
2719 struct drm_output *output;
2720
2721 if (!c->use_pixman)
2722 return;
2723
2724 weston_log("Switching to GL renderer\n");
2725
2726 c->gbm = create_gbm_device(c->drm.fd);
2727 if (!c->gbm) {
2728 weston_log("Failed to create gbm device. "
2729 "Aborting renderer switch\n");
2730 return;
2731 }
2732
2733 wl_list_for_each(output, &c->base.output_list, base.link)
2734 pixman_renderer_output_destroy(&output->base);
2735
2736 c->base.renderer->destroy(&c->base);
2737
2738 if (drm_compositor_create_gl_renderer(c) < 0) {
2739 gbm_device_destroy(c->gbm);
2740 weston_log("Failed to create GL renderer. Quitting.\n");
2741 /* FIXME: we need a function to shutdown cleanly */
2742 assert(0);
2743 }
2744
2745 wl_list_for_each(output, &c->base.output_list, base.link)
2746 drm_output_init_egl(output, c);
2747
2748 c->use_pixman = 0;
2749}
2750
2751static void
2752renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2753 void *data)
2754{
2755 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2756
2757 switch_to_gl_renderer(c);
2758}
2759
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002760static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002761drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002762 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002763 int *argc, char *argv[],
2764 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002765{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002766 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002767 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002768 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002769 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002770 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002771 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002772
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002773 weston_log("initializing drm backend\n");
2774
Peter Huttererf3d62272013-08-08 11:57:05 +10002775 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002776 if (ec == NULL)
2777 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002778
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002779 /* KMS support for sprites is not complete yet, so disable the
2780 * functionality for now. */
2781 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002782
2783 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002784 if (get_gbm_format_from_section(section,
2785 GBM_FORMAT_XRGB8888,
2786 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002787 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002788
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002789 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002790
Daniel Stone725c2c32012-06-22 14:04:36 +01002791 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002792 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002793 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002794 goto err_base;
2795 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002796
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002797 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002798 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2799 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002800 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002801 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002802 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002803 goto err_compositor;
2804 }
2805
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002806 ec->udev = udev_new();
2807 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002808 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002809 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002810 }
2811
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002812 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002813 ec->session_listener.notify = session_notify;
2814 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002815
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002816 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002817 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002818 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002819 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002820 }
David Herrmann0af066f2012-10-29 19:21:16 +01002821 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002822
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002823 if (init_drm(ec, drm_device) < 0) {
2824 weston_log("failed to initialize kms\n");
2825 goto err_udev_dev;
2826 }
2827
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002828 if (ec->use_pixman) {
2829 if (init_pixman(ec) < 0) {
2830 weston_log("failed to initialize pixman renderer\n");
2831 goto err_udev_dev;
2832 }
2833 } else {
2834 if (init_egl(ec) < 0) {
2835 weston_log("failed to initialize egl\n");
2836 goto err_udev_dev;
2837 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002838 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002839
2840 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002841 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002842
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002843 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002844
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002845 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002846 weston_compositor_add_key_binding(&ec->base, key,
2847 MODIFIER_CTRL | MODIFIER_ALT,
2848 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002849
Jesse Barnes58ef3792012-02-23 09:45:49 -05002850 wl_list_init(&ec->sprite_list);
2851 create_sprites(ec);
2852
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002853 if (udev_input_init(&ec->input,
2854 &ec->base, ec->udev, param->seat_id) < 0) {
2855 weston_log("failed to create input devices\n");
2856 goto err_sprite;
2857 }
2858
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002859 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002860 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002861 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002862 }
2863
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002864 /* A this point we have some idea of whether or not we have a working
2865 * cursor plane. */
2866 if (!ec->cursors_are_broken)
2867 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2868
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002869 path = NULL;
2870
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002871 loop = wl_display_get_event_loop(ec->base.wl_display);
2872 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002873 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002874 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002875
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002876 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2877 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002878 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002879 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002880 }
2881 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2882 "drm", NULL);
2883 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002884 wl_event_loop_add_fd(loop,
2885 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002886 WL_EVENT_READABLE, udev_drm_event, ec);
2887
2888 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002889 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002890 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002891 }
2892
Daniel Stonea96b93c2012-06-22 14:04:37 +01002893 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002894
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002895 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002896 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002897 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002898 planes_binding, ec);
2899 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2900 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002901 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2902 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002903 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2904 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002905
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002906 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002907
2908err_udev_monitor:
2909 wl_event_source_remove(ec->udev_drm_source);
2910 udev_monitor_unref(ec->udev_monitor);
2911err_drm_source:
2912 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002913err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002914 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002915err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002916 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002917 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002918 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002919err_udev_dev:
2920 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002921err_launcher:
2922 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002923err_udev:
2924 udev_unref(ec->udev);
2925err_compositor:
2926 weston_compositor_shutdown(&ec->base);
2927err_base:
2928 free(ec);
2929 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002930}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002931
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002932WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002933backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002934 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002935{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002936 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002937
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002938 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002939 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2940 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2941 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002942 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002943 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002944 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002945
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002946 param.seat_id = default_seat;
2947
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002948 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002949
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002950 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002951}