blob: 9b4d4dcf0031742da67c5b66216ad65ba6917c37 [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
Jesse Barnes58ef3792012-02-23 09:45:49 -0500228drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
229{
230 struct weston_compositor *ec = output_base->compositor;
231 struct drm_compositor *c =(struct drm_compositor *) ec;
232 struct drm_output *output = (struct drm_output *) output_base;
233 int crtc;
234
235 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
236 if (c->crtcs[crtc] != output->crtc_id)
237 continue;
238
239 if (supported & (1 << crtc))
240 return -1;
241 }
242
243 return 0;
244}
245
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300246static void
247drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
248{
249 struct drm_fb *fb = data;
250 struct gbm_device *gbm = gbm_bo_get_device(bo);
251
252 if (fb->fb_id)
253 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
254
Pekka Paalanende685b82012-12-04 15:58:12 +0200255 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300256
257 free(data);
258}
259
260static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200261drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
262{
263 struct drm_fb *fb;
264 int ret;
265
266 struct drm_mode_create_dumb create_arg;
267 struct drm_mode_destroy_dumb destroy_arg;
268 struct drm_mode_map_dumb map_arg;
269
Peter Huttererf3d62272013-08-08 11:57:05 +1000270 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200271 if (!fb)
272 return NULL;
273
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700274 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200275 create_arg.bpp = 32;
276 create_arg.width = width;
277 create_arg.height = height;
278
279 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
280 if (ret)
281 goto err_fb;
282
283 fb->handle = create_arg.handle;
284 fb->stride = create_arg.pitch;
285 fb->size = create_arg.size;
286 fb->fd = ec->drm.fd;
287
288 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
289 fb->stride, fb->handle, &fb->fb_id);
290 if (ret)
291 goto err_bo;
292
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700293 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200294 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400295 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200296 if (ret)
297 goto err_add_fb;
298
299 fb->map = mmap(0, fb->size, PROT_WRITE,
300 MAP_SHARED, ec->drm.fd, map_arg.offset);
301 if (fb->map == MAP_FAILED)
302 goto err_add_fb;
303
304 return fb;
305
306err_add_fb:
307 drmModeRmFB(ec->drm.fd, fb->fb_id);
308err_bo:
309 memset(&destroy_arg, 0, sizeof(destroy_arg));
310 destroy_arg.handle = create_arg.handle;
311 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
312err_fb:
313 free(fb);
314 return NULL;
315}
316
317static void
318drm_fb_destroy_dumb(struct drm_fb *fb)
319{
320 struct drm_mode_destroy_dumb destroy_arg;
321
322 if (!fb->map)
323 return;
324
325 if (fb->fb_id)
326 drmModeRmFB(fb->fd, fb->fb_id);
327
328 weston_buffer_reference(&fb->buffer_ref, NULL);
329
330 munmap(fb->map, fb->size);
331
332 memset(&destroy_arg, 0, sizeof(destroy_arg));
333 destroy_arg.handle = fb->handle;
334 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
335
336 free(fb);
337}
338
339static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500340drm_fb_get_from_bo(struct gbm_bo *bo,
341 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300342{
343 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200345 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300346 int ret;
347
348 if (fb)
349 return fb;
350
Bryce Harringtonde16d892014-11-20 22:21:57 -0800351 fb = zalloc(sizeof *fb);
352 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200353 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354
355 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356
357 width = gbm_bo_get_width(bo);
358 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 fb->stride = gbm_bo_get_stride(bo);
360 fb->handle = gbm_bo_get_handle(bo).u32;
361 fb->size = fb->stride * height;
362 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300363
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 if (compositor->min_width > width || width > compositor->max_width ||
365 compositor->min_height > height ||
366 height > compositor->max_height) {
367 weston_log("bo geometry out of bounds\n");
368 goto err_free;
369 }
370
371 ret = -1;
372
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200373 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200374 handles[0] = fb->handle;
375 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376 offsets[0] = 0;
377
378 ret = drmModeAddFB2(compositor->drm.fd, width, height,
379 format, handles, pitches, offsets,
380 &fb->fb_id, 0);
381 if (ret) {
382 weston_log("addfb2 failed: %m\n");
383 compositor->no_addfb2 = 1;
384 compositor->sprites_are_broken = 1;
385 }
386 }
387
388 if (ret)
389 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200390 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200391
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300392 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200393 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200394 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300395 }
396
397 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
398
399 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200400
401err_free:
402 free(fb);
403 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404}
405
406static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500407drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200408{
Pekka Paalanende685b82012-12-04 15:58:12 +0200409 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200410
411 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200412
Pekka Paalanende685b82012-12-04 15:58:12 +0200413 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200414}
415
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200416static void
417drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
418{
419 if (!fb)
420 return;
421
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200422 if (fb->map &&
423 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200424 drm_fb_destroy_dumb(fb);
425 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200426 if (fb->is_client_buffer)
427 gbm_bo_destroy(fb->bo);
428 else
429 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600430 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200431 }
432}
433
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500434static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200435drm_output_check_scanout_format(struct drm_output *output,
436 struct weston_surface *es, struct gbm_bo *bo)
437{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200438 uint32_t format;
439 pixman_region32_t r;
440
441 format = gbm_bo_get_format(bo);
442
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700443 if (format == GBM_FORMAT_ARGB8888) {
444 /* We can scanout an ARGB buffer if the surface's
445 * opaque region covers the whole output, but we have
446 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800447 pixman_region32_init_rect(&r, 0, 0,
448 output->base.width,
449 output->base.height);
450 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200451
452 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500453 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200454
455 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500456 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700457
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000458 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700459 return format;
460
461 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200462}
463
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400464static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500465drm_output_prepare_scanout_view(struct weston_output *_output,
466 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500467{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400468 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500469 struct drm_compositor *c =
470 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500471 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200472 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300473 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500474 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500475
Jason Ekstranda7af7042013-10-12 22:38:11 -0500476 if (ev->geometry.x != output->base.x ||
477 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200478 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200479 buffer->width != output->base.current_mode->width ||
480 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200481 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500482 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400483 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500484
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400485 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700486 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500487
Rob Bradford9b101872012-09-14 23:25:41 +0100488 /* Unable to use the buffer for scanout */
489 if (!bo)
490 return NULL;
491
Jason Ekstranda7af7042013-10-12 22:38:11 -0500492 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500493 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300494 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400495 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300496 }
497
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500498 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 if (!output->next) {
500 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400501 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300502 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500503
Pekka Paalanende685b82012-12-04 15:58:12 +0200504 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500505
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400506 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500507}
508
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500509static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200510drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400511{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200512 struct drm_compositor *c =
513 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300514 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200516 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400517
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300518 bo = gbm_surface_lock_front_buffer(output->surface);
519 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200520 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400521 return;
522 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300523
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000524 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300525 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200526 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300527 gbm_surface_release_buffer(output->surface, bo);
528 return;
529 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400530}
531
532static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200533drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
534{
535 struct weston_compositor *ec = output->base.compositor;
536 pixman_region32_t total_damage, previous_damage;
537
538 pixman_region32_init(&total_damage);
539 pixman_region32_init(&previous_damage);
540
541 pixman_region32_copy(&previous_damage, damage);
542
543 pixman_region32_union(&total_damage, damage, &output->previous_damage);
544 pixman_region32_copy(&output->previous_damage, &previous_damage);
545
546 output->current_image ^= 1;
547
548 output->next = output->dumb[output->current_image];
549 pixman_renderer_output_set_buffer(&output->base,
550 output->image[output->current_image]);
551
552 ec->renderer->repaint_output(&output->base, &total_damage);
553
554 pixman_region32_fini(&total_damage);
555 pixman_region32_fini(&previous_damage);
556}
557
558static void
559drm_output_render(struct drm_output *output, pixman_region32_t *damage)
560{
561 struct drm_compositor *c =
562 (struct drm_compositor *) output->base.compositor;
563
564 if (c->use_pixman)
565 drm_output_render_pixman(output, damage);
566 else
567 drm_output_render_gl(output, damage);
568
569 pixman_region32_subtract(&c->base.primary_plane.damage,
570 &c->base.primary_plane.damage, damage);
571}
572
573static void
Richard Hughese7299962013-05-01 21:52:12 +0100574drm_output_set_gamma(struct weston_output *output_base,
575 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
576{
577 int rc;
578 struct drm_output *output = (struct drm_output *) output_base;
579 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
580
581 /* check */
582 if (output_base->gamma_size != size)
583 return;
584 if (!output->original_crtc)
585 return;
586
587 rc = drmModeCrtcSetGamma(compositor->drm.fd,
588 output->crtc_id,
589 size, r, g, b);
590 if (rc)
591 weston_log("set gamma failed: %m\n");
592}
593
David Herrmann1edf44c2013-10-22 17:11:26 +0200594static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500595drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400596 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100597{
598 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500599 struct drm_compositor *compositor =
600 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400602 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100604
Xiong Zhangabd5d472013-10-11 14:43:07 +0800605 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200606 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800607
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300608 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400609 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300610 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200611 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100612
Hardeningff39efa2013-09-18 23:56:35 +0200613 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200614 if (!output->current ||
615 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400616 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300617 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400618 &output->connector_id, 1,
619 &mode->mode_info);
620 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200621 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200622 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400623 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300624 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200625 }
626
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500627 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300628 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500629 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200630 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200631 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500632 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100633
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300634 output->page_flip_pending = 1;
635
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400636 drm_output_set_cursor(output);
637
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638 /*
639 * Now, update all the sprite surfaces
640 */
641 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 drmVBlank vbl = {
644 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
645 .request.sequence = 1,
646 };
647
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200648 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200649 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650 continue;
651
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200652 if (s->next && !compositor->sprites_hidden)
653 fb_id = s->next->fb_id;
654
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200656 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 s->dest_x, s->dest_y,
658 s->dest_w, s->dest_h,
659 s->src_x, s->src_y,
660 s->src_w, s->src_h);
661 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200662 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500663 ret, strerror(errno));
664
Rob Clark5ca1a472012-08-08 20:27:37 -0500665 if (output->pipe > 0)
666 vbl.request.type |= DRM_VBLANK_SECONDARY;
667
Jesse Barnes58ef3792012-02-23 09:45:49 -0500668 /*
669 * Queue a vblank signal so we know when the surface
670 * becomes active on the display or has been replaced.
671 */
672 vbl.request.signal = (unsigned long)s;
673 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
674 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200675 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500676 ret, strerror(errno));
677 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300678
679 s->output = output;
680 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681 }
682
David Herrmann1edf44c2013-10-22 17:11:26 +0200683 return 0;
684
685err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800686 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200687 if (output->next) {
688 drm_output_release_fb(output, output->next);
689 output->next = NULL;
690 }
691
692 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400693}
694
695static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200696drm_output_start_repaint_loop(struct weston_output *output_base)
697{
698 struct drm_output *output = (struct drm_output *) output_base;
699 struct drm_compositor *compositor = (struct drm_compositor *)
700 output_base->compositor;
701 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300702 struct timespec ts;
703
Xiong Zhangabd5d472013-10-11 14:43:07 +0800704 if (output->destroy_pending)
705 return;
706
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300707 if (!output->current) {
708 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200709 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300710 }
711
712 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200713
714 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
715 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
716 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200717 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200718 }
David Herrmann3c688c52013-10-22 17:11:25 +0200719
720 return;
721
722finish_frame:
723 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400724 clock_gettime(compositor->base.presentation_clock, &ts);
725 weston_output_finish_frame(output_base, &ts);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200726}
727
728static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400729drm_output_update_msc(struct drm_output *output, unsigned int seq)
730{
731 uint64_t msc_hi = output->base.msc >> 32;
732
733 if (seq < (output->base.msc & 0xffffffff))
734 msc_hi++;
735
736 output->base.msc = (msc_hi << 32) + seq;
737}
738
739static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500740vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
741 void *data)
742{
743 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300744 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400745 struct timespec ts;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300746
Pekka Paalanen641307c2014-09-23 22:08:47 -0400747 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300748 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500749
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200750 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200751 s->current = s->next;
752 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300753
754 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400755 ts.tv_sec = sec;
756 ts.tv_nsec = usec * 1000;
757 weston_output_finish_frame(&output->base, &ts);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300758 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500759}
760
761static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800762drm_output_destroy(struct weston_output *output_base);
763
764static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400765page_flip_handler(int fd, unsigned int frame,
766 unsigned int sec, unsigned int usec, void *data)
767{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200768 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400769 struct timespec ts;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400770
Pekka Paalanen641307c2014-09-23 22:08:47 -0400771 drm_output_update_msc(output, frame);
772
Jonas Ådahle5a12252013-04-05 23:07:11 +0200773 /* We don't set page_flip_pending on start_repaint_loop, in that case
774 * we just want to page flip to the current buffer to get an accurate
775 * timestamp */
776 if (output->page_flip_pending) {
777 drm_output_release_fb(output, output->current);
778 output->current = output->next;
779 output->next = NULL;
780 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300781
Jonas Ådahle5a12252013-04-05 23:07:11 +0200782 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400783
Xiong Zhangabd5d472013-10-11 14:43:07 +0800784 if (output->destroy_pending)
785 drm_output_destroy(&output->base);
786 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400787 ts.tv_sec = sec;
788 ts.tv_nsec = usec * 1000;
789 weston_output_finish_frame(&output->base, &ts);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300790
791 /* We can't call this from frame_notify, because the output's
792 * repaint needed flag is cleared just after that */
793 if (output->recorder)
794 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300795 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200796}
797
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500798static uint32_t
799drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500800 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500802 uint32_t i, format;
803
804 format = gbm_bo_get_format(bo);
805
806 if (format == GBM_FORMAT_ARGB8888) {
807 pixman_region32_t r;
808
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500809 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600810 ev->surface->width,
811 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500812 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500813
814 if (!pixman_region32_not_empty(&r))
815 format = GBM_FORMAT_XRGB8888;
816
817 pixman_region32_fini(&r);
818 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500819
820 for (i = 0; i < s->count_formats; i++)
821 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500822 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823
824 return 0;
825}
826
827static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500828drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500829{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500830 return !ev->transform.enabled ||
831 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500832}
833
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500835drm_output_prepare_overlay_view(struct weston_output *output_base,
836 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837{
838 struct weston_compositor *ec = output_base->compositor;
839 struct drm_compositor *c =(struct drm_compositor *) ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200840 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 struct drm_sprite *s;
842 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500843 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200845 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500846 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400847 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500848
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200849 if (c->gbm == NULL)
850 return NULL;
851
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200852 if (viewport->buffer.transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200853 return NULL;
854
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200855 if (viewport->buffer.scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200856 return NULL;
857
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500858 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400859 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500860
Jason Ekstranda7af7042013-10-12 22:38:11 -0500861 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400862 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300863
Jason Ekstranda7af7042013-10-12 22:38:11 -0500864 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400865 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500866
Jason Ekstranda7af7042013-10-12 22:38:11 -0500867 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200868 return NULL;
869
Jason Ekstranda7af7042013-10-12 22:38:11 -0500870 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500871 return NULL;
872
Jason Ekstranda7af7042013-10-12 22:38:11 -0500873 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400874 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500875
Jesse Barnes58ef3792012-02-23 09:45:49 -0500876 wl_list_for_each(s, &c->sprite_list, link) {
877 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
878 continue;
879
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200880 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500881 found = 1;
882 break;
883 }
884 }
885
886 /* No sprites available */
887 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400888 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500889
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400890 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500891 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700892 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400893 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400894 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400895
Jason Ekstranda7af7042013-10-12 22:38:11 -0500896 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500897 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200898 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400899 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500900 }
901
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200902 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200903 if (!s->next) {
904 gbm_bo_destroy(bo);
905 return NULL;
906 }
907
Jason Ekstranda7af7042013-10-12 22:38:11 -0500908 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500909
Jason Ekstranda7af7042013-10-12 22:38:11 -0500910 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400911 s->plane.x = box->x1;
912 s->plane.y = box->y1;
913
Jesse Barnes58ef3792012-02-23 09:45:49 -0500914 /*
915 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500916 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500917 * for us already).
918 */
919 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500920 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500921 &output_base->region);
922 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
923 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200924 tbox = weston_transformed_rect(output_base->width,
925 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200926 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200927 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200928 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200929 s->dest_x = tbox.x1;
930 s->dest_y = tbox.y1;
931 s->dest_w = tbox.x2 - tbox.x1;
932 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500933 pixman_region32_fini(&dest_rect);
934
935 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500936 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500937 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500938 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400939
Jason Ekstranda7af7042013-10-12 22:38:11 -0500940 weston_view_from_global_fixed(ev,
941 wl_fixed_from_int(box->x1),
942 wl_fixed_from_int(box->y1),
943 &sx1, &sy1);
944 weston_view_from_global_fixed(ev,
945 wl_fixed_from_int(box->x2),
946 wl_fixed_from_int(box->y2),
947 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400948
949 if (sx1 < 0)
950 sx1 = 0;
951 if (sy1 < 0)
952 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600953 if (sx2 > wl_fixed_from_int(ev->surface->width))
954 sx2 = wl_fixed_from_int(ev->surface->width);
955 if (sy2 > wl_fixed_from_int(ev->surface->height))
956 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400957
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200958 tbox.x1 = sx1;
959 tbox.y1 = sy1;
960 tbox.x2 = sx2;
961 tbox.y2 = sy2;
962
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600963 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
964 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200965 viewport->buffer.transform,
966 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100967 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200968
969 s->src_x = tbox.x1 << 8;
970 s->src_y = tbox.y1 << 8;
971 s->src_w = (tbox.x2 - tbox.x1) << 8;
972 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500973 pixman_region32_fini(&src_rect);
974
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400975 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500976}
977
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400978static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500979drm_output_prepare_cursor_view(struct weston_output *output_base,
980 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500981{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400982 struct drm_compositor *c =
983 (struct drm_compositor *) output_base->compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100984 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400985 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400986
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200987 if (c->gbm == NULL)
988 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200989 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
990 return NULL;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100991 if (viewport->buffer.scale != output_base->current_scale)
992 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500993 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400994 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500995 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400996 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500997 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400998 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500999 if (ev->surface->buffer_ref.buffer == NULL ||
1000 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001001 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001002 return NULL;
1003
Jason Ekstranda7af7042013-10-12 22:38:11 -05001004 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001005
1006 return &output->cursor_plane;
1007}
1008
1009static void
1010drm_output_set_cursor(struct drm_output *output)
1011{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001012 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001013 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001014 struct drm_compositor *c =
1015 (struct drm_compositor *) output->base.compositor;
1016 EGLint handle, stride;
1017 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001018 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001019 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001020 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001021
Jason Ekstranda7af7042013-10-12 22:38:11 -05001022 output->cursor_view = NULL;
1023 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001024 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1025 return;
1026 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001027
Neil Robertse5051712013-11-13 15:44:06 +00001028 buffer = ev->surface->buffer_ref.buffer;
1029
1030 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001031 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001032 pixman_region32_fini(&output->cursor_plane.damage);
1033 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001034 output->current_cursor ^= 1;
1035 bo = output->cursor_bo[output->current_cursor];
1036 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001037 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1038 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1039 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001040 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001041 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001042 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001043 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001044
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001045 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001046 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001047
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001048 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001049 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1050 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001051 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001052 c->cursors_are_broken = 1;
1053 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001054 }
1055
Jason Ekstranda7af7042013-10-12 22:38:11 -05001056 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1057 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001058 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001059 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001060 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001061 c->cursors_are_broken = 1;
1062 }
1063
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001064 output->cursor_plane.x = x;
1065 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001066 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001067}
1068
Jesse Barnes58ef3792012-02-23 09:45:49 -05001069static void
1070drm_assign_planes(struct weston_output *output)
1071{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001072 struct drm_compositor *c =
1073 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001074 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001075 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001076 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001077
1078 /*
1079 * Find a surface for each sprite in the output using some heuristics:
1080 * 1) size
1081 * 2) frequency of update
1082 * 3) opacity (though some hw might support alpha blending)
1083 * 4) clipping (this can be fixed with color keys)
1084 *
1085 * The idea is to save on blitting since this should save power.
1086 * If we can get a large video surface on the sprite for example,
1087 * the main display surface may not need to update at all, and
1088 * the client buffer can be used directly for the sprite surface
1089 * as we do for flipping full screen surfaces.
1090 */
1091 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001092 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001093
Jason Ekstranda7af7042013-10-12 22:38:11 -05001094 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001095 struct weston_surface *es = ev->surface;
1096
1097 /* Test whether this buffer can ever go into a plane:
1098 * non-shm, or small enough to be a cursor.
1099 *
1100 * Also, keep a reference when using the pixman renderer.
1101 * That makes it possible to do a seamless switch to the GL
1102 * renderer and since the pixman renderer keeps a reference
1103 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001104 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001105 if (c->use_pixman ||
1106 (es->buffer_ref.buffer &&
1107 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001108 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001109 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001110 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001111 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001112
Jesse Barnes58ef3792012-02-23 09:45:49 -05001113 pixman_region32_init(&surface_overlap);
1114 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001115 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001116
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001117 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001118 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001119 next_plane = primary;
1120 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001121 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001122 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001123 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001124 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001125 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001126 if (next_plane == NULL)
1127 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001128 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001129 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001130 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001131 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001132
Jesse Barnes58ef3792012-02-23 09:45:49 -05001133 pixman_region32_fini(&surface_overlap);
1134 }
1135 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001136}
1137
Matt Roper361d2ad2011-08-29 13:52:23 -07001138static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001139drm_output_fini_pixman(struct drm_output *output);
1140
1141static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001142drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001143{
1144 struct drm_output *output = (struct drm_output *) output_base;
1145 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001146 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001147 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001148
Xiong Zhangabd5d472013-10-11 14:43:07 +08001149 if (output->page_flip_pending) {
1150 output->destroy_pending = 1;
1151 weston_log("destroy output while page flip pending\n");
1152 return;
1153 }
1154
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001155 if (output->backlight)
1156 backlight_destroy(output->backlight);
1157
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001158 drmModeFreeProperty(output->dpms_prop);
1159
Matt Roper361d2ad2011-08-29 13:52:23 -07001160 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001161 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001162
1163 /* Restore original CRTC state */
1164 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001165 origcrtc->x, origcrtc->y,
1166 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001167 drmModeFreeCrtc(origcrtc);
1168
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001169 c->crtc_allocator &= ~(1 << output->crtc_id);
1170 c->connector_allocator &= ~(1 << output->connector_id);
1171
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001172 if (c->use_pixman) {
1173 drm_output_fini_pixman(output);
1174 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001175 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001176 gbm_surface_destroy(output->surface);
1177 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001178
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001179 weston_plane_release(&output->fb_plane);
1180 weston_plane_release(&output->cursor_plane);
1181
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001182 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001183
Matt Roper361d2ad2011-08-29 13:52:23 -07001184 free(output);
1185}
1186
Alex Wub7b8bda2012-04-17 17:20:48 +08001187static struct drm_mode *
1188choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1189{
1190 struct drm_mode *tmp_mode = NULL, *mode;
1191
Hardeningff39efa2013-09-18 23:56:35 +02001192 if (output->base.current_mode->width == target_mode->width &&
1193 output->base.current_mode->height == target_mode->height &&
1194 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001195 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001196 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001197
1198 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1199 if (mode->mode_info.hdisplay == target_mode->width &&
1200 mode->mode_info.vdisplay == target_mode->height) {
1201 if (mode->mode_info.vrefresh == target_mode->refresh ||
1202 target_mode->refresh == 0) {
1203 return mode;
1204 } else if (!tmp_mode)
1205 tmp_mode = mode;
1206 }
1207 }
1208
1209 return tmp_mode;
1210}
1211
1212static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001213drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001214static int
1215drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001216
1217static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001218drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1219{
1220 struct drm_output *output;
1221 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001222 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001223
1224 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001225 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001226 return -1;
1227 }
1228
1229 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001230 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001231 return -1;
1232 }
1233
1234 ec = (struct drm_compositor *)output_base->compositor;
1235 output = (struct drm_output *)output_base;
1236 drm_mode = choose_mode (output, mode);
1237
1238 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001239 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001240 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001241 }
1242
Hardeningff39efa2013-09-18 23:56:35 +02001243 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001244 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001245
Hardeningff39efa2013-09-18 23:56:35 +02001246 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001247
Hardeningff39efa2013-09-18 23:56:35 +02001248 output->base.current_mode = &drm_mode->base;
1249 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001250 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1251
Alex Wub7b8bda2012-04-17 17:20:48 +08001252 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001253 drm_output_release_fb(output, output->current);
1254 drm_output_release_fb(output, output->next);
1255 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001256
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001257 if (ec->use_pixman) {
1258 drm_output_fini_pixman(output);
1259 if (drm_output_init_pixman(output, ec) < 0) {
1260 weston_log("failed to init output pixman state with "
1261 "new mode\n");
1262 return -1;
1263 }
1264 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001265 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001266 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001267
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001268 if (drm_output_init_egl(output, ec) < 0) {
1269 weston_log("failed to init output egl state with "
1270 "new mode");
1271 return -1;
1272 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001273 }
1274
Alex Wub7b8bda2012-04-17 17:20:48 +08001275 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001276}
1277
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001278static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001279on_drm_input(int fd, uint32_t mask, void *data)
1280{
1281 drmEventContext evctx;
1282
1283 memset(&evctx, 0, sizeof evctx);
1284 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1285 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001286 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001287 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001288
1289 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001290}
1291
1292static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001293init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001294{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001295 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001296 uint64_t cap;
1297 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001298 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001299
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001300 sysnum = udev_device_get_sysnum(device);
1301 if (sysnum)
1302 ec->drm.id = atoi(sysnum);
1303 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001304 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001305 return -1;
1306 }
1307
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001308 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001309 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001310 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001311 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001312 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001313 udev_device_get_devnode(device));
1314 return -1;
1315 }
1316
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001317 weston_log("using %s\n", filename);
1318
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001319 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001320 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001321
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001322 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1323 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001324 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001325 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001326 clk_id = CLOCK_REALTIME;
1327
1328 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1329 weston_log("Error: failed to set presentation clock %d.\n",
1330 clk_id);
1331 return -1;
1332 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001333
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001334 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1335 if (ret == 0)
1336 ec->cursor_width = cap;
1337 else
1338 ec->cursor_width = 64;
1339
1340 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1341 if (ret == 0)
1342 ec->cursor_height = cap;
1343 else
1344 ec->cursor_height = 64;
1345
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001346 return 0;
1347}
1348
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001349static struct gbm_device *
1350create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001351{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001352 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001353
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001354 gl_renderer = weston_load_module("gl-renderer.so",
1355 "gl_renderer_interface");
1356 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001357 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001358
1359 /* GBM will load a dri driver, but even though they need symbols from
1360 * libglapi, in some version of Mesa they are not linked to it. Since
1361 * only the gl-renderer module links to it, the call above won't make
1362 * these symbols globally available, and loading the DRI driver fails.
1363 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1364 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1365
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001366 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001367
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001368 return gbm;
1369}
1370
1371static int
1372drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1373{
1374 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001375
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001376 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001377 if (gl_renderer->create(&ec->base, ec->gbm,
1378 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001379 return -1;
1380 }
1381
1382 return 0;
1383}
1384
1385static int
1386init_egl(struct drm_compositor *ec)
1387{
1388 ec->gbm = create_gbm_device(ec->drm.fd);
1389
1390 if (!ec->gbm)
1391 return -1;
1392
1393 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001394 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001395 return -1;
1396 }
1397
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001398 return 0;
1399}
1400
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001401static int
1402init_pixman(struct drm_compositor *ec)
1403{
1404 return pixman_renderer_init(&ec->base);
1405}
1406
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001407static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001408drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001409{
1410 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001411 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001412
1413 mode = malloc(sizeof *mode);
1414 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001415 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001416
1417 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001418 mode->base.width = info->hdisplay;
1419 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001420
1421 /* Calculate higher precision (mHz) refresh rate */
1422 refresh = (info->clock * 1000000LL / info->htotal +
1423 info->vtotal / 2) / info->vtotal;
1424
1425 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1426 refresh *= 2;
1427 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1428 refresh /= 2;
1429 if (info->vscan > 1)
1430 refresh /= info->vscan;
1431
1432 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001433 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001434
1435 if (info->type & DRM_MODE_TYPE_PREFERRED)
1436 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1437
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001438 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1439
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001440 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001441}
1442
1443static int
1444drm_subpixel_to_wayland(int drm_value)
1445{
1446 switch (drm_value) {
1447 default:
1448 case DRM_MODE_SUBPIXEL_UNKNOWN:
1449 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1450 case DRM_MODE_SUBPIXEL_NONE:
1451 return WL_OUTPUT_SUBPIXEL_NONE;
1452 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1453 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1454 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1455 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1456 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1457 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1458 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1459 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1460 }
1461}
1462
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001463/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001464static uint32_t
1465drm_get_backlight(struct drm_output *output)
1466{
1467 long brightness, max_brightness, norm;
1468
1469 brightness = backlight_get_brightness(output->backlight);
1470 max_brightness = backlight_get_max_brightness(output->backlight);
1471
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001472 /* convert it on a scale of 0 to 255 */
1473 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001474
1475 return (uint32_t) norm;
1476}
1477
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001478/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001479static void
1480drm_set_backlight(struct weston_output *output_base, uint32_t value)
1481{
1482 struct drm_output *output = (struct drm_output *) output_base;
1483 long max_brightness, new_brightness;
1484
1485 if (!output->backlight)
1486 return;
1487
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001488 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001489 return;
1490
1491 max_brightness = backlight_get_max_brightness(output->backlight);
1492
1493 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001494 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001495
1496 backlight_set_brightness(output->backlight, new_brightness);
1497}
1498
1499static drmModePropertyPtr
1500drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1501{
1502 drmModePropertyPtr props;
1503 int i;
1504
1505 for (i = 0; i < connector->count_props; i++) {
1506 props = drmModeGetProperty(fd, connector->props[i]);
1507 if (!props)
1508 continue;
1509
1510 if (!strcmp(props->name, name))
1511 return props;
1512
1513 drmModeFreeProperty(props);
1514 }
1515
1516 return NULL;
1517}
1518
1519static void
1520drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1521{
1522 struct drm_output *output = (struct drm_output *) output_base;
1523 struct weston_compositor *ec = output_base->compositor;
1524 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001525
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001526 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001527 return;
1528
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001529 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1530 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001531}
1532
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001533static const char *connector_type_names[] = {
1534 "None",
1535 "VGA",
1536 "DVI",
1537 "DVI",
1538 "DVI",
1539 "Composite",
1540 "TV",
1541 "LVDS",
1542 "CTV",
1543 "DIN",
1544 "DP",
1545 "HDMI",
1546 "HDMI",
1547 "TV",
1548 "eDP",
1549};
1550
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001551static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001552find_crtc_for_connector(struct drm_compositor *ec,
1553 drmModeRes *resources, drmModeConnector *connector)
1554{
1555 drmModeEncoder *encoder;
1556 uint32_t possible_crtcs;
1557 int i, j;
1558
1559 for (j = 0; j < connector->count_encoders; j++) {
1560 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1561 if (encoder == NULL) {
1562 weston_log("Failed to get encoder.\n");
1563 return -1;
1564 }
1565 possible_crtcs = encoder->possible_crtcs;
1566 drmModeFreeEncoder(encoder);
1567
1568 for (i = 0; i < resources->count_crtcs; i++) {
1569 if (possible_crtcs & (1 << i) &&
1570 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1571 return i;
1572 }
1573 }
1574
1575 return -1;
1576}
1577
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001578/* Init output state that depends on gl or gbm */
1579static int
1580drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1581{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001582 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001583 int i, flags;
1584
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001585 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001586 output->base.current_mode->width,
1587 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001588 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001589 GBM_BO_USE_SCANOUT |
1590 GBM_BO_USE_RENDERING);
1591 if (!output->surface) {
1592 weston_log("failed to create gbm surface\n");
1593 return -1;
1594 }
1595
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001596 if (gl_renderer->output_create(&output->base, output->surface,
1597 gl_renderer->opaque_attribs,
1598 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001599 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001600 gbm_surface_destroy(output->surface);
1601 return -1;
1602 }
1603
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001604 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001605
1606 for (i = 0; i < 2; i++) {
1607 if (output->cursor_bo[i])
1608 continue;
1609
1610 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001611 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1612 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001613 }
1614
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001615 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1616 weston_log("cursor buffers unavailable, using gl cursors\n");
1617 ec->cursors_are_broken = 1;
1618 }
1619
1620 return 0;
1621}
1622
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001623static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001624drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1625{
Hardeningff39efa2013-09-18 23:56:35 +02001626 int w = output->base.current_mode->width;
1627 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001628 unsigned int i;
1629
1630 /* FIXME error checking */
1631
1632 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001633 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001634 if (!output->dumb[i])
1635 goto err;
1636
1637 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001638 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001639 output->dumb[i]->map,
1640 output->dumb[i]->stride);
1641 if (!output->image[i])
1642 goto err;
1643 }
1644
1645 if (pixman_renderer_output_create(&output->base) < 0)
1646 goto err;
1647
1648 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001649 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001650
1651 return 0;
1652
1653err:
1654 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1655 if (output->dumb[i])
1656 drm_fb_destroy_dumb(output->dumb[i]);
1657 if (output->image[i])
1658 pixman_image_unref(output->image[i]);
1659
1660 output->dumb[i] = NULL;
1661 output->image[i] = NULL;
1662 }
1663
1664 return -1;
1665}
1666
1667static void
1668drm_output_fini_pixman(struct drm_output *output)
1669{
1670 unsigned int i;
1671
1672 pixman_renderer_output_destroy(&output->base);
1673 pixman_region32_fini(&output->previous_damage);
1674
1675 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1676 drm_fb_destroy_dumb(output->dumb[i]);
1677 pixman_image_unref(output->image[i]);
1678 output->dumb[i] = NULL;
1679 output->image[i] = NULL;
1680 }
1681}
1682
Richard Hughes2b2092a2013-04-24 14:58:02 +01001683static void
1684edid_parse_string(const uint8_t *data, char text[])
1685{
1686 int i;
1687 int replaced = 0;
1688
1689 /* this is always 12 bytes, but we can't guarantee it's null
1690 * terminated or not junk. */
1691 strncpy(text, (const char *) data, 12);
1692
1693 /* remove insane chars */
1694 for (i = 0; text[i] != '\0'; i++) {
1695 if (text[i] == '\n' ||
1696 text[i] == '\r') {
1697 text[i] = '\0';
1698 break;
1699 }
1700 }
1701
1702 /* ensure string is printable */
1703 for (i = 0; text[i] != '\0'; i++) {
1704 if (!isprint(text[i])) {
1705 text[i] = '-';
1706 replaced++;
1707 }
1708 }
1709
1710 /* if the string is random junk, ignore the string */
1711 if (replaced > 4)
1712 text[0] = '\0';
1713}
1714
1715#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1716#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1717#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1718#define EDID_OFFSET_DATA_BLOCKS 0x36
1719#define EDID_OFFSET_LAST_BLOCK 0x6c
1720#define EDID_OFFSET_PNPID 0x08
1721#define EDID_OFFSET_SERIAL 0x0c
1722
1723static int
1724edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1725{
1726 int i;
1727 uint32_t serial_number;
1728
1729 /* check header */
1730 if (length < 128)
1731 return -1;
1732 if (data[0] != 0x00 || data[1] != 0xff)
1733 return -1;
1734
1735 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1736 * /--08--\/--09--\
1737 * 7654321076543210
1738 * |\---/\---/\---/
1739 * R C1 C2 C3 */
1740 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1741 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1742 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1743 edid->pnp_id[3] = '\0';
1744
1745 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1746 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1747 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1748 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1749 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1750 if (serial_number > 0)
1751 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1752
1753 /* parse EDID data */
1754 for (i = EDID_OFFSET_DATA_BLOCKS;
1755 i <= EDID_OFFSET_LAST_BLOCK;
1756 i += 18) {
1757 /* ignore pixel clock data */
1758 if (data[i] != 0)
1759 continue;
1760 if (data[i+2] != 0)
1761 continue;
1762
1763 /* any useful blocks? */
1764 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1765 edid_parse_string(&data[i+5],
1766 edid->monitor_name);
1767 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1768 edid_parse_string(&data[i+5],
1769 edid->serial_number);
1770 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1771 edid_parse_string(&data[i+5],
1772 edid->eisa_id);
1773 }
1774 }
1775 return 0;
1776}
1777
1778static void
1779find_and_parse_output_edid(struct drm_compositor *ec,
1780 struct drm_output *output,
1781 drmModeConnector *connector)
1782{
1783 drmModePropertyBlobPtr edid_blob = NULL;
1784 drmModePropertyPtr property;
1785 int i;
1786 int rc;
1787
1788 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1789 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1790 if (!property)
1791 continue;
1792 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1793 !strcmp(property->name, "EDID")) {
1794 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1795 connector->prop_values[i]);
1796 }
1797 drmModeFreeProperty(property);
1798 }
1799 if (!edid_blob)
1800 return;
1801
1802 rc = edid_parse(&output->edid,
1803 edid_blob->data,
1804 edid_blob->length);
1805 if (!rc) {
1806 weston_log("EDID data '%s', '%s', '%s'\n",
1807 output->edid.pnp_id,
1808 output->edid.monitor_name,
1809 output->edid.serial_number);
1810 if (output->edid.pnp_id[0] != '\0')
1811 output->base.make = output->edid.pnp_id;
1812 if (output->edid.monitor_name[0] != '\0')
1813 output->base.model = output->edid.monitor_name;
1814 if (output->edid.serial_number[0] != '\0')
1815 output->base.serial_number = output->edid.serial_number;
1816 }
1817 drmModeFreePropertyBlob(edid_blob);
1818}
1819
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001820
1821
1822static int
1823parse_modeline(const char *s, drmModeModeInfo *mode)
1824{
1825 char hsync[16];
1826 char vsync[16];
1827 float fclock;
1828
1829 mode->type = DRM_MODE_TYPE_USERDEF;
1830 mode->hskew = 0;
1831 mode->vscan = 0;
1832 mode->vrefresh = 0;
1833 mode->flags = 0;
1834
Rob Bradford307e09e2013-07-26 16:29:40 +01001835 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001836 &fclock,
1837 &mode->hdisplay,
1838 &mode->hsync_start,
1839 &mode->hsync_end,
1840 &mode->htotal,
1841 &mode->vdisplay,
1842 &mode->vsync_start,
1843 &mode->vsync_end,
1844 &mode->vtotal, hsync, vsync) != 11)
1845 return -1;
1846
1847 mode->clock = fclock * 1000;
1848 if (strcmp(hsync, "+hsync") == 0)
1849 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1850 else if (strcmp(hsync, "-hsync") == 0)
1851 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1852 else
1853 return -1;
1854
1855 if (strcmp(vsync, "+vsync") == 0)
1856 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1857 else if (strcmp(vsync, "-vsync") == 0)
1858 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1859 else
1860 return -1;
1861
1862 return 0;
1863}
1864
Rob Bradford66bd9f52013-06-25 18:56:42 +01001865static void
1866setup_output_seat_constraint(struct drm_compositor *ec,
1867 struct weston_output *output,
1868 const char *s)
1869{
1870 if (strcmp(s, "") != 0) {
1871 struct udev_seat *seat;
1872
Jonas Ådahl58e15862014-03-12 22:08:40 +01001873 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001874 if (seat)
1875 seat->base.output = output;
1876
1877 if (seat && seat->base.pointer)
1878 weston_pointer_clamp(seat->base.pointer,
1879 &seat->base.pointer->x,
1880 &seat->base.pointer->y);
1881 }
1882}
1883
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001884static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001885get_gbm_format_from_section(struct weston_config_section *section,
1886 uint32_t default_value,
1887 uint32_t *format)
1888{
1889 char *s;
1890 int ret = 0;
1891
1892 weston_config_section_get_string(section,
1893 "gbm-format", &s, NULL);
1894
1895 if (s == NULL)
1896 *format = default_value;
1897 else if (strcmp(s, "xrgb8888") == 0)
1898 *format = GBM_FORMAT_XRGB8888;
1899 else if (strcmp(s, "rgb565") == 0)
1900 *format = GBM_FORMAT_RGB565;
1901 else if (strcmp(s, "xrgb2101010") == 0)
1902 *format = GBM_FORMAT_XRGB2101010;
1903 else {
1904 weston_log("fatal: unrecognized pixel format: %s\n", s);
1905 ret = -1;
1906 }
1907
1908 free(s);
1909
1910 return ret;
1911}
1912
1913static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001914create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001915 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001916 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001917 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001918{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001919 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001920 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001921 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001922 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001923 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001924 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001925 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001926 int i, width, height, scale;
1927 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001928 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001929 enum output_config config;
1930 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001931
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001932 i = find_crtc_for_connector(ec, resources, connector);
1933 if (i < 0) {
1934 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001935 return -1;
1936 }
1937
Peter Huttererf3d62272013-08-08 11:57:05 +10001938 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001939 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001940 return -1;
1941
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001942 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1943 output->base.make = "unknown";
1944 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001945 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001946 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001947
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001948 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1949 type_name = connector_type_names[connector->connector_type];
1950 else
1951 type_name = "UNKNOWN";
1952 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001953 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001954
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001955 section = weston_config_get_section(ec->base.config, "output", "name",
1956 output->base.name);
1957 weston_config_section_get_string(section, "mode", &s, "preferred");
1958 if (strcmp(s, "off") == 0)
1959 config = OUTPUT_CONFIG_OFF;
1960 else if (strcmp(s, "preferred") == 0)
1961 config = OUTPUT_CONFIG_PREFERRED;
1962 else if (strcmp(s, "current") == 0)
1963 config = OUTPUT_CONFIG_CURRENT;
1964 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1965 config = OUTPUT_CONFIG_MODE;
1966 else if (parse_modeline(s, &modeline) == 0)
1967 config = OUTPUT_CONFIG_MODELINE;
1968 else {
1969 weston_log("Invalid mode \"%s\" for output %s\n",
1970 s, output->base.name);
1971 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001972 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001973 free(s);
1974
1975 weston_config_section_get_int(section, "scale", &scale, 1);
1976 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05001977 if (weston_parse_transform(s, &transform) < 0)
1978 weston_log("Invalid transform \"%s\" for output %s\n",
1979 s, output->base.name);
1980
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001981 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001982
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001983 if (get_gbm_format_from_section(section,
1984 ec->format,
1985 &output->format) == -1)
1986 output->format = ec->format;
1987
Rob Bradford66bd9f52013-06-25 18:56:42 +01001988 weston_config_section_get_string(section, "seat", &s, "");
1989 setup_output_seat_constraint(ec, &output->base, s);
1990 free(s);
1991
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001992 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001993 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001994 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001995 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001996 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001997
Matt Roper361d2ad2011-08-29 13:52:23 -07001998 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001999 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002000
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002001 /* Get the current mode on the crtc that's currently driving
2002 * this connector. */
2003 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002004 memset(&crtc_mode, 0, sizeof crtc_mode);
2005 if (encoder != NULL) {
2006 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2007 drmModeFreeEncoder(encoder);
2008 if (crtc == NULL)
2009 goto err_free;
2010 if (crtc->mode_valid)
2011 crtc_mode = crtc->mode;
2012 drmModeFreeCrtc(crtc);
2013 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002014
David Herrmann0f0d54e2011-12-08 17:05:45 +01002015 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002016 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002017 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002018 goto err_free;
2019 }
2020
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002021 if (config == OUTPUT_CONFIG_OFF) {
2022 weston_log("Disabling output %s\n", output->base.name);
2023 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2024 0, 0, 0, 0, 0, NULL);
2025 goto err_free;
2026 }
2027
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002028 preferred = NULL;
2029 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002030 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002031 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002032
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002033 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002034 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002035 width == drm_mode->base.width &&
2036 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002037 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002038 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002039 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002040 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002041 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002042 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002043 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002044
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002045 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002046 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002047 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002048 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002049 }
2050
Wang Quanxianacb805a2012-07-30 18:09:46 -04002051 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002052 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002053 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002054 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002055 }
2056
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002057 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002058 configured = current;
2059
Wang Quanxianacb805a2012-07-30 18:09:46 -04002060 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002061 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002062 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002063 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002064 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002065 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002066 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002067 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002068 else if (best)
2069 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002070
Hardeningff39efa2013-09-18 23:56:35 +02002071 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002072 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002073 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002074 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002075
Hardeningff39efa2013-09-18 23:56:35 +02002076 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002077
John Kåre Alsaker94659272012-11-13 19:10:18 +01002078 weston_output_init(&output->base, &ec->base, x, y,
2079 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002080 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002081
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002082 if (ec->use_pixman) {
2083 if (drm_output_init_pixman(output, ec) < 0) {
2084 weston_log("Failed to init output pixman state\n");
2085 goto err_output;
2086 }
2087 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002088 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002089 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002090 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002091
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002092 output->backlight = backlight_init(drm_device,
2093 connector->connector_type);
2094 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002095 weston_log("Initialized backlight, device %s\n",
2096 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002097 output->base.set_backlight = drm_set_backlight;
2098 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002099 } else {
2100 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002101 }
2102
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002103 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2104
Richard Hughes2b2092a2013-04-24 14:58:02 +01002105 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002106 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2107 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002108
Jonas Ådahle5a12252013-04-05 23:07:11 +02002109 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002110 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002111 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002112 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002113 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002114 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002115
Richard Hughese7299962013-05-01 21:52:12 +01002116 output->base.gamma_size = output->original_crtc->gamma_size;
2117 output->base.set_gamma = drm_output_set_gamma;
2118
Xiong Zhang97116532013-10-23 13:58:31 +08002119 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2120 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002121
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002122 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2123 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2124 &ec->base.primary_plane);
2125
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002126 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002127 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002128 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002129 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002130 m->width, m->height, m->refresh / 1000.0,
2131 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2132 ", preferred" : "",
2133 m->flags & WL_OUTPUT_MODE_CURRENT ?
2134 ", current" : "",
2135 connector->count_modes == 0 ?
2136 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002137
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002138 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002139
John Kåre Alsaker94659272012-11-13 19:10:18 +01002140err_output:
2141 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002142err_free:
2143 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2144 base.link) {
2145 wl_list_remove(&drm_mode->base.link);
2146 free(drm_mode);
2147 }
2148
2149 drmModeFreeCrtc(output->original_crtc);
2150 ec->crtc_allocator &= ~(1 << output->crtc_id);
2151 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002152 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002153
David Herrmann0f0d54e2011-12-08 17:05:45 +01002154 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002155}
2156
Jesse Barnes58ef3792012-02-23 09:45:49 -05002157static void
2158create_sprites(struct drm_compositor *ec)
2159{
2160 struct drm_sprite *sprite;
2161 drmModePlaneRes *plane_res;
2162 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002163 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002164
2165 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2166 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002167 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002168 strerror(errno));
2169 return;
2170 }
2171
2172 for (i = 0; i < plane_res->count_planes; i++) {
2173 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2174 if (!plane)
2175 continue;
2176
Peter Huttererf3d62272013-08-08 11:57:05 +10002177 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002178 plane->count_formats));
2179 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002180 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002181 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002182 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002183 continue;
2184 }
2185
Jesse Barnes58ef3792012-02-23 09:45:49 -05002186 sprite->possible_crtcs = plane->possible_crtcs;
2187 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002188 sprite->current = NULL;
2189 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002190 sprite->compositor = ec;
2191 sprite->count_formats = plane->count_formats;
2192 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002193 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002194 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002195 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002196 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2197 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002198
2199 wl_list_insert(&ec->sprite_list, &sprite->link);
2200 }
2201
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002202 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002203}
2204
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002205static void
2206destroy_sprites(struct drm_compositor *compositor)
2207{
2208 struct drm_sprite *sprite, *next;
2209 struct drm_output *output;
2210
2211 output = container_of(compositor->base.output_list.next,
2212 struct drm_output, base.link);
2213
2214 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2215 drmModeSetPlane(compositor->drm.fd,
2216 sprite->plane_id,
2217 output->crtc_id, 0, 0,
2218 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002219 drm_output_release_fb(output, sprite->current);
2220 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002221 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002222 free(sprite);
2223 }
2224}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002225
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002226static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002227create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002228 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002229{
2230 drmModeConnector *connector;
2231 drmModeRes *resources;
2232 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002233 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002234
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002235 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002236 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002237 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002238 return -1;
2239 }
2240
Jesse Barnes58ef3792012-02-23 09:45:49 -05002241 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002242 if (!ec->crtcs) {
2243 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002244 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002245 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002246
Rob Clark4339add2012-08-09 14:18:28 -05002247 ec->min_width = resources->min_width;
2248 ec->max_width = resources->max_width;
2249 ec->min_height = resources->min_height;
2250 ec->max_height = resources->max_height;
2251
Jesse Barnes58ef3792012-02-23 09:45:49 -05002252 ec->num_crtcs = resources->count_crtcs;
2253 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2254
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002255 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002256 connector = drmModeGetConnector(ec->drm.fd,
2257 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002258 if (connector == NULL)
2259 continue;
2260
2261 if (connector->connection == DRM_MODE_CONNECTED &&
2262 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002263 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002264 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002265 connector, x, y,
2266 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002267 drmModeFreeConnector(connector);
2268 continue;
2269 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002270
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002271 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002272 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002273 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002274 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002275
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002276 drmModeFreeConnector(connector);
2277 }
2278
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002279 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002280 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002281 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002282 return -1;
2283 }
2284
2285 drmModeFreeResources(resources);
2286
2287 return 0;
2288}
2289
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002290static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002291update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002292{
2293 drmModeConnector *connector;
2294 drmModeRes *resources;
2295 struct drm_output *output, *next;
2296 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002297 uint32_t connected = 0, disconnects = 0;
2298 int i;
2299
2300 resources = drmModeGetResources(ec->drm.fd);
2301 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002302 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002303 return;
2304 }
2305
2306 /* collect new connects */
2307 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002308 int connector_id = resources->connectors[i];
2309
2310 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002311 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002312 continue;
2313
David Herrmann7551cff2011-12-08 17:05:43 +01002314 if (connector->connection != DRM_MODE_CONNECTED) {
2315 drmModeFreeConnector(connector);
2316 continue;
2317 }
2318
Benjamin Franzke117483d2011-08-30 11:38:26 +02002319 connected |= (1 << connector_id);
2320
2321 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002322 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002323 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002324 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002325
2326 /* XXX: not yet needed, we die with 0 outputs */
2327 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002328 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002329 else
2330 x = 0;
2331 y = 0;
2332 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002333 connector, x, y,
2334 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002335 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002336
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002337 }
2338 drmModeFreeConnector(connector);
2339 }
2340 drmModeFreeResources(resources);
2341
2342 disconnects = ec->connector_allocator & ~connected;
2343 if (disconnects) {
2344 wl_list_for_each_safe(output, next, &ec->base.output_list,
2345 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002346 if (disconnects & (1 << output->connector_id)) {
2347 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002348 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002349 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002350 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002351 }
2352 }
2353 }
2354
2355 /* FIXME: handle zero outputs, without terminating */
2356 if (ec->connector_allocator == 0)
2357 wl_display_terminate(ec->base.wl_display);
2358}
2359
2360static int
David Herrmannd7488c22012-03-11 20:05:21 +01002361udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002362{
David Herrmannd7488c22012-03-11 20:05:21 +01002363 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002364 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002365
2366 sysnum = udev_device_get_sysnum(device);
2367 if (!sysnum || atoi(sysnum) != ec->drm.id)
2368 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002369
David Herrmann6ac52db2012-03-11 20:05:22 +01002370 val = udev_device_get_property_value(device, "HOTPLUG");
2371 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002372 return 0;
2373
David Herrmann6ac52db2012-03-11 20:05:22 +01002374 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002375}
2376
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002377static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002378udev_drm_event(int fd, uint32_t mask, void *data)
2379{
2380 struct drm_compositor *ec = data;
2381 struct udev_device *event;
2382
2383 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002384
David Herrmannd7488c22012-03-11 20:05:21 +01002385 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002386 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002387
2388 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002389
2390 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002391}
2392
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002393static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002394drm_restore(struct weston_compositor *ec)
2395{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002396 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002397}
2398
2399static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002400drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002401{
2402 struct drm_compositor *d = (struct drm_compositor *) ec;
2403
Rob Bradfordd355b802013-05-31 18:09:55 +01002404 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002405
2406 wl_event_source_remove(d->udev_drm_source);
2407 wl_event_source_remove(d->drm_source);
2408
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002409 destroy_sprites(d);
2410
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002411 weston_compositor_shutdown(ec);
2412
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002413 if (d->gbm)
2414 gbm_device_destroy(d->gbm);
2415
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002416 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002417
Rob Bradford45c15b82013-07-26 16:29:35 +01002418 close(d->drm.fd);
2419
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002420 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002421}
2422
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002423static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002424drm_compositor_set_modes(struct drm_compositor *compositor)
2425{
2426 struct drm_output *output;
2427 struct drm_mode *drm_mode;
2428 int ret;
2429
2430 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002431 if (!output->current) {
2432 /* If something that would cause the output to
2433 * switch mode happened while in another vt, we
2434 * might not have a current drm_fb. In that case,
2435 * schedule a repaint and let drm_output_repaint
2436 * handle setting the mode. */
2437 weston_output_schedule_repaint(&output->base);
2438 continue;
2439 }
2440
Hardeningff39efa2013-09-18 23:56:35 +02002441 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002442 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002443 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002444 &output->connector_id, 1,
2445 &drm_mode->mode_info);
2446 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002447 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002448 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002449 drm_mode->base.width, drm_mode->base.height,
2450 output->base.x, output->base.y);
2451 }
2452 }
2453}
2454
2455static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002456session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002457{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002458 struct weston_compositor *compositor = data;
2459 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002460 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002461 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002462
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002463 if (ec->base.session_active) {
2464 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002465 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002466 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002467 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002468 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002469 } else {
2470 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002471 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002472
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002473 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002474 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002475
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002476 /* If we have a repaint scheduled (either from a
2477 * pending pageflip or the idle handler), make sure we
2478 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002479 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002480 * further attemps at repainting. When we switch
2481 * back, we schedule a repaint, which will process
2482 * pending frame callbacks. */
2483
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002484 wl_list_for_each(output, &ec->base.output_list, base.link) {
2485 output->base.repaint_needed = 0;
2486 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002487 }
2488
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002489 output = container_of(ec->base.output_list.next,
2490 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002491
2492 wl_list_for_each(sprite, &ec->sprite_list, link)
2493 drmModeSetPlane(ec->drm.fd,
2494 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002495 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002496 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002497 };
2498}
2499
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002500static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002501switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002502{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002503 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002504
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002505 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002506}
2507
David Herrmann0af066f2012-10-29 19:21:16 +01002508/*
2509 * Find primary GPU
2510 * Some systems may have multiple DRM devices attached to a single seat. This
2511 * function loops over all devices and tries to find a PCI device with the
2512 * boot_vga sysfs attribute set to 1.
2513 * If no such device is found, the first DRM device reported by udev is used.
2514 */
2515static struct udev_device*
2516find_primary_gpu(struct drm_compositor *ec, const char *seat)
2517{
2518 struct udev_enumerate *e;
2519 struct udev_list_entry *entry;
2520 const char *path, *device_seat, *id;
2521 struct udev_device *device, *drm_device, *pci;
2522
2523 e = udev_enumerate_new(ec->udev);
2524 udev_enumerate_add_match_subsystem(e, "drm");
2525 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2526
2527 udev_enumerate_scan_devices(e);
2528 drm_device = NULL;
2529 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2530 path = udev_list_entry_get_name(entry);
2531 device = udev_device_new_from_syspath(ec->udev, path);
2532 if (!device)
2533 continue;
2534 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2535 if (!device_seat)
2536 device_seat = default_seat;
2537 if (strcmp(device_seat, seat)) {
2538 udev_device_unref(device);
2539 continue;
2540 }
2541
2542 pci = udev_device_get_parent_with_subsystem_devtype(device,
2543 "pci", NULL);
2544 if (pci) {
2545 id = udev_device_get_sysattr_value(pci, "boot_vga");
2546 if (id && !strcmp(id, "1")) {
2547 if (drm_device)
2548 udev_device_unref(drm_device);
2549 drm_device = device;
2550 break;
2551 }
2552 }
2553
2554 if (!drm_device)
2555 drm_device = device;
2556 else
2557 udev_device_unref(device);
2558 }
2559
2560 udev_enumerate_unref(e);
2561 return drm_device;
2562}
2563
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002564static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002565planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002566{
2567 struct drm_compositor *c = data;
2568
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002569 switch (key) {
2570 case KEY_C:
2571 c->cursors_are_broken ^= 1;
2572 break;
2573 case KEY_V:
2574 c->sprites_are_broken ^= 1;
2575 break;
2576 case KEY_O:
2577 c->sprites_hidden ^= 1;
2578 break;
2579 default:
2580 break;
2581 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002582}
2583
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002584#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002585static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002586recorder_destroy(struct drm_output *output)
2587{
2588 vaapi_recorder_destroy(output->recorder);
2589 output->recorder = NULL;
2590
2591 output->base.disable_planes--;
2592
2593 wl_list_remove(&output->recorder_frame_listener.link);
2594 weston_log("[libva recorder] done\n");
2595}
2596
2597static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002598recorder_frame_notify(struct wl_listener *listener, void *data)
2599{
2600 struct drm_output *output;
2601 struct drm_compositor *c;
2602 int fd, ret;
2603
2604 output = container_of(listener, struct drm_output,
2605 recorder_frame_listener);
2606 c = (struct drm_compositor *) output->base.compositor;
2607
2608 if (!output->recorder)
2609 return;
2610
2611 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2612 DRM_CLOEXEC, &fd);
2613 if (ret) {
2614 weston_log("[libva recorder] "
2615 "failed to create prime fd for front buffer\n");
2616 return;
2617 }
2618
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002619 ret = vaapi_recorder_frame(output->recorder, fd,
2620 output->current->stride);
2621 if (ret < 0) {
2622 weston_log("[libva recorder] aborted: %m\n");
2623 recorder_destroy(output);
2624 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002625}
2626
2627static void *
2628create_recorder(struct drm_compositor *c, int width, int height,
2629 const char *filename)
2630{
2631 int fd;
2632 drm_magic_t magic;
2633
2634 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2635 if (fd < 0)
2636 return NULL;
2637
2638 drmGetMagic(fd, &magic);
2639 drmAuthMagic(c->drm.fd, magic);
2640
2641 return vaapi_recorder_create(fd, width, height, filename);
2642}
2643
2644static void
2645recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2646 void *data)
2647{
2648 struct drm_compositor *c = data;
2649 struct drm_output *output;
2650 int width, height;
2651
2652 output = container_of(c->base.output_list.next,
2653 struct drm_output, base.link);
2654
2655 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002656 if (output->format != GBM_FORMAT_XRGB8888) {
2657 weston_log("failed to start vaapi recorder: "
2658 "output format not supported\n");
2659 return;
2660 }
2661
Hardeningff39efa2013-09-18 23:56:35 +02002662 width = output->base.current_mode->width;
2663 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002664
2665 output->recorder =
2666 create_recorder(c, width, height, "capture.h264");
2667 if (!output->recorder) {
2668 weston_log("failed to create vaapi recorder\n");
2669 return;
2670 }
2671
2672 output->base.disable_planes++;
2673
2674 output->recorder_frame_listener.notify = recorder_frame_notify;
2675 wl_signal_add(&output->base.frame_signal,
2676 &output->recorder_frame_listener);
2677
2678 weston_output_schedule_repaint(&output->base);
2679
2680 weston_log("[libva recorder] initialized\n");
2681 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002682 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002683 }
2684}
2685#else
2686static void
2687recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2688 void *data)
2689{
2690 weston_log("Compiled without libva support\n");
2691}
2692#endif
2693
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002694static void
2695switch_to_gl_renderer(struct drm_compositor *c)
2696{
2697 struct drm_output *output;
2698
2699 if (!c->use_pixman)
2700 return;
2701
2702 weston_log("Switching to GL renderer\n");
2703
2704 c->gbm = create_gbm_device(c->drm.fd);
2705 if (!c->gbm) {
2706 weston_log("Failed to create gbm device. "
2707 "Aborting renderer switch\n");
2708 return;
2709 }
2710
2711 wl_list_for_each(output, &c->base.output_list, base.link)
2712 pixman_renderer_output_destroy(&output->base);
2713
2714 c->base.renderer->destroy(&c->base);
2715
2716 if (drm_compositor_create_gl_renderer(c) < 0) {
2717 gbm_device_destroy(c->gbm);
2718 weston_log("Failed to create GL renderer. Quitting.\n");
2719 /* FIXME: we need a function to shutdown cleanly */
2720 assert(0);
2721 }
2722
2723 wl_list_for_each(output, &c->base.output_list, base.link)
2724 drm_output_init_egl(output, c);
2725
2726 c->use_pixman = 0;
2727}
2728
2729static void
2730renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2731 void *data)
2732{
2733 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2734
2735 switch_to_gl_renderer(c);
2736}
2737
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002738static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002739drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002740 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002741 int *argc, char *argv[],
2742 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002743{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002744 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002745 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002746 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002747 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002748 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002749 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002750
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002751 weston_log("initializing drm backend\n");
2752
Peter Huttererf3d62272013-08-08 11:57:05 +10002753 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002754 if (ec == NULL)
2755 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002756
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002757 /* KMS support for sprites is not complete yet, so disable the
2758 * functionality for now. */
2759 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002760
2761 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002762 if (get_gbm_format_from_section(section,
2763 GBM_FORMAT_XRGB8888,
2764 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002765 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002766
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002767 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002768
Daniel Stone725c2c32012-06-22 14:04:36 +01002769 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002770 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002771 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002772 goto err_base;
2773 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002774
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002775 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002776 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2777 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002778 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002779 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002780 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002781 goto err_compositor;
2782 }
2783
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002784 ec->udev = udev_new();
2785 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002786 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002787 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002788 }
2789
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002790 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002791 ec->session_listener.notify = session_notify;
2792 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002793
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002794 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002795 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002796 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002797 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002798 }
David Herrmann0af066f2012-10-29 19:21:16 +01002799 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002800
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002801 if (init_drm(ec, drm_device) < 0) {
2802 weston_log("failed to initialize kms\n");
2803 goto err_udev_dev;
2804 }
2805
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002806 if (ec->use_pixman) {
2807 if (init_pixman(ec) < 0) {
2808 weston_log("failed to initialize pixman renderer\n");
2809 goto err_udev_dev;
2810 }
2811 } else {
2812 if (init_egl(ec) < 0) {
2813 weston_log("failed to initialize egl\n");
2814 goto err_udev_dev;
2815 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002816 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002817
2818 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002819 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002820
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002821 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002822
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002823 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002824 weston_compositor_add_key_binding(&ec->base, key,
2825 MODIFIER_CTRL | MODIFIER_ALT,
2826 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002827
Jesse Barnes58ef3792012-02-23 09:45:49 -05002828 wl_list_init(&ec->sprite_list);
2829 create_sprites(ec);
2830
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002831 if (udev_input_init(&ec->input,
2832 &ec->base, ec->udev, param->seat_id) < 0) {
2833 weston_log("failed to create input devices\n");
2834 goto err_sprite;
2835 }
2836
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002837 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002838 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002839 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002840 }
2841
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002842 /* A this point we have some idea of whether or not we have a working
2843 * cursor plane. */
2844 if (!ec->cursors_are_broken)
2845 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2846
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002847 path = NULL;
2848
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002849 loop = wl_display_get_event_loop(ec->base.wl_display);
2850 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002851 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002852 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002853
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002854 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2855 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002856 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002857 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002858 }
2859 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2860 "drm", NULL);
2861 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002862 wl_event_loop_add_fd(loop,
2863 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002864 WL_EVENT_READABLE, udev_drm_event, ec);
2865
2866 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002867 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002868 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002869 }
2870
Daniel Stonea96b93c2012-06-22 14:04:37 +01002871 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002872
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002873 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002874 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002875 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002876 planes_binding, ec);
2877 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2878 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002879 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2880 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002881 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2882 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002883
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002884 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002885
2886err_udev_monitor:
2887 wl_event_source_remove(ec->udev_drm_source);
2888 udev_monitor_unref(ec->udev_monitor);
2889err_drm_source:
2890 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002891err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002892 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002893err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002894 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002895 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002896 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002897err_udev_dev:
2898 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002899err_launcher:
2900 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002901err_udev:
2902 udev_unref(ec->udev);
2903err_compositor:
2904 weston_compositor_shutdown(&ec->base);
2905err_base:
2906 free(ec);
2907 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002908}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002909
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002910WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002911backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002912 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002913{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002914 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002915
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002916 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002917 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2918 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2919 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002920 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002921 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002922 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002923
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002924 param.seat_id = default_seat;
2925
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002926 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002927
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002928 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002929}