blob: ead04a7407e6dbc206d9e6f9744f76eb071ab551 [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"
Peter Hutterer823ad332014-11-26 07:06:31 +100050#include "libinput-seat.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
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200228drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500229{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200230 struct weston_compositor *ec = output->base.compositor;
231 struct drm_compositor *c = (struct drm_compositor *)ec;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500232 int crtc;
233
234 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
235 if (c->crtcs[crtc] != output->crtc_id)
236 continue;
237
238 if (supported & (1 << crtc))
239 return -1;
240 }
241
242 return 0;
243}
244
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300245static void
246drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
247{
248 struct drm_fb *fb = data;
249 struct gbm_device *gbm = gbm_bo_get_device(bo);
250
251 if (fb->fb_id)
252 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
253
Pekka Paalanende685b82012-12-04 15:58:12 +0200254 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300255
256 free(data);
257}
258
259static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200260drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
261{
262 struct drm_fb *fb;
263 int ret;
264
265 struct drm_mode_create_dumb create_arg;
266 struct drm_mode_destroy_dumb destroy_arg;
267 struct drm_mode_map_dumb map_arg;
268
Peter Huttererf3d62272013-08-08 11:57:05 +1000269 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200270 if (!fb)
271 return NULL;
272
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700273 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200274 create_arg.bpp = 32;
275 create_arg.width = width;
276 create_arg.height = height;
277
278 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
279 if (ret)
280 goto err_fb;
281
282 fb->handle = create_arg.handle;
283 fb->stride = create_arg.pitch;
284 fb->size = create_arg.size;
285 fb->fd = ec->drm.fd;
286
287 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
288 fb->stride, fb->handle, &fb->fb_id);
289 if (ret)
290 goto err_bo;
291
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700292 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200293 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400294 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200295 if (ret)
296 goto err_add_fb;
297
298 fb->map = mmap(0, fb->size, PROT_WRITE,
299 MAP_SHARED, ec->drm.fd, map_arg.offset);
300 if (fb->map == MAP_FAILED)
301 goto err_add_fb;
302
303 return fb;
304
305err_add_fb:
306 drmModeRmFB(ec->drm.fd, fb->fb_id);
307err_bo:
308 memset(&destroy_arg, 0, sizeof(destroy_arg));
309 destroy_arg.handle = create_arg.handle;
310 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
311err_fb:
312 free(fb);
313 return NULL;
314}
315
316static void
317drm_fb_destroy_dumb(struct drm_fb *fb)
318{
319 struct drm_mode_destroy_dumb destroy_arg;
320
321 if (!fb->map)
322 return;
323
324 if (fb->fb_id)
325 drmModeRmFB(fb->fd, fb->fb_id);
326
327 weston_buffer_reference(&fb->buffer_ref, NULL);
328
329 munmap(fb->map, fb->size);
330
331 memset(&destroy_arg, 0, sizeof(destroy_arg));
332 destroy_arg.handle = fb->handle;
333 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
334
335 free(fb);
336}
337
338static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500339drm_fb_get_from_bo(struct gbm_bo *bo,
340 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341{
342 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200343 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200344 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300345 int ret;
346
347 if (fb)
348 return fb;
349
Bryce Harringtonde16d892014-11-20 22:21:57 -0800350 fb = zalloc(sizeof *fb);
351 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200352 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300353
354 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300355
356 width = gbm_bo_get_width(bo);
357 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200358 fb->stride = gbm_bo_get_stride(bo);
359 fb->handle = gbm_bo_get_handle(bo).u32;
360 fb->size = fb->stride * height;
361 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200363 if (compositor->min_width > width || width > compositor->max_width ||
364 compositor->min_height > height ||
365 height > compositor->max_height) {
366 weston_log("bo geometry out of bounds\n");
367 goto err_free;
368 }
369
370 ret = -1;
371
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200372 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200373 handles[0] = fb->handle;
374 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200375 offsets[0] = 0;
376
377 ret = drmModeAddFB2(compositor->drm.fd, width, height,
378 format, handles, pitches, offsets,
379 &fb->fb_id, 0);
380 if (ret) {
381 weston_log("addfb2 failed: %m\n");
382 compositor->no_addfb2 = 1;
383 compositor->sprites_are_broken = 1;
384 }
385 }
386
387 if (ret)
388 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200389 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200390
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300391 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200392 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200393 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300394 }
395
396 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
397
398 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200399
400err_free:
401 free(fb);
402 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300403}
404
405static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500406drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200407{
Pekka Paalanende685b82012-12-04 15:58:12 +0200408 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200409
410 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200411
Pekka Paalanende685b82012-12-04 15:58:12 +0200412 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200413}
414
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200415static void
416drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
417{
418 if (!fb)
419 return;
420
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200421 if (fb->map &&
422 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200423 drm_fb_destroy_dumb(fb);
424 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200425 if (fb->is_client_buffer)
426 gbm_bo_destroy(fb->bo);
427 else
428 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600429 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200430 }
431}
432
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500433static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434drm_output_check_scanout_format(struct drm_output *output,
435 struct weston_surface *es, struct gbm_bo *bo)
436{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200437 uint32_t format;
438 pixman_region32_t r;
439
440 format = gbm_bo_get_format(bo);
441
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700442 if (format == GBM_FORMAT_ARGB8888) {
443 /* We can scanout an ARGB buffer if the surface's
444 * opaque region covers the whole output, but we have
445 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800446 pixman_region32_init_rect(&r, 0, 0,
447 output->base.width,
448 output->base.height);
449 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200450
451 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500452 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200453
454 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500455 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700456
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000457 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700458 return format;
459
460 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200461}
462
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400463static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200464drm_output_prepare_scanout_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500465 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500466{
467 struct drm_compositor *c =
468 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500469 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200470 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300471 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500472 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500473
Jason Ekstranda7af7042013-10-12 22:38:11 -0500474 if (ev->geometry.x != output->base.x ||
475 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200476 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200477 buffer->width != output->base.current_mode->width ||
478 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200479 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500480 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400481 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500482
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400483 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700484 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500485
Rob Bradford9b101872012-09-14 23:25:41 +0100486 /* Unable to use the buffer for scanout */
487 if (!bo)
488 return NULL;
489
Jason Ekstranda7af7042013-10-12 22:38:11 -0500490 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500491 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300492 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400493 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300494 }
495
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500496 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300497 if (!output->next) {
498 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400499 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300500 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500501
Pekka Paalanende685b82012-12-04 15:58:12 +0200502 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500503
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400504 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500505}
506
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500507static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200508drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400509{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200510 struct drm_compositor *c =
511 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300512 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400513
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200514 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300516 bo = gbm_surface_lock_front_buffer(output->surface);
517 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200518 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400519 return;
520 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300521
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000522 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300523 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200524 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300525 gbm_surface_release_buffer(output->surface, bo);
526 return;
527 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400528}
529
530static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200531drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
532{
533 struct weston_compositor *ec = output->base.compositor;
534 pixman_region32_t total_damage, previous_damage;
535
536 pixman_region32_init(&total_damage);
537 pixman_region32_init(&previous_damage);
538
539 pixman_region32_copy(&previous_damage, damage);
540
541 pixman_region32_union(&total_damage, damage, &output->previous_damage);
542 pixman_region32_copy(&output->previous_damage, &previous_damage);
543
544 output->current_image ^= 1;
545
546 output->next = output->dumb[output->current_image];
547 pixman_renderer_output_set_buffer(&output->base,
548 output->image[output->current_image]);
549
550 ec->renderer->repaint_output(&output->base, &total_damage);
551
552 pixman_region32_fini(&total_damage);
553 pixman_region32_fini(&previous_damage);
554}
555
556static void
557drm_output_render(struct drm_output *output, pixman_region32_t *damage)
558{
559 struct drm_compositor *c =
560 (struct drm_compositor *) output->base.compositor;
561
562 if (c->use_pixman)
563 drm_output_render_pixman(output, damage);
564 else
565 drm_output_render_gl(output, damage);
566
567 pixman_region32_subtract(&c->base.primary_plane.damage,
568 &c->base.primary_plane.damage, damage);
569}
570
571static void
Richard Hughese7299962013-05-01 21:52:12 +0100572drm_output_set_gamma(struct weston_output *output_base,
573 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
574{
575 int rc;
576 struct drm_output *output = (struct drm_output *) output_base;
577 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
578
579 /* check */
580 if (output_base->gamma_size != size)
581 return;
582 if (!output->original_crtc)
583 return;
584
585 rc = drmModeCrtcSetGamma(compositor->drm.fd,
586 output->crtc_id,
587 size, r, g, b);
588 if (rc)
589 weston_log("set gamma failed: %m\n");
590}
591
David Herrmann1edf44c2013-10-22 17:11:26 +0200592static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500593drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400594 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100595{
596 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500597 struct drm_compositor *compositor =
598 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400600 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100602
Xiong Zhangabd5d472013-10-11 14:43:07 +0800603 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200604 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800605
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300606 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400607 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300608 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200609 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100610
Hardeningff39efa2013-09-18 23:56:35 +0200611 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200612 if (!output->current ||
613 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400614 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300615 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400616 &output->connector_id, 1,
617 &mode->mode_info);
618 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200619 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200620 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400621 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300622 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200623 }
624
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500625 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300626 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500627 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200628 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200629 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500630 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100631
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300632 output->page_flip_pending = 1;
633
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400634 drm_output_set_cursor(output);
635
Jesse Barnes58ef3792012-02-23 09:45:49 -0500636 /*
637 * Now, update all the sprite surfaces
638 */
639 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200640 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 drmVBlank vbl = {
642 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
643 .request.sequence = 1,
644 };
645
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200646 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200647 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500648 continue;
649
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200650 if (s->next && !compositor->sprites_hidden)
651 fb_id = s->next->fb_id;
652
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200654 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655 s->dest_x, s->dest_y,
656 s->dest_w, s->dest_h,
657 s->src_x, s->src_y,
658 s->src_w, s->src_h);
659 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200660 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500661 ret, strerror(errno));
662
Rob Clark5ca1a472012-08-08 20:27:37 -0500663 if (output->pipe > 0)
664 vbl.request.type |= DRM_VBLANK_SECONDARY;
665
Jesse Barnes58ef3792012-02-23 09:45:49 -0500666 /*
667 * Queue a vblank signal so we know when the surface
668 * becomes active on the display or has been replaced.
669 */
670 vbl.request.signal = (unsigned long)s;
671 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
672 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200673 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500674 ret, strerror(errno));
675 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300676
677 s->output = output;
678 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500679 }
680
David Herrmann1edf44c2013-10-22 17:11:26 +0200681 return 0;
682
683err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800684 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200685 if (output->next) {
686 drm_output_release_fb(output, output->next);
687 output->next = NULL;
688 }
689
690 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400691}
692
693static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200694drm_output_start_repaint_loop(struct weston_output *output_base)
695{
696 struct drm_output *output = (struct drm_output *) output_base;
697 struct drm_compositor *compositor = (struct drm_compositor *)
698 output_base->compositor;
699 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300700 struct timespec ts;
701
Xiong Zhangabd5d472013-10-11 14:43:07 +0800702 if (output->destroy_pending)
703 return;
704
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300705 if (!output->current) {
706 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200707 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300708 }
709
710 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200711
712 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
713 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
714 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200715 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200716 }
David Herrmann3c688c52013-10-22 17:11:25 +0200717
718 return;
719
720finish_frame:
721 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400722 clock_gettime(compositor->base.presentation_clock, &ts);
723 weston_output_finish_frame(output_base, &ts);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200724}
725
726static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400727drm_output_update_msc(struct drm_output *output, unsigned int seq)
728{
729 uint64_t msc_hi = output->base.msc >> 32;
730
731 if (seq < (output->base.msc & 0xffffffff))
732 msc_hi++;
733
734 output->base.msc = (msc_hi << 32) + seq;
735}
736
737static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500738vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
739 void *data)
740{
741 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300742 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400743 struct timespec ts;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300744
Pekka Paalanen641307c2014-09-23 22:08:47 -0400745 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300746 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500747
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200748 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200749 s->current = s->next;
750 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300751
752 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400753 ts.tv_sec = sec;
754 ts.tv_nsec = usec * 1000;
755 weston_output_finish_frame(&output->base, &ts);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300756 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500757}
758
759static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800760drm_output_destroy(struct weston_output *output_base);
761
762static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400763page_flip_handler(int fd, unsigned int frame,
764 unsigned int sec, unsigned int usec, void *data)
765{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200766 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400767 struct timespec ts;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400768
Pekka Paalanen641307c2014-09-23 22:08:47 -0400769 drm_output_update_msc(output, frame);
770
Jonas Ådahle5a12252013-04-05 23:07:11 +0200771 /* We don't set page_flip_pending on start_repaint_loop, in that case
772 * we just want to page flip to the current buffer to get an accurate
773 * timestamp */
774 if (output->page_flip_pending) {
775 drm_output_release_fb(output, output->current);
776 output->current = output->next;
777 output->next = NULL;
778 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300779
Jonas Ådahle5a12252013-04-05 23:07:11 +0200780 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400781
Xiong Zhangabd5d472013-10-11 14:43:07 +0800782 if (output->destroy_pending)
783 drm_output_destroy(&output->base);
784 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400785 ts.tv_sec = sec;
786 ts.tv_nsec = usec * 1000;
787 weston_output_finish_frame(&output->base, &ts);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300788
789 /* We can't call this from frame_notify, because the output's
790 * repaint needed flag is cleared just after that */
791 if (output->recorder)
792 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300793 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200794}
795
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500796static uint32_t
797drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500798 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500800 uint32_t i, format;
801
802 format = gbm_bo_get_format(bo);
803
804 if (format == GBM_FORMAT_ARGB8888) {
805 pixman_region32_t r;
806
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500807 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600808 ev->surface->width,
809 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500810 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500811
812 if (!pixman_region32_not_empty(&r))
813 format = GBM_FORMAT_XRGB8888;
814
815 pixman_region32_fini(&r);
816 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817
818 for (i = 0; i < s->count_formats; i++)
819 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500820 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821
822 return 0;
823}
824
825static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500826drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500827{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500828 return !ev->transform.enabled ||
829 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500830}
831
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400832static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200833drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500834 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200836 struct weston_compositor *ec = output->base.compositor;
837 struct drm_compositor *c = (struct drm_compositor *)ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200838 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839 struct drm_sprite *s;
840 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500842 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200843 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400845 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500846
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200847 if (c->gbm == NULL)
848 return NULL;
849
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200850 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200851 return NULL;
852
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200853 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200854 return NULL;
855
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500856 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400857 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500858
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200859 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400860 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300861
Jason Ekstranda7af7042013-10-12 22:38:11 -0500862 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400863 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500864
Jason Ekstranda7af7042013-10-12 22:38:11 -0500865 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200866 return NULL;
867
Jason Ekstranda7af7042013-10-12 22:38:11 -0500868 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500869 return NULL;
870
Jason Ekstranda7af7042013-10-12 22:38:11 -0500871 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400872 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500873
Jesse Barnes58ef3792012-02-23 09:45:49 -0500874 wl_list_for_each(s, &c->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200875 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500876 continue;
877
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200878 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500879 found = 1;
880 break;
881 }
882 }
883
884 /* No sprites available */
885 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400886 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500887
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400888 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500889 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700890 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400891 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400892 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400893
Jason Ekstranda7af7042013-10-12 22:38:11 -0500894 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500895 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200896 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400897 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500898 }
899
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200900 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200901 if (!s->next) {
902 gbm_bo_destroy(bo);
903 return NULL;
904 }
905
Jason Ekstranda7af7042013-10-12 22:38:11 -0500906 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500907
Jason Ekstranda7af7042013-10-12 22:38:11 -0500908 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400909 s->plane.x = box->x1;
910 s->plane.y = box->y1;
911
Jesse Barnes58ef3792012-02-23 09:45:49 -0500912 /*
913 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500914 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500915 * for us already).
916 */
917 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500918 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200919 &output->base.region);
920 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500921 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200922 tbox = weston_transformed_rect(output->base.width,
923 output->base.height,
924 output->base.transform,
925 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200926 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200927 s->dest_x = tbox.x1;
928 s->dest_y = tbox.y1;
929 s->dest_w = tbox.x2 - tbox.x1;
930 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931 pixman_region32_fini(&dest_rect);
932
933 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500934 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200935 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500936 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400937
Jason Ekstranda7af7042013-10-12 22:38:11 -0500938 weston_view_from_global_fixed(ev,
939 wl_fixed_from_int(box->x1),
940 wl_fixed_from_int(box->y1),
941 &sx1, &sy1);
942 weston_view_from_global_fixed(ev,
943 wl_fixed_from_int(box->x2),
944 wl_fixed_from_int(box->y2),
945 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400946
947 if (sx1 < 0)
948 sx1 = 0;
949 if (sy1 < 0)
950 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600951 if (sx2 > wl_fixed_from_int(ev->surface->width))
952 sx2 = wl_fixed_from_int(ev->surface->width);
953 if (sy2 > wl_fixed_from_int(ev->surface->height))
954 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400955
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200956 tbox.x1 = sx1;
957 tbox.y1 = sy1;
958 tbox.x2 = sx2;
959 tbox.y2 = sy2;
960
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600961 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
962 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200963 viewport->buffer.transform,
964 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100965 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200966
967 s->src_x = tbox.x1 << 8;
968 s->src_y = tbox.y1 << 8;
969 s->src_w = (tbox.x2 - tbox.x1) << 8;
970 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500971 pixman_region32_fini(&src_rect);
972
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400973 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500974}
975
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400976static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200977drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500978 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500979{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400980 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200981 (struct drm_compositor *)output->base.compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100982 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400983
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200984 if (c->gbm == NULL)
985 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200986 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
987 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200988 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +0100989 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500990 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400991 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200992 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400993 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500994 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400995 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500996 if (ev->surface->buffer_ref.buffer == NULL ||
997 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600998 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400999 return NULL;
1000
Jason Ekstranda7af7042013-10-12 22:38:11 -05001001 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001002
1003 return &output->cursor_plane;
1004}
1005
1006static void
1007drm_output_set_cursor(struct drm_output *output)
1008{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001009 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001010 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001011 struct drm_compositor *c =
1012 (struct drm_compositor *) output->base.compositor;
1013 EGLint handle, stride;
1014 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001015 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001016 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001017 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001018
Jason Ekstranda7af7042013-10-12 22:38:11 -05001019 output->cursor_view = NULL;
1020 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001021 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1022 return;
1023 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001024
Neil Robertse5051712013-11-13 15:44:06 +00001025 buffer = ev->surface->buffer_ref.buffer;
1026
1027 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001028 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001029 pixman_region32_fini(&output->cursor_plane.damage);
1030 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001031 output->current_cursor ^= 1;
1032 bo = output->cursor_bo[output->current_cursor];
1033 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001034 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1035 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1036 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001037 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001038 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001039 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001040 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001041
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001042 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001043 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001044
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001045 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001046 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1047 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001048 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001049 c->cursors_are_broken = 1;
1050 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001051 }
1052
Jason Ekstranda7af7042013-10-12 22:38:11 -05001053 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1054 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001055 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001056 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001057 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001058 c->cursors_are_broken = 1;
1059 }
1060
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001061 output->cursor_plane.x = x;
1062 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001063 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001064}
1065
Jesse Barnes58ef3792012-02-23 09:45:49 -05001066static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001067drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001068{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001069 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001070 (struct drm_compositor *)output_base->compositor;
1071 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001072 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001073 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001074 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001075
1076 /*
1077 * Find a surface for each sprite in the output using some heuristics:
1078 * 1) size
1079 * 2) frequency of update
1080 * 3) opacity (though some hw might support alpha blending)
1081 * 4) clipping (this can be fixed with color keys)
1082 *
1083 * The idea is to save on blitting since this should save power.
1084 * If we can get a large video surface on the sprite for example,
1085 * the main display surface may not need to update at all, and
1086 * the client buffer can be used directly for the sprite surface
1087 * as we do for flipping full screen surfaces.
1088 */
1089 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001090 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001091
Jason Ekstranda7af7042013-10-12 22:38:11 -05001092 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001093 struct weston_surface *es = ev->surface;
1094
1095 /* Test whether this buffer can ever go into a plane:
1096 * non-shm, or small enough to be a cursor.
1097 *
1098 * Also, keep a reference when using the pixman renderer.
1099 * That makes it possible to do a seamless switch to the GL
1100 * renderer and since the pixman renderer keeps a reference
1101 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001102 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001103 if (c->use_pixman ||
1104 (es->buffer_ref.buffer &&
1105 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001106 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001107 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001108 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001109 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001110
Jesse Barnes58ef3792012-02-23 09:45:49 -05001111 pixman_region32_init(&surface_overlap);
1112 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001113 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001114
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001115 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001116 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001117 next_plane = primary;
1118 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001119 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001120 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001121 next_plane = drm_output_prepare_scanout_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_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001124 if (next_plane == NULL)
1125 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001126 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001127 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001128 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001129 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001130
Jesse Barnes58ef3792012-02-23 09:45:49 -05001131 pixman_region32_fini(&surface_overlap);
1132 }
1133 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001134}
1135
Matt Roper361d2ad2011-08-29 13:52:23 -07001136static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001137drm_output_fini_pixman(struct drm_output *output);
1138
1139static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001140drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001141{
1142 struct drm_output *output = (struct drm_output *) output_base;
1143 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001144 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001145 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001146
Xiong Zhangabd5d472013-10-11 14:43:07 +08001147 if (output->page_flip_pending) {
1148 output->destroy_pending = 1;
1149 weston_log("destroy output while page flip pending\n");
1150 return;
1151 }
1152
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001153 if (output->backlight)
1154 backlight_destroy(output->backlight);
1155
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001156 drmModeFreeProperty(output->dpms_prop);
1157
Matt Roper361d2ad2011-08-29 13:52:23 -07001158 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001159 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001160
1161 /* Restore original CRTC state */
1162 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001163 origcrtc->x, origcrtc->y,
1164 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001165 drmModeFreeCrtc(origcrtc);
1166
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001167 c->crtc_allocator &= ~(1 << output->crtc_id);
1168 c->connector_allocator &= ~(1 << output->connector_id);
1169
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001170 if (c->use_pixman) {
1171 drm_output_fini_pixman(output);
1172 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001173 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001174 gbm_surface_destroy(output->surface);
1175 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001176
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001177 weston_plane_release(&output->fb_plane);
1178 weston_plane_release(&output->cursor_plane);
1179
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001180 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001181
Matt Roper361d2ad2011-08-29 13:52:23 -07001182 free(output);
1183}
1184
Alex Wub7b8bda2012-04-17 17:20:48 +08001185static struct drm_mode *
1186choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1187{
1188 struct drm_mode *tmp_mode = NULL, *mode;
1189
Hardeningff39efa2013-09-18 23:56:35 +02001190 if (output->base.current_mode->width == target_mode->width &&
1191 output->base.current_mode->height == target_mode->height &&
1192 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001193 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001194 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001195
1196 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1197 if (mode->mode_info.hdisplay == target_mode->width &&
1198 mode->mode_info.vdisplay == target_mode->height) {
1199 if (mode->mode_info.vrefresh == target_mode->refresh ||
1200 target_mode->refresh == 0) {
1201 return mode;
1202 } else if (!tmp_mode)
1203 tmp_mode = mode;
1204 }
1205 }
1206
1207 return tmp_mode;
1208}
1209
1210static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001211drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001212static int
1213drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001214
1215static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001216drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1217{
1218 struct drm_output *output;
1219 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001220 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001221
1222 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001223 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001224 return -1;
1225 }
1226
1227 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001228 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001229 return -1;
1230 }
1231
1232 ec = (struct drm_compositor *)output_base->compositor;
1233 output = (struct drm_output *)output_base;
1234 drm_mode = choose_mode (output, mode);
1235
1236 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001237 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001238 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001239 }
1240
Hardeningff39efa2013-09-18 23:56:35 +02001241 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001242 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001243
Hardeningff39efa2013-09-18 23:56:35 +02001244 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001245
Hardeningff39efa2013-09-18 23:56:35 +02001246 output->base.current_mode = &drm_mode->base;
1247 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001248 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1249
Alex Wub7b8bda2012-04-17 17:20:48 +08001250 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001251 drm_output_release_fb(output, output->current);
1252 drm_output_release_fb(output, output->next);
1253 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001254
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001255 if (ec->use_pixman) {
1256 drm_output_fini_pixman(output);
1257 if (drm_output_init_pixman(output, ec) < 0) {
1258 weston_log("failed to init output pixman state with "
1259 "new mode\n");
1260 return -1;
1261 }
1262 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001263 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001264 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001265
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001266 if (drm_output_init_egl(output, ec) < 0) {
1267 weston_log("failed to init output egl state with "
1268 "new mode");
1269 return -1;
1270 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001271 }
1272
Alex Wub7b8bda2012-04-17 17:20:48 +08001273 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001274}
1275
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001276static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001277on_drm_input(int fd, uint32_t mask, void *data)
1278{
1279 drmEventContext evctx;
1280
1281 memset(&evctx, 0, sizeof evctx);
1282 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1283 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001284 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001285 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001286
1287 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001288}
1289
1290static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001291init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001292{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001293 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001294 uint64_t cap;
1295 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001296 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001297
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001298 sysnum = udev_device_get_sysnum(device);
1299 if (sysnum)
1300 ec->drm.id = atoi(sysnum);
1301 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001302 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001303 return -1;
1304 }
1305
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001306 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001307 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001308 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001309 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001310 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001311 udev_device_get_devnode(device));
1312 return -1;
1313 }
1314
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001315 weston_log("using %s\n", filename);
1316
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001317 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001318 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001319
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001320 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1321 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001322 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001323 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001324 clk_id = CLOCK_REALTIME;
1325
1326 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1327 weston_log("Error: failed to set presentation clock %d.\n",
1328 clk_id);
1329 return -1;
1330 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001331
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001332 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1333 if (ret == 0)
1334 ec->cursor_width = cap;
1335 else
1336 ec->cursor_width = 64;
1337
1338 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1339 if (ret == 0)
1340 ec->cursor_height = cap;
1341 else
1342 ec->cursor_height = 64;
1343
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001344 return 0;
1345}
1346
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001347static struct gbm_device *
1348create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001349{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001350 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001351
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001352 gl_renderer = weston_load_module("gl-renderer.so",
1353 "gl_renderer_interface");
1354 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001355 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001356
1357 /* GBM will load a dri driver, but even though they need symbols from
1358 * libglapi, in some version of Mesa they are not linked to it. Since
1359 * only the gl-renderer module links to it, the call above won't make
1360 * these symbols globally available, and loading the DRI driver fails.
1361 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1362 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1363
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001364 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001365
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001366 return gbm;
1367}
1368
1369static int
1370drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1371{
1372 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001373
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001374 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001375 if (gl_renderer->create(&ec->base, ec->gbm,
1376 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001377 return -1;
1378 }
1379
1380 return 0;
1381}
1382
1383static int
1384init_egl(struct drm_compositor *ec)
1385{
1386 ec->gbm = create_gbm_device(ec->drm.fd);
1387
1388 if (!ec->gbm)
1389 return -1;
1390
1391 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001392 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001393 return -1;
1394 }
1395
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001396 return 0;
1397}
1398
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001399static int
1400init_pixman(struct drm_compositor *ec)
1401{
1402 return pixman_renderer_init(&ec->base);
1403}
1404
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001405static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001406drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001407{
1408 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001409 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001410
1411 mode = malloc(sizeof *mode);
1412 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001413 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001414
1415 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001416 mode->base.width = info->hdisplay;
1417 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001418
1419 /* Calculate higher precision (mHz) refresh rate */
1420 refresh = (info->clock * 1000000LL / info->htotal +
1421 info->vtotal / 2) / info->vtotal;
1422
1423 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1424 refresh *= 2;
1425 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1426 refresh /= 2;
1427 if (info->vscan > 1)
1428 refresh /= info->vscan;
1429
1430 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001431 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001432
1433 if (info->type & DRM_MODE_TYPE_PREFERRED)
1434 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1435
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001436 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1437
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001438 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001439}
1440
1441static int
1442drm_subpixel_to_wayland(int drm_value)
1443{
1444 switch (drm_value) {
1445 default:
1446 case DRM_MODE_SUBPIXEL_UNKNOWN:
1447 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1448 case DRM_MODE_SUBPIXEL_NONE:
1449 return WL_OUTPUT_SUBPIXEL_NONE;
1450 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1451 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1452 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1453 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1454 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1455 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1456 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1457 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1458 }
1459}
1460
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001461/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001462static uint32_t
1463drm_get_backlight(struct drm_output *output)
1464{
1465 long brightness, max_brightness, norm;
1466
1467 brightness = backlight_get_brightness(output->backlight);
1468 max_brightness = backlight_get_max_brightness(output->backlight);
1469
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001470 /* convert it on a scale of 0 to 255 */
1471 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001472
1473 return (uint32_t) norm;
1474}
1475
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001476/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001477static void
1478drm_set_backlight(struct weston_output *output_base, uint32_t value)
1479{
1480 struct drm_output *output = (struct drm_output *) output_base;
1481 long max_brightness, new_brightness;
1482
1483 if (!output->backlight)
1484 return;
1485
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001486 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001487 return;
1488
1489 max_brightness = backlight_get_max_brightness(output->backlight);
1490
1491 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001492 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001493
1494 backlight_set_brightness(output->backlight, new_brightness);
1495}
1496
1497static drmModePropertyPtr
1498drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1499{
1500 drmModePropertyPtr props;
1501 int i;
1502
1503 for (i = 0; i < connector->count_props; i++) {
1504 props = drmModeGetProperty(fd, connector->props[i]);
1505 if (!props)
1506 continue;
1507
1508 if (!strcmp(props->name, name))
1509 return props;
1510
1511 drmModeFreeProperty(props);
1512 }
1513
1514 return NULL;
1515}
1516
1517static void
1518drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1519{
1520 struct drm_output *output = (struct drm_output *) output_base;
1521 struct weston_compositor *ec = output_base->compositor;
1522 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001523
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001524 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001525 return;
1526
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001527 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1528 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001529}
1530
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001531static const char *connector_type_names[] = {
1532 "None",
1533 "VGA",
1534 "DVI",
1535 "DVI",
1536 "DVI",
1537 "Composite",
1538 "TV",
1539 "LVDS",
1540 "CTV",
1541 "DIN",
1542 "DP",
1543 "HDMI",
1544 "HDMI",
1545 "TV",
1546 "eDP",
1547};
1548
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001549static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001550find_crtc_for_connector(struct drm_compositor *ec,
1551 drmModeRes *resources, drmModeConnector *connector)
1552{
1553 drmModeEncoder *encoder;
1554 uint32_t possible_crtcs;
1555 int i, j;
1556
1557 for (j = 0; j < connector->count_encoders; j++) {
1558 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1559 if (encoder == NULL) {
1560 weston_log("Failed to get encoder.\n");
1561 return -1;
1562 }
1563 possible_crtcs = encoder->possible_crtcs;
1564 drmModeFreeEncoder(encoder);
1565
1566 for (i = 0; i < resources->count_crtcs; i++) {
1567 if (possible_crtcs & (1 << i) &&
1568 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1569 return i;
1570 }
1571 }
1572
1573 return -1;
1574}
1575
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001576/* Init output state that depends on gl or gbm */
1577static int
1578drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1579{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001580 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001581 int i, flags;
1582
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001583 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001584 output->base.current_mode->width,
1585 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001586 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001587 GBM_BO_USE_SCANOUT |
1588 GBM_BO_USE_RENDERING);
1589 if (!output->surface) {
1590 weston_log("failed to create gbm surface\n");
1591 return -1;
1592 }
1593
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001594 if (gl_renderer->output_create(&output->base, output->surface,
1595 gl_renderer->opaque_attribs,
1596 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001597 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001598 gbm_surface_destroy(output->surface);
1599 return -1;
1600 }
1601
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001602 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001603
1604 for (i = 0; i < 2; i++) {
1605 if (output->cursor_bo[i])
1606 continue;
1607
1608 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001609 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1610 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001611 }
1612
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001613 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1614 weston_log("cursor buffers unavailable, using gl cursors\n");
1615 ec->cursors_are_broken = 1;
1616 }
1617
1618 return 0;
1619}
1620
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001621static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001622drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1623{
Hardeningff39efa2013-09-18 23:56:35 +02001624 int w = output->base.current_mode->width;
1625 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001626 unsigned int i;
1627
1628 /* FIXME error checking */
1629
1630 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001631 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001632 if (!output->dumb[i])
1633 goto err;
1634
1635 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001636 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001637 output->dumb[i]->map,
1638 output->dumb[i]->stride);
1639 if (!output->image[i])
1640 goto err;
1641 }
1642
1643 if (pixman_renderer_output_create(&output->base) < 0)
1644 goto err;
1645
1646 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001647 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001648
1649 return 0;
1650
1651err:
1652 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1653 if (output->dumb[i])
1654 drm_fb_destroy_dumb(output->dumb[i]);
1655 if (output->image[i])
1656 pixman_image_unref(output->image[i]);
1657
1658 output->dumb[i] = NULL;
1659 output->image[i] = NULL;
1660 }
1661
1662 return -1;
1663}
1664
1665static void
1666drm_output_fini_pixman(struct drm_output *output)
1667{
1668 unsigned int i;
1669
1670 pixman_renderer_output_destroy(&output->base);
1671 pixman_region32_fini(&output->previous_damage);
1672
1673 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1674 drm_fb_destroy_dumb(output->dumb[i]);
1675 pixman_image_unref(output->image[i]);
1676 output->dumb[i] = NULL;
1677 output->image[i] = NULL;
1678 }
1679}
1680
Richard Hughes2b2092a2013-04-24 14:58:02 +01001681static void
1682edid_parse_string(const uint8_t *data, char text[])
1683{
1684 int i;
1685 int replaced = 0;
1686
1687 /* this is always 12 bytes, but we can't guarantee it's null
1688 * terminated or not junk. */
1689 strncpy(text, (const char *) data, 12);
1690
1691 /* remove insane chars */
1692 for (i = 0; text[i] != '\0'; i++) {
1693 if (text[i] == '\n' ||
1694 text[i] == '\r') {
1695 text[i] = '\0';
1696 break;
1697 }
1698 }
1699
1700 /* ensure string is printable */
1701 for (i = 0; text[i] != '\0'; i++) {
1702 if (!isprint(text[i])) {
1703 text[i] = '-';
1704 replaced++;
1705 }
1706 }
1707
1708 /* if the string is random junk, ignore the string */
1709 if (replaced > 4)
1710 text[0] = '\0';
1711}
1712
1713#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1714#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1715#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1716#define EDID_OFFSET_DATA_BLOCKS 0x36
1717#define EDID_OFFSET_LAST_BLOCK 0x6c
1718#define EDID_OFFSET_PNPID 0x08
1719#define EDID_OFFSET_SERIAL 0x0c
1720
1721static int
1722edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1723{
1724 int i;
1725 uint32_t serial_number;
1726
1727 /* check header */
1728 if (length < 128)
1729 return -1;
1730 if (data[0] != 0x00 || data[1] != 0xff)
1731 return -1;
1732
1733 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1734 * /--08--\/--09--\
1735 * 7654321076543210
1736 * |\---/\---/\---/
1737 * R C1 C2 C3 */
1738 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1739 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1740 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1741 edid->pnp_id[3] = '\0';
1742
1743 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1744 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1745 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1746 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1747 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1748 if (serial_number > 0)
1749 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1750
1751 /* parse EDID data */
1752 for (i = EDID_OFFSET_DATA_BLOCKS;
1753 i <= EDID_OFFSET_LAST_BLOCK;
1754 i += 18) {
1755 /* ignore pixel clock data */
1756 if (data[i] != 0)
1757 continue;
1758 if (data[i+2] != 0)
1759 continue;
1760
1761 /* any useful blocks? */
1762 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1763 edid_parse_string(&data[i+5],
1764 edid->monitor_name);
1765 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1766 edid_parse_string(&data[i+5],
1767 edid->serial_number);
1768 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1769 edid_parse_string(&data[i+5],
1770 edid->eisa_id);
1771 }
1772 }
1773 return 0;
1774}
1775
1776static void
1777find_and_parse_output_edid(struct drm_compositor *ec,
1778 struct drm_output *output,
1779 drmModeConnector *connector)
1780{
1781 drmModePropertyBlobPtr edid_blob = NULL;
1782 drmModePropertyPtr property;
1783 int i;
1784 int rc;
1785
1786 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1787 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1788 if (!property)
1789 continue;
1790 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1791 !strcmp(property->name, "EDID")) {
1792 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1793 connector->prop_values[i]);
1794 }
1795 drmModeFreeProperty(property);
1796 }
1797 if (!edid_blob)
1798 return;
1799
1800 rc = edid_parse(&output->edid,
1801 edid_blob->data,
1802 edid_blob->length);
1803 if (!rc) {
1804 weston_log("EDID data '%s', '%s', '%s'\n",
1805 output->edid.pnp_id,
1806 output->edid.monitor_name,
1807 output->edid.serial_number);
1808 if (output->edid.pnp_id[0] != '\0')
1809 output->base.make = output->edid.pnp_id;
1810 if (output->edid.monitor_name[0] != '\0')
1811 output->base.model = output->edid.monitor_name;
1812 if (output->edid.serial_number[0] != '\0')
1813 output->base.serial_number = output->edid.serial_number;
1814 }
1815 drmModeFreePropertyBlob(edid_blob);
1816}
1817
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001818
1819
1820static int
1821parse_modeline(const char *s, drmModeModeInfo *mode)
1822{
1823 char hsync[16];
1824 char vsync[16];
1825 float fclock;
1826
1827 mode->type = DRM_MODE_TYPE_USERDEF;
1828 mode->hskew = 0;
1829 mode->vscan = 0;
1830 mode->vrefresh = 0;
1831 mode->flags = 0;
1832
Rob Bradford307e09e2013-07-26 16:29:40 +01001833 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001834 &fclock,
1835 &mode->hdisplay,
1836 &mode->hsync_start,
1837 &mode->hsync_end,
1838 &mode->htotal,
1839 &mode->vdisplay,
1840 &mode->vsync_start,
1841 &mode->vsync_end,
1842 &mode->vtotal, hsync, vsync) != 11)
1843 return -1;
1844
1845 mode->clock = fclock * 1000;
1846 if (strcmp(hsync, "+hsync") == 0)
1847 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1848 else if (strcmp(hsync, "-hsync") == 0)
1849 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1850 else
1851 return -1;
1852
1853 if (strcmp(vsync, "+vsync") == 0)
1854 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1855 else if (strcmp(vsync, "-vsync") == 0)
1856 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1857 else
1858 return -1;
1859
1860 return 0;
1861}
1862
Rob Bradford66bd9f52013-06-25 18:56:42 +01001863static void
1864setup_output_seat_constraint(struct drm_compositor *ec,
1865 struct weston_output *output,
1866 const char *s)
1867{
1868 if (strcmp(s, "") != 0) {
1869 struct udev_seat *seat;
1870
Jonas Ådahl58e15862014-03-12 22:08:40 +01001871 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001872 if (seat)
1873 seat->base.output = output;
1874
1875 if (seat && seat->base.pointer)
1876 weston_pointer_clamp(seat->base.pointer,
1877 &seat->base.pointer->x,
1878 &seat->base.pointer->y);
1879 }
1880}
1881
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001882static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001883get_gbm_format_from_section(struct weston_config_section *section,
1884 uint32_t default_value,
1885 uint32_t *format)
1886{
1887 char *s;
1888 int ret = 0;
1889
1890 weston_config_section_get_string(section,
1891 "gbm-format", &s, NULL);
1892
1893 if (s == NULL)
1894 *format = default_value;
1895 else if (strcmp(s, "xrgb8888") == 0)
1896 *format = GBM_FORMAT_XRGB8888;
1897 else if (strcmp(s, "rgb565") == 0)
1898 *format = GBM_FORMAT_RGB565;
1899 else if (strcmp(s, "xrgb2101010") == 0)
1900 *format = GBM_FORMAT_XRGB2101010;
1901 else {
1902 weston_log("fatal: unrecognized pixel format: %s\n", s);
1903 ret = -1;
1904 }
1905
1906 free(s);
1907
1908 return ret;
1909}
1910
1911static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001912create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001913 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001914 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001915 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001916{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001917 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001918 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001919 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001920 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001921 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001922 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001923 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001924 int i, width, height, scale;
1925 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001926 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001927 enum output_config config;
1928 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001929
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001930 i = find_crtc_for_connector(ec, resources, connector);
1931 if (i < 0) {
1932 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001933 return -1;
1934 }
1935
Peter Huttererf3d62272013-08-08 11:57:05 +10001936 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001937 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001938 return -1;
1939
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001940 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1941 output->base.make = "unknown";
1942 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001943 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001944 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001945
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001946 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1947 type_name = connector_type_names[connector->connector_type];
1948 else
1949 type_name = "UNKNOWN";
1950 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001951 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001952
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001953 section = weston_config_get_section(ec->base.config, "output", "name",
1954 output->base.name);
1955 weston_config_section_get_string(section, "mode", &s, "preferred");
1956 if (strcmp(s, "off") == 0)
1957 config = OUTPUT_CONFIG_OFF;
1958 else if (strcmp(s, "preferred") == 0)
1959 config = OUTPUT_CONFIG_PREFERRED;
1960 else if (strcmp(s, "current") == 0)
1961 config = OUTPUT_CONFIG_CURRENT;
1962 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1963 config = OUTPUT_CONFIG_MODE;
1964 else if (parse_modeline(s, &modeline) == 0)
1965 config = OUTPUT_CONFIG_MODELINE;
1966 else {
1967 weston_log("Invalid mode \"%s\" for output %s\n",
1968 s, output->base.name);
1969 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001970 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001971 free(s);
1972
1973 weston_config_section_get_int(section, "scale", &scale, 1);
1974 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05001975 if (weston_parse_transform(s, &transform) < 0)
1976 weston_log("Invalid transform \"%s\" for output %s\n",
1977 s, output->base.name);
1978
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001979 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001980
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001981 if (get_gbm_format_from_section(section,
1982 ec->format,
1983 &output->format) == -1)
1984 output->format = ec->format;
1985
Rob Bradford66bd9f52013-06-25 18:56:42 +01001986 weston_config_section_get_string(section, "seat", &s, "");
1987 setup_output_seat_constraint(ec, &output->base, s);
1988 free(s);
1989
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001990 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001991 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001992 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001993 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001994 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001995
Matt Roper361d2ad2011-08-29 13:52:23 -07001996 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001997 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001998
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001999 /* Get the current mode on the crtc that's currently driving
2000 * this connector. */
2001 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002002 memset(&crtc_mode, 0, sizeof crtc_mode);
2003 if (encoder != NULL) {
2004 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2005 drmModeFreeEncoder(encoder);
2006 if (crtc == NULL)
2007 goto err_free;
2008 if (crtc->mode_valid)
2009 crtc_mode = crtc->mode;
2010 drmModeFreeCrtc(crtc);
2011 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002012
David Herrmann0f0d54e2011-12-08 17:05:45 +01002013 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002014 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002015 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002016 goto err_free;
2017 }
2018
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002019 if (config == OUTPUT_CONFIG_OFF) {
2020 weston_log("Disabling output %s\n", output->base.name);
2021 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2022 0, 0, 0, 0, 0, NULL);
2023 goto err_free;
2024 }
2025
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002026 preferred = NULL;
2027 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002028 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002029 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002030
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002031 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002032 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002033 width == drm_mode->base.width &&
2034 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002035 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002036 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002037 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002038 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002039 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002040 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002041 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002042
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002043 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002044 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002045 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002046 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002047 }
2048
Wang Quanxianacb805a2012-07-30 18:09:46 -04002049 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002050 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002051 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002052 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002053 }
2054
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002055 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002056 configured = current;
2057
Wang Quanxianacb805a2012-07-30 18:09:46 -04002058 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002059 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002060 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002061 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002062 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002063 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002064 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002065 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002066 else if (best)
2067 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002068
Hardeningff39efa2013-09-18 23:56:35 +02002069 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002070 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002071 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002072 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002073
Hardeningff39efa2013-09-18 23:56:35 +02002074 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002075
John Kåre Alsaker94659272012-11-13 19:10:18 +01002076 weston_output_init(&output->base, &ec->base, x, y,
2077 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002078 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002079
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002080 if (ec->use_pixman) {
2081 if (drm_output_init_pixman(output, ec) < 0) {
2082 weston_log("Failed to init output pixman state\n");
2083 goto err_output;
2084 }
2085 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002086 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002087 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002088 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002089
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002090 output->backlight = backlight_init(drm_device,
2091 connector->connector_type);
2092 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002093 weston_log("Initialized backlight, device %s\n",
2094 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002095 output->base.set_backlight = drm_set_backlight;
2096 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002097 } else {
2098 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002099 }
2100
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002101 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2102
Richard Hughes2b2092a2013-04-24 14:58:02 +01002103 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002104 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2105 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002106
Jonas Ådahle5a12252013-04-05 23:07:11 +02002107 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002108 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002109 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002110 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002111 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002112 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002113
Richard Hughese7299962013-05-01 21:52:12 +01002114 output->base.gamma_size = output->original_crtc->gamma_size;
2115 output->base.set_gamma = drm_output_set_gamma;
2116
Xiong Zhang97116532013-10-23 13:58:31 +08002117 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2118 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002119
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002120 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2121 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2122 &ec->base.primary_plane);
2123
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002124 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002125 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002126 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002127 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002128 m->width, m->height, m->refresh / 1000.0,
2129 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2130 ", preferred" : "",
2131 m->flags & WL_OUTPUT_MODE_CURRENT ?
2132 ", current" : "",
2133 connector->count_modes == 0 ?
2134 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002135
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002136 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002137
John Kåre Alsaker94659272012-11-13 19:10:18 +01002138err_output:
2139 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002140err_free:
2141 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2142 base.link) {
2143 wl_list_remove(&drm_mode->base.link);
2144 free(drm_mode);
2145 }
2146
2147 drmModeFreeCrtc(output->original_crtc);
2148 ec->crtc_allocator &= ~(1 << output->crtc_id);
2149 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002150 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002151
David Herrmann0f0d54e2011-12-08 17:05:45 +01002152 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002153}
2154
Jesse Barnes58ef3792012-02-23 09:45:49 -05002155static void
2156create_sprites(struct drm_compositor *ec)
2157{
2158 struct drm_sprite *sprite;
2159 drmModePlaneRes *plane_res;
2160 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002161 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002162
2163 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2164 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002165 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002166 strerror(errno));
2167 return;
2168 }
2169
2170 for (i = 0; i < plane_res->count_planes; i++) {
2171 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2172 if (!plane)
2173 continue;
2174
Peter Huttererf3d62272013-08-08 11:57:05 +10002175 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002176 plane->count_formats));
2177 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002178 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002179 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002180 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002181 continue;
2182 }
2183
Jesse Barnes58ef3792012-02-23 09:45:49 -05002184 sprite->possible_crtcs = plane->possible_crtcs;
2185 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002186 sprite->current = NULL;
2187 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002188 sprite->compositor = ec;
2189 sprite->count_formats = plane->count_formats;
2190 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002191 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002192 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002193 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002194 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2195 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002196
2197 wl_list_insert(&ec->sprite_list, &sprite->link);
2198 }
2199
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002200 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002201}
2202
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002203static void
2204destroy_sprites(struct drm_compositor *compositor)
2205{
2206 struct drm_sprite *sprite, *next;
2207 struct drm_output *output;
2208
2209 output = container_of(compositor->base.output_list.next,
2210 struct drm_output, base.link);
2211
2212 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2213 drmModeSetPlane(compositor->drm.fd,
2214 sprite->plane_id,
2215 output->crtc_id, 0, 0,
2216 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002217 drm_output_release_fb(output, sprite->current);
2218 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002219 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002220 free(sprite);
2221 }
2222}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002223
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002224static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002225create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002226 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002227{
2228 drmModeConnector *connector;
2229 drmModeRes *resources;
2230 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002231 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002232
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002233 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002234 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002235 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002236 return -1;
2237 }
2238
Jesse Barnes58ef3792012-02-23 09:45:49 -05002239 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002240 if (!ec->crtcs) {
2241 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002242 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002243 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002244
Rob Clark4339add2012-08-09 14:18:28 -05002245 ec->min_width = resources->min_width;
2246 ec->max_width = resources->max_width;
2247 ec->min_height = resources->min_height;
2248 ec->max_height = resources->max_height;
2249
Jesse Barnes58ef3792012-02-23 09:45:49 -05002250 ec->num_crtcs = resources->count_crtcs;
2251 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2252
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002253 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002254 connector = drmModeGetConnector(ec->drm.fd,
2255 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002256 if (connector == NULL)
2257 continue;
2258
2259 if (connector->connection == DRM_MODE_CONNECTED &&
2260 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002261 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002262 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002263 connector, x, y,
2264 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002265 drmModeFreeConnector(connector);
2266 continue;
2267 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002268
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002269 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002270 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002271 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002272 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002273
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002274 drmModeFreeConnector(connector);
2275 }
2276
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002277 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002278 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002279 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002280 return -1;
2281 }
2282
2283 drmModeFreeResources(resources);
2284
2285 return 0;
2286}
2287
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002288static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002289update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002290{
2291 drmModeConnector *connector;
2292 drmModeRes *resources;
2293 struct drm_output *output, *next;
2294 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002295 uint32_t connected = 0, disconnects = 0;
2296 int i;
2297
2298 resources = drmModeGetResources(ec->drm.fd);
2299 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002300 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002301 return;
2302 }
2303
2304 /* collect new connects */
2305 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002306 int connector_id = resources->connectors[i];
2307
2308 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002309 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002310 continue;
2311
David Herrmann7551cff2011-12-08 17:05:43 +01002312 if (connector->connection != DRM_MODE_CONNECTED) {
2313 drmModeFreeConnector(connector);
2314 continue;
2315 }
2316
Benjamin Franzke117483d2011-08-30 11:38:26 +02002317 connected |= (1 << connector_id);
2318
2319 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002320 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002321 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002322 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002323
2324 /* XXX: not yet needed, we die with 0 outputs */
2325 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002326 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002327 else
2328 x = 0;
2329 y = 0;
2330 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002331 connector, x, y,
2332 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002333 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002334
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002335 }
2336 drmModeFreeConnector(connector);
2337 }
2338 drmModeFreeResources(resources);
2339
2340 disconnects = ec->connector_allocator & ~connected;
2341 if (disconnects) {
2342 wl_list_for_each_safe(output, next, &ec->base.output_list,
2343 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002344 if (disconnects & (1 << output->connector_id)) {
2345 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002346 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002347 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002348 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002349 }
2350 }
2351 }
2352
2353 /* FIXME: handle zero outputs, without terminating */
2354 if (ec->connector_allocator == 0)
2355 wl_display_terminate(ec->base.wl_display);
2356}
2357
2358static int
David Herrmannd7488c22012-03-11 20:05:21 +01002359udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002360{
David Herrmannd7488c22012-03-11 20:05:21 +01002361 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002362 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002363
2364 sysnum = udev_device_get_sysnum(device);
2365 if (!sysnum || atoi(sysnum) != ec->drm.id)
2366 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002367
David Herrmann6ac52db2012-03-11 20:05:22 +01002368 val = udev_device_get_property_value(device, "HOTPLUG");
2369 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002370 return 0;
2371
David Herrmann6ac52db2012-03-11 20:05:22 +01002372 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002373}
2374
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002375static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002376udev_drm_event(int fd, uint32_t mask, void *data)
2377{
2378 struct drm_compositor *ec = data;
2379 struct udev_device *event;
2380
2381 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002382
David Herrmannd7488c22012-03-11 20:05:21 +01002383 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002384 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002385
2386 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002387
2388 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002389}
2390
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002391static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002392drm_restore(struct weston_compositor *ec)
2393{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002394 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002395}
2396
2397static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002398drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002399{
2400 struct drm_compositor *d = (struct drm_compositor *) ec;
2401
Rob Bradfordd355b802013-05-31 18:09:55 +01002402 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002403
2404 wl_event_source_remove(d->udev_drm_source);
2405 wl_event_source_remove(d->drm_source);
2406
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002407 destroy_sprites(d);
2408
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002409 weston_compositor_shutdown(ec);
2410
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002411 if (d->gbm)
2412 gbm_device_destroy(d->gbm);
2413
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002414 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002415
Rob Bradford45c15b82013-07-26 16:29:35 +01002416 close(d->drm.fd);
2417
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002418 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002419}
2420
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002421static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002422drm_compositor_set_modes(struct drm_compositor *compositor)
2423{
2424 struct drm_output *output;
2425 struct drm_mode *drm_mode;
2426 int ret;
2427
2428 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002429 if (!output->current) {
2430 /* If something that would cause the output to
2431 * switch mode happened while in another vt, we
2432 * might not have a current drm_fb. In that case,
2433 * schedule a repaint and let drm_output_repaint
2434 * handle setting the mode. */
2435 weston_output_schedule_repaint(&output->base);
2436 continue;
2437 }
2438
Hardeningff39efa2013-09-18 23:56:35 +02002439 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002440 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002441 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002442 &output->connector_id, 1,
2443 &drm_mode->mode_info);
2444 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002445 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002446 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002447 drm_mode->base.width, drm_mode->base.height,
2448 output->base.x, output->base.y);
2449 }
2450 }
2451}
2452
2453static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002454session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002455{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002456 struct weston_compositor *compositor = data;
2457 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002458 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002459 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002460
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002461 if (ec->base.session_active) {
2462 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002463 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002464 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002465 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002466 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002467 } else {
2468 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002469 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002470
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002471 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002472 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002473
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002474 /* If we have a repaint scheduled (either from a
2475 * pending pageflip or the idle handler), make sure we
2476 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002477 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002478 * further attemps at repainting. When we switch
2479 * back, we schedule a repaint, which will process
2480 * pending frame callbacks. */
2481
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002482 wl_list_for_each(output, &ec->base.output_list, base.link) {
2483 output->base.repaint_needed = 0;
2484 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002485 }
2486
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002487 output = container_of(ec->base.output_list.next,
2488 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002489
2490 wl_list_for_each(sprite, &ec->sprite_list, link)
2491 drmModeSetPlane(ec->drm.fd,
2492 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002493 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002494 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002495 };
2496}
2497
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002498static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002499switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002500{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002501 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002502
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002503 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002504}
2505
David Herrmann0af066f2012-10-29 19:21:16 +01002506/*
2507 * Find primary GPU
2508 * Some systems may have multiple DRM devices attached to a single seat. This
2509 * function loops over all devices and tries to find a PCI device with the
2510 * boot_vga sysfs attribute set to 1.
2511 * If no such device is found, the first DRM device reported by udev is used.
2512 */
2513static struct udev_device*
2514find_primary_gpu(struct drm_compositor *ec, const char *seat)
2515{
2516 struct udev_enumerate *e;
2517 struct udev_list_entry *entry;
2518 const char *path, *device_seat, *id;
2519 struct udev_device *device, *drm_device, *pci;
2520
2521 e = udev_enumerate_new(ec->udev);
2522 udev_enumerate_add_match_subsystem(e, "drm");
2523 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2524
2525 udev_enumerate_scan_devices(e);
2526 drm_device = NULL;
2527 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2528 path = udev_list_entry_get_name(entry);
2529 device = udev_device_new_from_syspath(ec->udev, path);
2530 if (!device)
2531 continue;
2532 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2533 if (!device_seat)
2534 device_seat = default_seat;
2535 if (strcmp(device_seat, seat)) {
2536 udev_device_unref(device);
2537 continue;
2538 }
2539
2540 pci = udev_device_get_parent_with_subsystem_devtype(device,
2541 "pci", NULL);
2542 if (pci) {
2543 id = udev_device_get_sysattr_value(pci, "boot_vga");
2544 if (id && !strcmp(id, "1")) {
2545 if (drm_device)
2546 udev_device_unref(drm_device);
2547 drm_device = device;
2548 break;
2549 }
2550 }
2551
2552 if (!drm_device)
2553 drm_device = device;
2554 else
2555 udev_device_unref(device);
2556 }
2557
2558 udev_enumerate_unref(e);
2559 return drm_device;
2560}
2561
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002562static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002563planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002564{
2565 struct drm_compositor *c = data;
2566
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002567 switch (key) {
2568 case KEY_C:
2569 c->cursors_are_broken ^= 1;
2570 break;
2571 case KEY_V:
2572 c->sprites_are_broken ^= 1;
2573 break;
2574 case KEY_O:
2575 c->sprites_hidden ^= 1;
2576 break;
2577 default:
2578 break;
2579 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002580}
2581
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002582#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002583static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002584recorder_destroy(struct drm_output *output)
2585{
2586 vaapi_recorder_destroy(output->recorder);
2587 output->recorder = NULL;
2588
2589 output->base.disable_planes--;
2590
2591 wl_list_remove(&output->recorder_frame_listener.link);
2592 weston_log("[libva recorder] done\n");
2593}
2594
2595static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002596recorder_frame_notify(struct wl_listener *listener, void *data)
2597{
2598 struct drm_output *output;
2599 struct drm_compositor *c;
2600 int fd, ret;
2601
2602 output = container_of(listener, struct drm_output,
2603 recorder_frame_listener);
2604 c = (struct drm_compositor *) output->base.compositor;
2605
2606 if (!output->recorder)
2607 return;
2608
2609 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2610 DRM_CLOEXEC, &fd);
2611 if (ret) {
2612 weston_log("[libva recorder] "
2613 "failed to create prime fd for front buffer\n");
2614 return;
2615 }
2616
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002617 ret = vaapi_recorder_frame(output->recorder, fd,
2618 output->current->stride);
2619 if (ret < 0) {
2620 weston_log("[libva recorder] aborted: %m\n");
2621 recorder_destroy(output);
2622 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002623}
2624
2625static void *
2626create_recorder(struct drm_compositor *c, int width, int height,
2627 const char *filename)
2628{
2629 int fd;
2630 drm_magic_t magic;
2631
2632 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2633 if (fd < 0)
2634 return NULL;
2635
2636 drmGetMagic(fd, &magic);
2637 drmAuthMagic(c->drm.fd, magic);
2638
2639 return vaapi_recorder_create(fd, width, height, filename);
2640}
2641
2642static void
2643recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2644 void *data)
2645{
2646 struct drm_compositor *c = data;
2647 struct drm_output *output;
2648 int width, height;
2649
2650 output = container_of(c->base.output_list.next,
2651 struct drm_output, base.link);
2652
2653 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002654 if (output->format != GBM_FORMAT_XRGB8888) {
2655 weston_log("failed to start vaapi recorder: "
2656 "output format not supported\n");
2657 return;
2658 }
2659
Hardeningff39efa2013-09-18 23:56:35 +02002660 width = output->base.current_mode->width;
2661 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002662
2663 output->recorder =
2664 create_recorder(c, width, height, "capture.h264");
2665 if (!output->recorder) {
2666 weston_log("failed to create vaapi recorder\n");
2667 return;
2668 }
2669
2670 output->base.disable_planes++;
2671
2672 output->recorder_frame_listener.notify = recorder_frame_notify;
2673 wl_signal_add(&output->base.frame_signal,
2674 &output->recorder_frame_listener);
2675
2676 weston_output_schedule_repaint(&output->base);
2677
2678 weston_log("[libva recorder] initialized\n");
2679 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002680 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002681 }
2682}
2683#else
2684static void
2685recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2686 void *data)
2687{
2688 weston_log("Compiled without libva support\n");
2689}
2690#endif
2691
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002692static void
2693switch_to_gl_renderer(struct drm_compositor *c)
2694{
2695 struct drm_output *output;
2696
2697 if (!c->use_pixman)
2698 return;
2699
2700 weston_log("Switching to GL renderer\n");
2701
2702 c->gbm = create_gbm_device(c->drm.fd);
2703 if (!c->gbm) {
2704 weston_log("Failed to create gbm device. "
2705 "Aborting renderer switch\n");
2706 return;
2707 }
2708
2709 wl_list_for_each(output, &c->base.output_list, base.link)
2710 pixman_renderer_output_destroy(&output->base);
2711
2712 c->base.renderer->destroy(&c->base);
2713
2714 if (drm_compositor_create_gl_renderer(c) < 0) {
2715 gbm_device_destroy(c->gbm);
2716 weston_log("Failed to create GL renderer. Quitting.\n");
2717 /* FIXME: we need a function to shutdown cleanly */
2718 assert(0);
2719 }
2720
2721 wl_list_for_each(output, &c->base.output_list, base.link)
2722 drm_output_init_egl(output, c);
2723
2724 c->use_pixman = 0;
2725}
2726
2727static void
2728renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2729 void *data)
2730{
2731 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2732
2733 switch_to_gl_renderer(c);
2734}
2735
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002736static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002737drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002738 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002739 int *argc, char *argv[],
2740 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002741{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002742 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002743 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002744 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002745 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002746 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002747 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002748
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002749 weston_log("initializing drm backend\n");
2750
Peter Huttererf3d62272013-08-08 11:57:05 +10002751 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002752 if (ec == NULL)
2753 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002754
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002755 /* KMS support for sprites is not complete yet, so disable the
2756 * functionality for now. */
2757 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002758
2759 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002760 if (get_gbm_format_from_section(section,
2761 GBM_FORMAT_XRGB8888,
2762 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002763 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002764
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002765 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002766
Daniel Stone725c2c32012-06-22 14:04:36 +01002767 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002768 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002769 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002770 goto err_base;
2771 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002772
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002773 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002774 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002775 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002776 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002777 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002778 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002779 goto err_compositor;
2780 }
2781
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002782 ec->udev = udev_new();
2783 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002784 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002785 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002786 }
2787
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002788 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002789 ec->session_listener.notify = session_notify;
2790 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002791
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002792 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002793 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002794 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002795 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002796 }
David Herrmann0af066f2012-10-29 19:21:16 +01002797 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002798
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002799 if (init_drm(ec, drm_device) < 0) {
2800 weston_log("failed to initialize kms\n");
2801 goto err_udev_dev;
2802 }
2803
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002804 if (ec->use_pixman) {
2805 if (init_pixman(ec) < 0) {
2806 weston_log("failed to initialize pixman renderer\n");
2807 goto err_udev_dev;
2808 }
2809 } else {
2810 if (init_egl(ec) < 0) {
2811 weston_log("failed to initialize egl\n");
2812 goto err_udev_dev;
2813 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002814 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002815
2816 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002817 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002818
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002819 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002820
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002821 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002822 weston_compositor_add_key_binding(&ec->base, key,
2823 MODIFIER_CTRL | MODIFIER_ALT,
2824 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002825
Jesse Barnes58ef3792012-02-23 09:45:49 -05002826 wl_list_init(&ec->sprite_list);
2827 create_sprites(ec);
2828
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002829 if (udev_input_init(&ec->input,
2830 &ec->base, ec->udev, param->seat_id) < 0) {
2831 weston_log("failed to create input devices\n");
2832 goto err_sprite;
2833 }
2834
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002835 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002836 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002837 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002838 }
2839
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002840 /* A this point we have some idea of whether or not we have a working
2841 * cursor plane. */
2842 if (!ec->cursors_are_broken)
2843 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2844
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002845 path = NULL;
2846
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002847 loop = wl_display_get_event_loop(ec->base.wl_display);
2848 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002849 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002850 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002851
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002852 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2853 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002854 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002855 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002856 }
2857 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2858 "drm", NULL);
2859 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002860 wl_event_loop_add_fd(loop,
2861 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002862 WL_EVENT_READABLE, udev_drm_event, ec);
2863
2864 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002865 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002866 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002867 }
2868
Daniel Stonea96b93c2012-06-22 14:04:37 +01002869 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002870
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002871 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002872 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002873 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002874 planes_binding, ec);
2875 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2876 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002877 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2878 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002879 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2880 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002881
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002882 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002883
2884err_udev_monitor:
2885 wl_event_source_remove(ec->udev_drm_source);
2886 udev_monitor_unref(ec->udev_monitor);
2887err_drm_source:
2888 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002889err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002890 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002891err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002892 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002893 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002894 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002895err_udev_dev:
2896 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002897err_launcher:
2898 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002899err_udev:
2900 udev_unref(ec->udev);
2901err_compositor:
2902 weston_compositor_shutdown(&ec->base);
2903err_base:
2904 free(ec);
2905 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002906}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002907
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002908WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002909backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002910 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002911{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002912 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002913
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002914 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002915 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2916 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2917 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002918 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002919 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002920 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002921
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002922 param.seat_id = default_seat;
2923
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002924 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002925
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002926 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002927}