blob: 626a2debd2aedf2e6a354f1157e12c59080d004e [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040044#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020045
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080046#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Jonas Ådahle0de3c22014-03-12 22:08:42 +010050#include "udev-input.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030054#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
55#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
56#endif
57
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030058#ifndef DRM_CAP_CURSOR_WIDTH
59#define DRM_CAP_CURSOR_WIDTH 0x8
60#endif
61
62#ifndef DRM_CAP_CURSOR_HEIGHT
63#define DRM_CAP_CURSOR_HEIGHT 0x9
64#endif
65
66#ifndef GBM_BO_USE_CURSOR
67#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
68#endif
69
Kristian Høgsberg061c4252012-06-28 11:28:15 -040070static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060071
72enum output_config {
73 OUTPUT_CONFIG_INVALID = 0,
74 OUTPUT_CONFIG_OFF,
75 OUTPUT_CONFIG_PREFERRED,
76 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060077 OUTPUT_CONFIG_MODE,
78 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060079};
80
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040081struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050082 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040083
84 struct udev *udev;
85 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040086
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010087 struct udev_monitor *udev_monitor;
88 struct wl_event_source *udev_drm_source;
89
Benjamin Franzke2af7f102011-03-02 11:14:59 +010090 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010091 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010092 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030093 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010094 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020095 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050096 uint32_t *crtcs;
97 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050098 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010099 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700100 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700101 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200102
Rob Clark4339add2012-08-09 14:18:28 -0500103 /* we need these parameters in order to not fail drmModeAddFB2()
104 * due to out of bounds dimensions, and then mistakenly set
105 * sprites_are_broken:
106 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200107 uint32_t min_width, max_width;
108 uint32_t min_height, max_height;
109 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500110
Jesse Barnes58ef3792012-02-23 09:45:49 -0500111 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500112 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200113 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500114
Rob Clarkab5b1e32012-08-09 13:24:45 -0500115 int cursors_are_broken;
116
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200117 int use_pixman;
118
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200119 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300120
Rob Bradfordd355b802013-05-31 18:09:55 +0100121 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300122
123 uint32_t cursor_width;
124 uint32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400125};
126
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400127struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500128 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400129 drmModeModeInfo mode_info;
130};
131
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132struct drm_output;
133
134struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300135 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200136 uint32_t fb_id, stride, handle, size;
137 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300138 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200139 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200140
141 /* Used by gbm fbs */
142 struct gbm_bo *bo;
143
144 /* Used by dumb fbs */
145 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300146};
147
Richard Hughes2b2092a2013-04-24 14:58:02 +0100148struct drm_edid {
149 char eisa_id[13];
150 char monitor_name[13];
151 char pnp_id[5];
152 char serial_number[13];
153};
154
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400155struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500156 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400157
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400158 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500159 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400160 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700161 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100162 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300163 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000164 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200165
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300166 int vblank_pending;
167 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800168 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300169
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400170 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400171 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400172 struct weston_plane cursor_plane;
173 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500174 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400175 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300176 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200177 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200178
179 struct drm_fb *dumb[2];
180 pixman_image_t *image[2];
181 int current_image;
182 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300183
184 struct vaapi_recorder *recorder;
185 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400186};
187
Jesse Barnes58ef3792012-02-23 09:45:49 -0500188/*
189 * An output has a primary display plane plus zero or more sprites for
190 * blending display contents.
191 */
192struct drm_sprite {
193 struct wl_list link;
194
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400195 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500196
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200197 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300198 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500199 struct drm_compositor *compositor;
200
Jesse Barnes58ef3792012-02-23 09:45:49 -0500201 uint32_t possible_crtcs;
202 uint32_t plane_id;
203 uint32_t count_formats;
204
205 int32_t src_x, src_y;
206 uint32_t src_w, src_h;
207 uint32_t dest_x, dest_y;
208 uint32_t dest_w, dest_h;
209
210 uint32_t formats[];
211};
212
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700213struct drm_parameters {
214 int connector;
215 int tty;
216 int use_pixman;
217 const char *seat_id;
218};
219
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300220static struct gl_renderer_interface *gl_renderer;
221
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500222static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400223
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400224static void
225drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400226
Jesse Barnes58ef3792012-02-23 09:45:49 -0500227static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500228drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
229{
230 struct weston_compositor *ec = output_base->compositor;
231 struct drm_compositor *c =(struct drm_compositor *) ec;
232 struct drm_output *output = (struct drm_output *) output_base;
233 int crtc;
234
235 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
236 if (c->crtcs[crtc] != output->crtc_id)
237 continue;
238
239 if (supported & (1 << crtc))
240 return -1;
241 }
242
243 return 0;
244}
245
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300246static void
247drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
248{
249 struct drm_fb *fb = data;
250 struct gbm_device *gbm = gbm_bo_get_device(bo);
251
252 if (fb->fb_id)
253 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
254
Pekka Paalanende685b82012-12-04 15:58:12 +0200255 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300256
257 free(data);
258}
259
260static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200261drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
262{
263 struct drm_fb *fb;
264 int ret;
265
266 struct drm_mode_create_dumb create_arg;
267 struct drm_mode_destroy_dumb destroy_arg;
268 struct drm_mode_map_dumb map_arg;
269
Peter Huttererf3d62272013-08-08 11:57:05 +1000270 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200271 if (!fb)
272 return NULL;
273
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700274 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200275 create_arg.bpp = 32;
276 create_arg.width = width;
277 create_arg.height = height;
278
279 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
280 if (ret)
281 goto err_fb;
282
283 fb->handle = create_arg.handle;
284 fb->stride = create_arg.pitch;
285 fb->size = create_arg.size;
286 fb->fd = ec->drm.fd;
287
288 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
289 fb->stride, fb->handle, &fb->fb_id);
290 if (ret)
291 goto err_bo;
292
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700293 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200294 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400295 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200296 if (ret)
297 goto err_add_fb;
298
299 fb->map = mmap(0, fb->size, PROT_WRITE,
300 MAP_SHARED, ec->drm.fd, map_arg.offset);
301 if (fb->map == MAP_FAILED)
302 goto err_add_fb;
303
304 return fb;
305
306err_add_fb:
307 drmModeRmFB(ec->drm.fd, fb->fb_id);
308err_bo:
309 memset(&destroy_arg, 0, sizeof(destroy_arg));
310 destroy_arg.handle = create_arg.handle;
311 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
312err_fb:
313 free(fb);
314 return NULL;
315}
316
317static void
318drm_fb_destroy_dumb(struct drm_fb *fb)
319{
320 struct drm_mode_destroy_dumb destroy_arg;
321
322 if (!fb->map)
323 return;
324
325 if (fb->fb_id)
326 drmModeRmFB(fb->fd, fb->fb_id);
327
328 weston_buffer_reference(&fb->buffer_ref, NULL);
329
330 munmap(fb->map, fb->size);
331
332 memset(&destroy_arg, 0, sizeof(destroy_arg));
333 destroy_arg.handle = fb->handle;
334 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
335
336 free(fb);
337}
338
339static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500340drm_fb_get_from_bo(struct gbm_bo *bo,
341 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300342{
343 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200345 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300346 int ret;
347
348 if (fb)
349 return fb;
350
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200351 fb = calloc(1, sizeof *fb);
352 if (!fb)
353 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354
355 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356
357 width = gbm_bo_get_width(bo);
358 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 fb->stride = gbm_bo_get_stride(bo);
360 fb->handle = gbm_bo_get_handle(bo).u32;
361 fb->size = fb->stride * height;
362 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300363
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 if (compositor->min_width > width || width > compositor->max_width ||
365 compositor->min_height > height ||
366 height > compositor->max_height) {
367 weston_log("bo geometry out of bounds\n");
368 goto err_free;
369 }
370
371 ret = -1;
372
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200373 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200374 handles[0] = fb->handle;
375 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376 offsets[0] = 0;
377
378 ret = drmModeAddFB2(compositor->drm.fd, width, height,
379 format, handles, pitches, offsets,
380 &fb->fb_id, 0);
381 if (ret) {
382 weston_log("addfb2 failed: %m\n");
383 compositor->no_addfb2 = 1;
384 compositor->sprites_are_broken = 1;
385 }
386 }
387
388 if (ret)
389 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200390 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200391
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300392 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200393 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200394 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300395 }
396
397 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
398
399 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200400
401err_free:
402 free(fb);
403 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404}
405
406static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500407drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200408{
Pekka Paalanende685b82012-12-04 15:58:12 +0200409 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200410
411 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200412
Pekka Paalanende685b82012-12-04 15:58:12 +0200413 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200414}
415
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200416static void
417drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
418{
419 if (!fb)
420 return;
421
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200422 if (fb->map &&
423 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200424 drm_fb_destroy_dumb(fb);
425 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200426 if (fb->is_client_buffer)
427 gbm_bo_destroy(fb->bo);
428 else
429 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600430 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200431 }
432}
433
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500434static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200435drm_output_check_scanout_format(struct drm_output *output,
436 struct weston_surface *es, struct gbm_bo *bo)
437{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200438 uint32_t format;
439 pixman_region32_t r;
440
441 format = gbm_bo_get_format(bo);
442
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700443 if (format == GBM_FORMAT_ARGB8888) {
444 /* We can scanout an ARGB buffer if the surface's
445 * opaque region covers the whole output, but we have
446 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800447 pixman_region32_init_rect(&r, 0, 0,
448 output->base.width,
449 output->base.height);
450 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200451
452 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500453 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200454
455 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500456 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700457
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000458 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700459 return format;
460
461 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200462}
463
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400464static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500465drm_output_prepare_scanout_view(struct weston_output *_output,
466 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500467{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400468 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500469 struct drm_compositor *c =
470 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500471 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200472 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300473 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500474 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500475
Jason Ekstranda7af7042013-10-12 22:38:11 -0500476 if (ev->geometry.x != output->base.x ||
477 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200478 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200479 buffer->width != output->base.current_mode->width ||
480 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200481 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500482 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400483 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500484
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400485 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700486 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500487
Rob Bradford9b101872012-09-14 23:25:41 +0100488 /* Unable to use the buffer for scanout */
489 if (!bo)
490 return NULL;
491
Jason Ekstranda7af7042013-10-12 22:38:11 -0500492 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500493 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300494 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400495 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300496 }
497
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500498 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 if (!output->next) {
500 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400501 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300502 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500503
Pekka Paalanende685b82012-12-04 15:58:12 +0200504 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500505
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400506 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500507}
508
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500509static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200510drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400511{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200512 struct drm_compositor *c =
513 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300514 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200516 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400517
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300518 bo = gbm_surface_lock_front_buffer(output->surface);
519 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200520 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400521 return;
522 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300523
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000524 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300525 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200526 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300527 gbm_surface_release_buffer(output->surface, bo);
528 return;
529 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400530}
531
532static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200533drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
534{
535 struct weston_compositor *ec = output->base.compositor;
536 pixman_region32_t total_damage, previous_damage;
537
538 pixman_region32_init(&total_damage);
539 pixman_region32_init(&previous_damage);
540
541 pixman_region32_copy(&previous_damage, damage);
542
543 pixman_region32_union(&total_damage, damage, &output->previous_damage);
544 pixman_region32_copy(&output->previous_damage, &previous_damage);
545
546 output->current_image ^= 1;
547
548 output->next = output->dumb[output->current_image];
549 pixman_renderer_output_set_buffer(&output->base,
550 output->image[output->current_image]);
551
552 ec->renderer->repaint_output(&output->base, &total_damage);
553
554 pixman_region32_fini(&total_damage);
555 pixman_region32_fini(&previous_damage);
556}
557
558static void
559drm_output_render(struct drm_output *output, pixman_region32_t *damage)
560{
561 struct drm_compositor *c =
562 (struct drm_compositor *) output->base.compositor;
563
564 if (c->use_pixman)
565 drm_output_render_pixman(output, damage);
566 else
567 drm_output_render_gl(output, damage);
568
569 pixman_region32_subtract(&c->base.primary_plane.damage,
570 &c->base.primary_plane.damage, damage);
571}
572
573static void
Richard Hughese7299962013-05-01 21:52:12 +0100574drm_output_set_gamma(struct weston_output *output_base,
575 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
576{
577 int rc;
578 struct drm_output *output = (struct drm_output *) output_base;
579 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
580
581 /* check */
582 if (output_base->gamma_size != size)
583 return;
584 if (!output->original_crtc)
585 return;
586
587 rc = drmModeCrtcSetGamma(compositor->drm.fd,
588 output->crtc_id,
589 size, r, g, b);
590 if (rc)
591 weston_log("set gamma failed: %m\n");
592}
593
David Herrmann1edf44c2013-10-22 17:11:26 +0200594static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500595drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400596 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100597{
598 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500599 struct drm_compositor *compositor =
600 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400602 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100604
Xiong Zhangabd5d472013-10-11 14:43:07 +0800605 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200606 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800607
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300608 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400609 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300610 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200611 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100612
Hardeningff39efa2013-09-18 23:56:35 +0200613 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200614 if (!output->current ||
615 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400616 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300617 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400618 &output->connector_id, 1,
619 &mode->mode_info);
620 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200621 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200622 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400623 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300624 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200625 }
626
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500627 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300628 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500629 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200630 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200631 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500632 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100633
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300634 output->page_flip_pending = 1;
635
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400636 drm_output_set_cursor(output);
637
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638 /*
639 * Now, update all the sprite surfaces
640 */
641 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 drmVBlank vbl = {
644 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
645 .request.sequence = 1,
646 };
647
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200648 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200649 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650 continue;
651
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200652 if (s->next && !compositor->sprites_hidden)
653 fb_id = s->next->fb_id;
654
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200656 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 s->dest_x, s->dest_y,
658 s->dest_w, s->dest_h,
659 s->src_x, s->src_y,
660 s->src_w, s->src_h);
661 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200662 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500663 ret, strerror(errno));
664
Rob Clark5ca1a472012-08-08 20:27:37 -0500665 if (output->pipe > 0)
666 vbl.request.type |= DRM_VBLANK_SECONDARY;
667
Jesse Barnes58ef3792012-02-23 09:45:49 -0500668 /*
669 * Queue a vblank signal so we know when the surface
670 * becomes active on the display or has been replaced.
671 */
672 vbl.request.signal = (unsigned long)s;
673 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
674 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200675 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500676 ret, strerror(errno));
677 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300678
679 s->output = output;
680 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681 }
682
David Herrmann1edf44c2013-10-22 17:11:26 +0200683 return 0;
684
685err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800686 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200687 if (output->next) {
688 drm_output_release_fb(output, output->next);
689 output->next = NULL;
690 }
691
692 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400693}
694
695static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200696drm_output_start_repaint_loop(struct weston_output *output_base)
697{
698 struct drm_output *output = (struct drm_output *) output_base;
699 struct drm_compositor *compositor = (struct drm_compositor *)
700 output_base->compositor;
701 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300702 struct timespec ts;
703
Xiong Zhangabd5d472013-10-11 14:43:07 +0800704 if (output->destroy_pending)
705 return;
706
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300707 if (!output->current) {
708 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200709 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300710 }
711
712 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200713
714 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
715 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
716 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200717 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200718 }
David Herrmann3c688c52013-10-22 17:11:25 +0200719
720 return;
721
722finish_frame:
723 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400724 clock_gettime(compositor->base.presentation_clock, &ts);
725 weston_output_finish_frame(output_base, &ts);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200726}
727
728static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500729vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
730 void *data)
731{
732 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300733 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400734 struct timespec ts;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300735
736 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500737
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200738 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200739 s->current = s->next;
740 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300741
742 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400743 ts.tv_sec = sec;
744 ts.tv_nsec = usec * 1000;
745 weston_output_finish_frame(&output->base, &ts);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300746 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500747}
748
749static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800750drm_output_destroy(struct weston_output *output_base);
751
752static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400753page_flip_handler(int fd, unsigned int frame,
754 unsigned int sec, unsigned int usec, void *data)
755{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200756 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400757 struct timespec ts;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400758
Jonas Ådahle5a12252013-04-05 23:07:11 +0200759 /* We don't set page_flip_pending on start_repaint_loop, in that case
760 * we just want to page flip to the current buffer to get an accurate
761 * timestamp */
762 if (output->page_flip_pending) {
763 drm_output_release_fb(output, output->current);
764 output->current = output->next;
765 output->next = NULL;
766 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300767
Jonas Ådahle5a12252013-04-05 23:07:11 +0200768 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400769
Xiong Zhangabd5d472013-10-11 14:43:07 +0800770 if (output->destroy_pending)
771 drm_output_destroy(&output->base);
772 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400773 ts.tv_sec = sec;
774 ts.tv_nsec = usec * 1000;
775 weston_output_finish_frame(&output->base, &ts);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300776
777 /* We can't call this from frame_notify, because the output's
778 * repaint needed flag is cleared just after that */
779 if (output->recorder)
780 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300781 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200782}
783
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500784static uint32_t
785drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500786 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500787{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500788 uint32_t i, format;
789
790 format = gbm_bo_get_format(bo);
791
792 if (format == GBM_FORMAT_ARGB8888) {
793 pixman_region32_t r;
794
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500795 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600796 ev->surface->width,
797 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500798 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500799
800 if (!pixman_region32_not_empty(&r))
801 format = GBM_FORMAT_XRGB8888;
802
803 pixman_region32_fini(&r);
804 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500805
806 for (i = 0; i < s->count_formats; i++)
807 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500808 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809
810 return 0;
811}
812
813static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500814drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500816 return !ev->transform.enabled ||
817 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818}
819
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400820static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500821drm_output_prepare_overlay_view(struct weston_output *output_base,
822 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823{
824 struct weston_compositor *ec = output_base->compositor;
825 struct drm_compositor *c =(struct drm_compositor *) ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200826 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500827 struct drm_sprite *s;
828 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500829 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500830 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200831 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500832 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400833 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200835 if (c->gbm == NULL)
836 return NULL;
837
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200838 if (viewport->buffer.transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200839 return NULL;
840
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200841 if (viewport->buffer.scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200842 return NULL;
843
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500844 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400845 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500846
Jason Ekstranda7af7042013-10-12 22:38:11 -0500847 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400848 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300849
Jason Ekstranda7af7042013-10-12 22:38:11 -0500850 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400851 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500852
Jason Ekstranda7af7042013-10-12 22:38:11 -0500853 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200854 return NULL;
855
Jason Ekstranda7af7042013-10-12 22:38:11 -0500856 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500857 return NULL;
858
Jason Ekstranda7af7042013-10-12 22:38:11 -0500859 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400860 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500861
Jesse Barnes58ef3792012-02-23 09:45:49 -0500862 wl_list_for_each(s, &c->sprite_list, link) {
863 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
864 continue;
865
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200866 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500867 found = 1;
868 break;
869 }
870 }
871
872 /* No sprites available */
873 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400874 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500875
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400876 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500877 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700878 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400879 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400880 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400881
Jason Ekstranda7af7042013-10-12 22:38:11 -0500882 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500883 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200884 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400885 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500886 }
887
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200888 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200889 if (!s->next) {
890 gbm_bo_destroy(bo);
891 return NULL;
892 }
893
Jason Ekstranda7af7042013-10-12 22:38:11 -0500894 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500895
Jason Ekstranda7af7042013-10-12 22:38:11 -0500896 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400897 s->plane.x = box->x1;
898 s->plane.y = box->y1;
899
Jesse Barnes58ef3792012-02-23 09:45:49 -0500900 /*
901 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500902 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500903 * for us already).
904 */
905 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500906 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500907 &output_base->region);
908 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
909 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200910 tbox = weston_transformed_rect(output_base->width,
911 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200912 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200913 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200914 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200915 s->dest_x = tbox.x1;
916 s->dest_y = tbox.y1;
917 s->dest_w = tbox.x2 - tbox.x1;
918 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500919 pixman_region32_fini(&dest_rect);
920
921 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500922 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500923 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500924 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400925
Jason Ekstranda7af7042013-10-12 22:38:11 -0500926 weston_view_from_global_fixed(ev,
927 wl_fixed_from_int(box->x1),
928 wl_fixed_from_int(box->y1),
929 &sx1, &sy1);
930 weston_view_from_global_fixed(ev,
931 wl_fixed_from_int(box->x2),
932 wl_fixed_from_int(box->y2),
933 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400934
935 if (sx1 < 0)
936 sx1 = 0;
937 if (sy1 < 0)
938 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600939 if (sx2 > wl_fixed_from_int(ev->surface->width))
940 sx2 = wl_fixed_from_int(ev->surface->width);
941 if (sy2 > wl_fixed_from_int(ev->surface->height))
942 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400943
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200944 tbox.x1 = sx1;
945 tbox.y1 = sy1;
946 tbox.x2 = sx2;
947 tbox.y2 = sy2;
948
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600949 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
950 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200951 viewport->buffer.transform,
952 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100953 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200954
955 s->src_x = tbox.x1 << 8;
956 s->src_y = tbox.y1 << 8;
957 s->src_w = (tbox.x2 - tbox.x1) << 8;
958 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500959 pixman_region32_fini(&src_rect);
960
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400961 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500962}
963
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400964static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500965drm_output_prepare_cursor_view(struct weston_output *output_base,
966 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500967{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400968 struct drm_compositor *c =
969 (struct drm_compositor *) output_base->compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100970 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400971 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400972
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200973 if (c->gbm == NULL)
974 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200975 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
976 return NULL;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100977 if (viewport->buffer.scale != output_base->current_scale)
978 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500979 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400980 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500981 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400982 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500983 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400984 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500985 if (ev->surface->buffer_ref.buffer == NULL ||
986 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600987 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400988 return NULL;
989
Jason Ekstranda7af7042013-10-12 22:38:11 -0500990 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400991
992 return &output->cursor_plane;
993}
994
995static void
996drm_output_set_cursor(struct drm_output *output)
997{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500998 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +0000999 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001000 struct drm_compositor *c =
1001 (struct drm_compositor *) output->base.compositor;
1002 EGLint handle, stride;
1003 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001004 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001005 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001006 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001007
Jason Ekstranda7af7042013-10-12 22:38:11 -05001008 output->cursor_view = NULL;
1009 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001010 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1011 return;
1012 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001013
Neil Robertse5051712013-11-13 15:44:06 +00001014 buffer = ev->surface->buffer_ref.buffer;
1015
1016 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001017 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001018 pixman_region32_fini(&output->cursor_plane.damage);
1019 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001020 output->current_cursor ^= 1;
1021 bo = output->cursor_bo[output->current_cursor];
1022 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001023 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1024 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1025 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001026 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001027 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001028 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001029 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001030
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001031 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001032 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001033
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001034 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001035 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1036 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001037 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001038 c->cursors_are_broken = 1;
1039 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001040 }
1041
Jason Ekstranda7af7042013-10-12 22:38:11 -05001042 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1043 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001044 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001045 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001046 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001047 c->cursors_are_broken = 1;
1048 }
1049
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001050 output->cursor_plane.x = x;
1051 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001052 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001053}
1054
Jesse Barnes58ef3792012-02-23 09:45:49 -05001055static void
1056drm_assign_planes(struct weston_output *output)
1057{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001058 struct drm_compositor *c =
1059 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001060 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001061 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001062 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001063
1064 /*
1065 * Find a surface for each sprite in the output using some heuristics:
1066 * 1) size
1067 * 2) frequency of update
1068 * 3) opacity (though some hw might support alpha blending)
1069 * 4) clipping (this can be fixed with color keys)
1070 *
1071 * The idea is to save on blitting since this should save power.
1072 * If we can get a large video surface on the sprite for example,
1073 * the main display surface may not need to update at all, and
1074 * the client buffer can be used directly for the sprite surface
1075 * as we do for flipping full screen surfaces.
1076 */
1077 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001078 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001079
Jason Ekstranda7af7042013-10-12 22:38:11 -05001080 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001081 struct weston_surface *es = ev->surface;
1082
1083 /* Test whether this buffer can ever go into a plane:
1084 * non-shm, or small enough to be a cursor.
1085 *
1086 * Also, keep a reference when using the pixman renderer.
1087 * That makes it possible to do a seamless switch to the GL
1088 * renderer and since the pixman renderer keeps a reference
1089 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001090 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001091 if (c->use_pixman ||
1092 (es->buffer_ref.buffer &&
1093 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001094 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001095 es->keep_buffer = 1;
1096 else
1097 es->keep_buffer = 0;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001098
Jesse Barnes58ef3792012-02-23 09:45:49 -05001099 pixman_region32_init(&surface_overlap);
1100 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001101 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001102
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001103 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001104 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001105 next_plane = primary;
1106 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001107 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001108 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001109 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001110 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001111 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001112 if (next_plane == NULL)
1113 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001114 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001115 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001116 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001117 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001118
Jesse Barnes58ef3792012-02-23 09:45:49 -05001119 pixman_region32_fini(&surface_overlap);
1120 }
1121 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001122}
1123
Matt Roper361d2ad2011-08-29 13:52:23 -07001124static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001125drm_output_fini_pixman(struct drm_output *output);
1126
1127static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001128drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001129{
1130 struct drm_output *output = (struct drm_output *) output_base;
1131 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001132 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001133 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001134
Xiong Zhangabd5d472013-10-11 14:43:07 +08001135 if (output->page_flip_pending) {
1136 output->destroy_pending = 1;
1137 weston_log("destroy output while page flip pending\n");
1138 return;
1139 }
1140
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001141 if (output->backlight)
1142 backlight_destroy(output->backlight);
1143
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001144 drmModeFreeProperty(output->dpms_prop);
1145
Matt Roper361d2ad2011-08-29 13:52:23 -07001146 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001147 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001148
1149 /* Restore original CRTC state */
1150 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001151 origcrtc->x, origcrtc->y,
1152 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001153 drmModeFreeCrtc(origcrtc);
1154
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001155 c->crtc_allocator &= ~(1 << output->crtc_id);
1156 c->connector_allocator &= ~(1 << output->connector_id);
1157
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001158 if (c->use_pixman) {
1159 drm_output_fini_pixman(output);
1160 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001161 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001162 gbm_surface_destroy(output->surface);
1163 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001164
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001165 weston_plane_release(&output->fb_plane);
1166 weston_plane_release(&output->cursor_plane);
1167
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001168 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001169
Matt Roper361d2ad2011-08-29 13:52:23 -07001170 free(output);
1171}
1172
Alex Wub7b8bda2012-04-17 17:20:48 +08001173static struct drm_mode *
1174choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1175{
1176 struct drm_mode *tmp_mode = NULL, *mode;
1177
Hardeningff39efa2013-09-18 23:56:35 +02001178 if (output->base.current_mode->width == target_mode->width &&
1179 output->base.current_mode->height == target_mode->height &&
1180 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001181 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001182 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001183
1184 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1185 if (mode->mode_info.hdisplay == target_mode->width &&
1186 mode->mode_info.vdisplay == target_mode->height) {
1187 if (mode->mode_info.vrefresh == target_mode->refresh ||
1188 target_mode->refresh == 0) {
1189 return mode;
1190 } else if (!tmp_mode)
1191 tmp_mode = mode;
1192 }
1193 }
1194
1195 return tmp_mode;
1196}
1197
1198static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001199drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001200static int
1201drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001202
1203static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001204drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1205{
1206 struct drm_output *output;
1207 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001208 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001209
1210 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001211 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001212 return -1;
1213 }
1214
1215 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001216 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001217 return -1;
1218 }
1219
1220 ec = (struct drm_compositor *)output_base->compositor;
1221 output = (struct drm_output *)output_base;
1222 drm_mode = choose_mode (output, mode);
1223
1224 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001225 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001226 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001227 }
1228
Hardeningff39efa2013-09-18 23:56:35 +02001229 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001230 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001231
Hardeningff39efa2013-09-18 23:56:35 +02001232 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001233
Hardeningff39efa2013-09-18 23:56:35 +02001234 output->base.current_mode = &drm_mode->base;
1235 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001236 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1237
Alex Wub7b8bda2012-04-17 17:20:48 +08001238 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001239 drm_output_release_fb(output, output->current);
1240 drm_output_release_fb(output, output->next);
1241 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001242
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001243 if (ec->use_pixman) {
1244 drm_output_fini_pixman(output);
1245 if (drm_output_init_pixman(output, ec) < 0) {
1246 weston_log("failed to init output pixman state with "
1247 "new mode\n");
1248 return -1;
1249 }
1250 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001251 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001252 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001253
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001254 if (drm_output_init_egl(output, ec) < 0) {
1255 weston_log("failed to init output egl state with "
1256 "new mode");
1257 return -1;
1258 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001259 }
1260
Alex Wub7b8bda2012-04-17 17:20:48 +08001261 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001262}
1263
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001264static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001265on_drm_input(int fd, uint32_t mask, void *data)
1266{
1267 drmEventContext evctx;
1268
1269 memset(&evctx, 0, sizeof evctx);
1270 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1271 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001272 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001273 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001274
1275 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001276}
1277
1278static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001279init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001280{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001281 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001282 uint64_t cap;
1283 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001284 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001285
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001286 sysnum = udev_device_get_sysnum(device);
1287 if (sysnum)
1288 ec->drm.id = atoi(sysnum);
1289 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001290 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001291 return -1;
1292 }
1293
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001294 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001295 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001296 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001297 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001298 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001299 udev_device_get_devnode(device));
1300 return -1;
1301 }
1302
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001303 weston_log("using %s\n", filename);
1304
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001305 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001306 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001307
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001308 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1309 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001310 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001311 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001312 clk_id = CLOCK_REALTIME;
1313
1314 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1315 weston_log("Error: failed to set presentation clock %d.\n",
1316 clk_id);
1317 return -1;
1318 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001319
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001320 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1321 if (ret == 0)
1322 ec->cursor_width = cap;
1323 else
1324 ec->cursor_width = 64;
1325
1326 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1327 if (ret == 0)
1328 ec->cursor_height = cap;
1329 else
1330 ec->cursor_height = 64;
1331
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001332 return 0;
1333}
1334
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001335static struct gbm_device *
1336create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001337{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001338 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001339
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001340 gl_renderer = weston_load_module("gl-renderer.so",
1341 "gl_renderer_interface");
1342 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001343 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001344
1345 /* GBM will load a dri driver, but even though they need symbols from
1346 * libglapi, in some version of Mesa they are not linked to it. Since
1347 * only the gl-renderer module links to it, the call above won't make
1348 * these symbols globally available, and loading the DRI driver fails.
1349 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1350 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1351
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001352 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001353
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001354 return gbm;
1355}
1356
1357static int
1358drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1359{
1360 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001361
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001362 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001363 if (gl_renderer->create(&ec->base, ec->gbm,
1364 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001365 return -1;
1366 }
1367
1368 return 0;
1369}
1370
1371static int
1372init_egl(struct drm_compositor *ec)
1373{
1374 ec->gbm = create_gbm_device(ec->drm.fd);
1375
1376 if (!ec->gbm)
1377 return -1;
1378
1379 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001380 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001381 return -1;
1382 }
1383
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001384 return 0;
1385}
1386
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001387static int
1388init_pixman(struct drm_compositor *ec)
1389{
1390 return pixman_renderer_init(&ec->base);
1391}
1392
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001393static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001394drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001395{
1396 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001397 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001398
1399 mode = malloc(sizeof *mode);
1400 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001401 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001402
1403 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001404 mode->base.width = info->hdisplay;
1405 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001406
1407 /* Calculate higher precision (mHz) refresh rate */
1408 refresh = (info->clock * 1000000LL / info->htotal +
1409 info->vtotal / 2) / info->vtotal;
1410
1411 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1412 refresh *= 2;
1413 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1414 refresh /= 2;
1415 if (info->vscan > 1)
1416 refresh /= info->vscan;
1417
1418 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001419 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420
1421 if (info->type & DRM_MODE_TYPE_PREFERRED)
1422 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1423
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001424 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1425
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001426 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001427}
1428
1429static int
1430drm_subpixel_to_wayland(int drm_value)
1431{
1432 switch (drm_value) {
1433 default:
1434 case DRM_MODE_SUBPIXEL_UNKNOWN:
1435 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1436 case DRM_MODE_SUBPIXEL_NONE:
1437 return WL_OUTPUT_SUBPIXEL_NONE;
1438 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1439 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1440 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1441 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1442 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1443 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1444 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1445 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1446 }
1447}
1448
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001449/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001450static uint32_t
1451drm_get_backlight(struct drm_output *output)
1452{
1453 long brightness, max_brightness, norm;
1454
1455 brightness = backlight_get_brightness(output->backlight);
1456 max_brightness = backlight_get_max_brightness(output->backlight);
1457
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001458 /* convert it on a scale of 0 to 255 */
1459 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001460
1461 return (uint32_t) norm;
1462}
1463
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001464/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001465static void
1466drm_set_backlight(struct weston_output *output_base, uint32_t value)
1467{
1468 struct drm_output *output = (struct drm_output *) output_base;
1469 long max_brightness, new_brightness;
1470
1471 if (!output->backlight)
1472 return;
1473
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001474 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001475 return;
1476
1477 max_brightness = backlight_get_max_brightness(output->backlight);
1478
1479 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001480 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001481
1482 backlight_set_brightness(output->backlight, new_brightness);
1483}
1484
1485static drmModePropertyPtr
1486drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1487{
1488 drmModePropertyPtr props;
1489 int i;
1490
1491 for (i = 0; i < connector->count_props; i++) {
1492 props = drmModeGetProperty(fd, connector->props[i]);
1493 if (!props)
1494 continue;
1495
1496 if (!strcmp(props->name, name))
1497 return props;
1498
1499 drmModeFreeProperty(props);
1500 }
1501
1502 return NULL;
1503}
1504
1505static void
1506drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1507{
1508 struct drm_output *output = (struct drm_output *) output_base;
1509 struct weston_compositor *ec = output_base->compositor;
1510 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001511
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001512 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001513 return;
1514
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001515 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1516 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001517}
1518
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001519static const char *connector_type_names[] = {
1520 "None",
1521 "VGA",
1522 "DVI",
1523 "DVI",
1524 "DVI",
1525 "Composite",
1526 "TV",
1527 "LVDS",
1528 "CTV",
1529 "DIN",
1530 "DP",
1531 "HDMI",
1532 "HDMI",
1533 "TV",
1534 "eDP",
1535};
1536
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001537static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001538find_crtc_for_connector(struct drm_compositor *ec,
1539 drmModeRes *resources, drmModeConnector *connector)
1540{
1541 drmModeEncoder *encoder;
1542 uint32_t possible_crtcs;
1543 int i, j;
1544
1545 for (j = 0; j < connector->count_encoders; j++) {
1546 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1547 if (encoder == NULL) {
1548 weston_log("Failed to get encoder.\n");
1549 return -1;
1550 }
1551 possible_crtcs = encoder->possible_crtcs;
1552 drmModeFreeEncoder(encoder);
1553
1554 for (i = 0; i < resources->count_crtcs; i++) {
1555 if (possible_crtcs & (1 << i) &&
1556 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1557 return i;
1558 }
1559 }
1560
1561 return -1;
1562}
1563
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001564/* Init output state that depends on gl or gbm */
1565static int
1566drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1567{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001568 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001569 int i, flags;
1570
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001571 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001572 output->base.current_mode->width,
1573 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001574 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001575 GBM_BO_USE_SCANOUT |
1576 GBM_BO_USE_RENDERING);
1577 if (!output->surface) {
1578 weston_log("failed to create gbm surface\n");
1579 return -1;
1580 }
1581
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001582 if (gl_renderer->output_create(&output->base, output->surface,
1583 gl_renderer->opaque_attribs,
1584 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001585 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001586 gbm_surface_destroy(output->surface);
1587 return -1;
1588 }
1589
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001590 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001591
1592 for (i = 0; i < 2; i++) {
1593 if (output->cursor_bo[i])
1594 continue;
1595
1596 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001597 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1598 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001599 }
1600
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001601 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1602 weston_log("cursor buffers unavailable, using gl cursors\n");
1603 ec->cursors_are_broken = 1;
1604 }
1605
1606 return 0;
1607}
1608
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001609static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001610drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1611{
Hardeningff39efa2013-09-18 23:56:35 +02001612 int w = output->base.current_mode->width;
1613 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001614 unsigned int i;
1615
1616 /* FIXME error checking */
1617
1618 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001619 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001620 if (!output->dumb[i])
1621 goto err;
1622
1623 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001624 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001625 output->dumb[i]->map,
1626 output->dumb[i]->stride);
1627 if (!output->image[i])
1628 goto err;
1629 }
1630
1631 if (pixman_renderer_output_create(&output->base) < 0)
1632 goto err;
1633
1634 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001635 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001636
1637 return 0;
1638
1639err:
1640 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1641 if (output->dumb[i])
1642 drm_fb_destroy_dumb(output->dumb[i]);
1643 if (output->image[i])
1644 pixman_image_unref(output->image[i]);
1645
1646 output->dumb[i] = NULL;
1647 output->image[i] = NULL;
1648 }
1649
1650 return -1;
1651}
1652
1653static void
1654drm_output_fini_pixman(struct drm_output *output)
1655{
1656 unsigned int i;
1657
1658 pixman_renderer_output_destroy(&output->base);
1659 pixman_region32_fini(&output->previous_damage);
1660
1661 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1662 drm_fb_destroy_dumb(output->dumb[i]);
1663 pixman_image_unref(output->image[i]);
1664 output->dumb[i] = NULL;
1665 output->image[i] = NULL;
1666 }
1667}
1668
Richard Hughes2b2092a2013-04-24 14:58:02 +01001669static void
1670edid_parse_string(const uint8_t *data, char text[])
1671{
1672 int i;
1673 int replaced = 0;
1674
1675 /* this is always 12 bytes, but we can't guarantee it's null
1676 * terminated or not junk. */
1677 strncpy(text, (const char *) data, 12);
1678
1679 /* remove insane chars */
1680 for (i = 0; text[i] != '\0'; i++) {
1681 if (text[i] == '\n' ||
1682 text[i] == '\r') {
1683 text[i] = '\0';
1684 break;
1685 }
1686 }
1687
1688 /* ensure string is printable */
1689 for (i = 0; text[i] != '\0'; i++) {
1690 if (!isprint(text[i])) {
1691 text[i] = '-';
1692 replaced++;
1693 }
1694 }
1695
1696 /* if the string is random junk, ignore the string */
1697 if (replaced > 4)
1698 text[0] = '\0';
1699}
1700
1701#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1702#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1703#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1704#define EDID_OFFSET_DATA_BLOCKS 0x36
1705#define EDID_OFFSET_LAST_BLOCK 0x6c
1706#define EDID_OFFSET_PNPID 0x08
1707#define EDID_OFFSET_SERIAL 0x0c
1708
1709static int
1710edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1711{
1712 int i;
1713 uint32_t serial_number;
1714
1715 /* check header */
1716 if (length < 128)
1717 return -1;
1718 if (data[0] != 0x00 || data[1] != 0xff)
1719 return -1;
1720
1721 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1722 * /--08--\/--09--\
1723 * 7654321076543210
1724 * |\---/\---/\---/
1725 * R C1 C2 C3 */
1726 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1727 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1728 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1729 edid->pnp_id[3] = '\0';
1730
1731 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1732 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1733 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1734 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1735 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1736 if (serial_number > 0)
1737 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1738
1739 /* parse EDID data */
1740 for (i = EDID_OFFSET_DATA_BLOCKS;
1741 i <= EDID_OFFSET_LAST_BLOCK;
1742 i += 18) {
1743 /* ignore pixel clock data */
1744 if (data[i] != 0)
1745 continue;
1746 if (data[i+2] != 0)
1747 continue;
1748
1749 /* any useful blocks? */
1750 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1751 edid_parse_string(&data[i+5],
1752 edid->monitor_name);
1753 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1754 edid_parse_string(&data[i+5],
1755 edid->serial_number);
1756 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1757 edid_parse_string(&data[i+5],
1758 edid->eisa_id);
1759 }
1760 }
1761 return 0;
1762}
1763
1764static void
1765find_and_parse_output_edid(struct drm_compositor *ec,
1766 struct drm_output *output,
1767 drmModeConnector *connector)
1768{
1769 drmModePropertyBlobPtr edid_blob = NULL;
1770 drmModePropertyPtr property;
1771 int i;
1772 int rc;
1773
1774 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1775 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1776 if (!property)
1777 continue;
1778 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1779 !strcmp(property->name, "EDID")) {
1780 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1781 connector->prop_values[i]);
1782 }
1783 drmModeFreeProperty(property);
1784 }
1785 if (!edid_blob)
1786 return;
1787
1788 rc = edid_parse(&output->edid,
1789 edid_blob->data,
1790 edid_blob->length);
1791 if (!rc) {
1792 weston_log("EDID data '%s', '%s', '%s'\n",
1793 output->edid.pnp_id,
1794 output->edid.monitor_name,
1795 output->edid.serial_number);
1796 if (output->edid.pnp_id[0] != '\0')
1797 output->base.make = output->edid.pnp_id;
1798 if (output->edid.monitor_name[0] != '\0')
1799 output->base.model = output->edid.monitor_name;
1800 if (output->edid.serial_number[0] != '\0')
1801 output->base.serial_number = output->edid.serial_number;
1802 }
1803 drmModeFreePropertyBlob(edid_blob);
1804}
1805
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001806
1807
1808static int
1809parse_modeline(const char *s, drmModeModeInfo *mode)
1810{
1811 char hsync[16];
1812 char vsync[16];
1813 float fclock;
1814
1815 mode->type = DRM_MODE_TYPE_USERDEF;
1816 mode->hskew = 0;
1817 mode->vscan = 0;
1818 mode->vrefresh = 0;
1819 mode->flags = 0;
1820
Rob Bradford307e09e2013-07-26 16:29:40 +01001821 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001822 &fclock,
1823 &mode->hdisplay,
1824 &mode->hsync_start,
1825 &mode->hsync_end,
1826 &mode->htotal,
1827 &mode->vdisplay,
1828 &mode->vsync_start,
1829 &mode->vsync_end,
1830 &mode->vtotal, hsync, vsync) != 11)
1831 return -1;
1832
1833 mode->clock = fclock * 1000;
1834 if (strcmp(hsync, "+hsync") == 0)
1835 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1836 else if (strcmp(hsync, "-hsync") == 0)
1837 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1838 else
1839 return -1;
1840
1841 if (strcmp(vsync, "+vsync") == 0)
1842 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1843 else if (strcmp(vsync, "-vsync") == 0)
1844 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1845 else
1846 return -1;
1847
1848 return 0;
1849}
1850
1851static uint32_t
1852parse_transform(const char *transform, const char *output_name)
1853{
1854 static const struct { const char *name; uint32_t token; } names[] = {
1855 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1856 { "90", WL_OUTPUT_TRANSFORM_90 },
1857 { "180", WL_OUTPUT_TRANSFORM_180 },
1858 { "270", WL_OUTPUT_TRANSFORM_270 },
1859 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1860 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1861 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1862 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1863 };
1864 unsigned int i;
1865
1866 for (i = 0; i < ARRAY_LENGTH(names); i++)
1867 if (strcmp(names[i].name, transform) == 0)
1868 return names[i].token;
1869
1870 weston_log("Invalid transform \"%s\" for output %s\n",
1871 transform, output_name);
1872
1873 return WL_OUTPUT_TRANSFORM_NORMAL;
1874}
1875
Rob Bradford66bd9f52013-06-25 18:56:42 +01001876static void
1877setup_output_seat_constraint(struct drm_compositor *ec,
1878 struct weston_output *output,
1879 const char *s)
1880{
1881 if (strcmp(s, "") != 0) {
1882 struct udev_seat *seat;
1883
Jonas Ådahl58e15862014-03-12 22:08:40 +01001884 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001885 if (seat)
1886 seat->base.output = output;
1887
1888 if (seat && seat->base.pointer)
1889 weston_pointer_clamp(seat->base.pointer,
1890 &seat->base.pointer->x,
1891 &seat->base.pointer->y);
1892 }
1893}
1894
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001895static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001896get_gbm_format_from_section(struct weston_config_section *section,
1897 uint32_t default_value,
1898 uint32_t *format)
1899{
1900 char *s;
1901 int ret = 0;
1902
1903 weston_config_section_get_string(section,
1904 "gbm-format", &s, NULL);
1905
1906 if (s == NULL)
1907 *format = default_value;
1908 else if (strcmp(s, "xrgb8888") == 0)
1909 *format = GBM_FORMAT_XRGB8888;
1910 else if (strcmp(s, "rgb565") == 0)
1911 *format = GBM_FORMAT_RGB565;
1912 else if (strcmp(s, "xrgb2101010") == 0)
1913 *format = GBM_FORMAT_XRGB2101010;
1914 else {
1915 weston_log("fatal: unrecognized pixel format: %s\n", s);
1916 ret = -1;
1917 }
1918
1919 free(s);
1920
1921 return ret;
1922}
1923
1924static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001925create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001926 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001927 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001928 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001929{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001930 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001931 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001932 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001933 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001934 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001935 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001936 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001937 int i, width, height, scale;
1938 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001939 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001940 enum output_config config;
1941 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001942
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001943 i = find_crtc_for_connector(ec, resources, connector);
1944 if (i < 0) {
1945 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001946 return -1;
1947 }
1948
Peter Huttererf3d62272013-08-08 11:57:05 +10001949 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001950 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001951 return -1;
1952
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001953 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1954 output->base.make = "unknown";
1955 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001956 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001957 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001958
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001959 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1960 type_name = connector_type_names[connector->connector_type];
1961 else
1962 type_name = "UNKNOWN";
1963 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001964 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001965
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001966 section = weston_config_get_section(ec->base.config, "output", "name",
1967 output->base.name);
1968 weston_config_section_get_string(section, "mode", &s, "preferred");
1969 if (strcmp(s, "off") == 0)
1970 config = OUTPUT_CONFIG_OFF;
1971 else if (strcmp(s, "preferred") == 0)
1972 config = OUTPUT_CONFIG_PREFERRED;
1973 else if (strcmp(s, "current") == 0)
1974 config = OUTPUT_CONFIG_CURRENT;
1975 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1976 config = OUTPUT_CONFIG_MODE;
1977 else if (parse_modeline(s, &modeline) == 0)
1978 config = OUTPUT_CONFIG_MODELINE;
1979 else {
1980 weston_log("Invalid mode \"%s\" for output %s\n",
1981 s, output->base.name);
1982 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001983 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001984 free(s);
1985
1986 weston_config_section_get_int(section, "scale", &scale, 1);
1987 weston_config_section_get_string(section, "transform", &s, "normal");
1988 transform = parse_transform(s, output->base.name);
1989 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001990
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001991 if (get_gbm_format_from_section(section,
1992 ec->format,
1993 &output->format) == -1)
1994 output->format = ec->format;
1995
Rob Bradford66bd9f52013-06-25 18:56:42 +01001996 weston_config_section_get_string(section, "seat", &s, "");
1997 setup_output_seat_constraint(ec, &output->base, s);
1998 free(s);
1999
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002000 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002001 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002002 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002003 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002004 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002005
Matt Roper361d2ad2011-08-29 13:52:23 -07002006 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002007 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002008
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002009 /* Get the current mode on the crtc that's currently driving
2010 * this connector. */
2011 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002012 memset(&crtc_mode, 0, sizeof crtc_mode);
2013 if (encoder != NULL) {
2014 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2015 drmModeFreeEncoder(encoder);
2016 if (crtc == NULL)
2017 goto err_free;
2018 if (crtc->mode_valid)
2019 crtc_mode = crtc->mode;
2020 drmModeFreeCrtc(crtc);
2021 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002022
David Herrmann0f0d54e2011-12-08 17:05:45 +01002023 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002024 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002025 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002026 goto err_free;
2027 }
2028
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002029 if (config == OUTPUT_CONFIG_OFF) {
2030 weston_log("Disabling output %s\n", output->base.name);
2031 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2032 0, 0, 0, 0, 0, NULL);
2033 goto err_free;
2034 }
2035
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002036 preferred = NULL;
2037 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002038 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002039 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002040
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002041 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002042 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002043 width == drm_mode->base.width &&
2044 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002045 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002046 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002047 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002048 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002049 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002050 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002051 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002052
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002053 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002054 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002055 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002056 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002057 }
2058
Wang Quanxianacb805a2012-07-30 18:09:46 -04002059 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002060 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002061 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002062 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002063 }
2064
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002065 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002066 configured = current;
2067
Wang Quanxianacb805a2012-07-30 18:09:46 -04002068 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002069 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002070 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002071 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002072 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002073 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002074 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002075 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002076 else if (best)
2077 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002078
Hardeningff39efa2013-09-18 23:56:35 +02002079 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002080 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002081 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002082 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002083
Hardeningff39efa2013-09-18 23:56:35 +02002084 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002085
John Kåre Alsaker94659272012-11-13 19:10:18 +01002086 weston_output_init(&output->base, &ec->base, x, y,
2087 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002088 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002089
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002090 if (ec->use_pixman) {
2091 if (drm_output_init_pixman(output, ec) < 0) {
2092 weston_log("Failed to init output pixman state\n");
2093 goto err_output;
2094 }
2095 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002096 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002097 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002098 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002099
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002100 output->backlight = backlight_init(drm_device,
2101 connector->connector_type);
2102 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002103 weston_log("Initialized backlight, device %s\n",
2104 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002105 output->base.set_backlight = drm_set_backlight;
2106 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002107 } else {
2108 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002109 }
2110
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002111 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2112
Richard Hughes2b2092a2013-04-24 14:58:02 +01002113 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002114 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2115 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002116
Jonas Ådahle5a12252013-04-05 23:07:11 +02002117 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002118 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002119 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002120 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002121 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002122 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002123
Richard Hughese7299962013-05-01 21:52:12 +01002124 output->base.gamma_size = output->original_crtc->gamma_size;
2125 output->base.set_gamma = drm_output_set_gamma;
2126
Xiong Zhang97116532013-10-23 13:58:31 +08002127 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2128 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002129
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002130 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2131 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2132 &ec->base.primary_plane);
2133
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002134 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002135 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002136 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002137 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002138 m->width, m->height, m->refresh / 1000.0,
2139 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2140 ", preferred" : "",
2141 m->flags & WL_OUTPUT_MODE_CURRENT ?
2142 ", current" : "",
2143 connector->count_modes == 0 ?
2144 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002145
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002146 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002147
John Kåre Alsaker94659272012-11-13 19:10:18 +01002148err_output:
2149 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002150err_free:
2151 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2152 base.link) {
2153 wl_list_remove(&drm_mode->base.link);
2154 free(drm_mode);
2155 }
2156
2157 drmModeFreeCrtc(output->original_crtc);
2158 ec->crtc_allocator &= ~(1 << output->crtc_id);
2159 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002160 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002161
David Herrmann0f0d54e2011-12-08 17:05:45 +01002162 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002163}
2164
Jesse Barnes58ef3792012-02-23 09:45:49 -05002165static void
2166create_sprites(struct drm_compositor *ec)
2167{
2168 struct drm_sprite *sprite;
2169 drmModePlaneRes *plane_res;
2170 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002171 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002172
2173 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2174 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002175 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002176 strerror(errno));
2177 return;
2178 }
2179
2180 for (i = 0; i < plane_res->count_planes; i++) {
2181 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2182 if (!plane)
2183 continue;
2184
Peter Huttererf3d62272013-08-08 11:57:05 +10002185 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002186 plane->count_formats));
2187 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002188 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002189 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002190 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002191 continue;
2192 }
2193
Jesse Barnes58ef3792012-02-23 09:45:49 -05002194 sprite->possible_crtcs = plane->possible_crtcs;
2195 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002196 sprite->current = NULL;
2197 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002198 sprite->compositor = ec;
2199 sprite->count_formats = plane->count_formats;
2200 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002201 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002202 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002203 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002204 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2205 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002206
2207 wl_list_insert(&ec->sprite_list, &sprite->link);
2208 }
2209
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002210 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002211}
2212
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002213static void
2214destroy_sprites(struct drm_compositor *compositor)
2215{
2216 struct drm_sprite *sprite, *next;
2217 struct drm_output *output;
2218
2219 output = container_of(compositor->base.output_list.next,
2220 struct drm_output, base.link);
2221
2222 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2223 drmModeSetPlane(compositor->drm.fd,
2224 sprite->plane_id,
2225 output->crtc_id, 0, 0,
2226 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002227 drm_output_release_fb(output, sprite->current);
2228 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002229 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002230 free(sprite);
2231 }
2232}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002233
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002234static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002235create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002236 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002237{
2238 drmModeConnector *connector;
2239 drmModeRes *resources;
2240 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002241 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002242
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002243 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002244 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002245 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002246 return -1;
2247 }
2248
Jesse Barnes58ef3792012-02-23 09:45:49 -05002249 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002250 if (!ec->crtcs) {
2251 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002252 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002253 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002254
Rob Clark4339add2012-08-09 14:18:28 -05002255 ec->min_width = resources->min_width;
2256 ec->max_width = resources->max_width;
2257 ec->min_height = resources->min_height;
2258 ec->max_height = resources->max_height;
2259
Jesse Barnes58ef3792012-02-23 09:45:49 -05002260 ec->num_crtcs = resources->count_crtcs;
2261 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2262
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002263 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002264 connector = drmModeGetConnector(ec->drm.fd,
2265 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002266 if (connector == NULL)
2267 continue;
2268
2269 if (connector->connection == DRM_MODE_CONNECTED &&
2270 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002271 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002272 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002273 connector, x, y,
2274 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002275 drmModeFreeConnector(connector);
2276 continue;
2277 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002278
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002279 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002280 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002281 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002282 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002283
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002284 drmModeFreeConnector(connector);
2285 }
2286
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002287 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002288 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002289 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002290 return -1;
2291 }
2292
2293 drmModeFreeResources(resources);
2294
2295 return 0;
2296}
2297
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002298static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002299update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002300{
2301 drmModeConnector *connector;
2302 drmModeRes *resources;
2303 struct drm_output *output, *next;
2304 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002305 uint32_t connected = 0, disconnects = 0;
2306 int i;
2307
2308 resources = drmModeGetResources(ec->drm.fd);
2309 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002310 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002311 return;
2312 }
2313
2314 /* collect new connects */
2315 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002316 int connector_id = resources->connectors[i];
2317
2318 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002319 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002320 continue;
2321
David Herrmann7551cff2011-12-08 17:05:43 +01002322 if (connector->connection != DRM_MODE_CONNECTED) {
2323 drmModeFreeConnector(connector);
2324 continue;
2325 }
2326
Benjamin Franzke117483d2011-08-30 11:38:26 +02002327 connected |= (1 << connector_id);
2328
2329 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002330 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002331 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002332 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002333
2334 /* XXX: not yet needed, we die with 0 outputs */
2335 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002336 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002337 else
2338 x = 0;
2339 y = 0;
2340 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002341 connector, x, y,
2342 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002343 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002344
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002345 }
2346 drmModeFreeConnector(connector);
2347 }
2348 drmModeFreeResources(resources);
2349
2350 disconnects = ec->connector_allocator & ~connected;
2351 if (disconnects) {
2352 wl_list_for_each_safe(output, next, &ec->base.output_list,
2353 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002354 if (disconnects & (1 << output->connector_id)) {
2355 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002356 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002357 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002358 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002359 }
2360 }
2361 }
2362
2363 /* FIXME: handle zero outputs, without terminating */
2364 if (ec->connector_allocator == 0)
2365 wl_display_terminate(ec->base.wl_display);
2366}
2367
2368static int
David Herrmannd7488c22012-03-11 20:05:21 +01002369udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002370{
David Herrmannd7488c22012-03-11 20:05:21 +01002371 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002372 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002373
2374 sysnum = udev_device_get_sysnum(device);
2375 if (!sysnum || atoi(sysnum) != ec->drm.id)
2376 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002377
David Herrmann6ac52db2012-03-11 20:05:22 +01002378 val = udev_device_get_property_value(device, "HOTPLUG");
2379 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002380 return 0;
2381
David Herrmann6ac52db2012-03-11 20:05:22 +01002382 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002383}
2384
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002385static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002386udev_drm_event(int fd, uint32_t mask, void *data)
2387{
2388 struct drm_compositor *ec = data;
2389 struct udev_device *event;
2390
2391 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002392
David Herrmannd7488c22012-03-11 20:05:21 +01002393 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002394 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002395
2396 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002397
2398 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002399}
2400
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002401static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002402drm_restore(struct weston_compositor *ec)
2403{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002404 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002405}
2406
2407static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002408drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002409{
2410 struct drm_compositor *d = (struct drm_compositor *) ec;
2411
Rob Bradfordd355b802013-05-31 18:09:55 +01002412 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002413
2414 wl_event_source_remove(d->udev_drm_source);
2415 wl_event_source_remove(d->drm_source);
2416
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002417 destroy_sprites(d);
2418
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002419 weston_compositor_shutdown(ec);
2420
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002421 if (d->gbm)
2422 gbm_device_destroy(d->gbm);
2423
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002424 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002425
Rob Bradford45c15b82013-07-26 16:29:35 +01002426 close(d->drm.fd);
2427
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002428 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002429}
2430
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002431static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002432drm_compositor_set_modes(struct drm_compositor *compositor)
2433{
2434 struct drm_output *output;
2435 struct drm_mode *drm_mode;
2436 int ret;
2437
2438 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002439 if (!output->current) {
2440 /* If something that would cause the output to
2441 * switch mode happened while in another vt, we
2442 * might not have a current drm_fb. In that case,
2443 * schedule a repaint and let drm_output_repaint
2444 * handle setting the mode. */
2445 weston_output_schedule_repaint(&output->base);
2446 continue;
2447 }
2448
Hardeningff39efa2013-09-18 23:56:35 +02002449 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002450 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002451 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002452 &output->connector_id, 1,
2453 &drm_mode->mode_info);
2454 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002455 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002456 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002457 drm_mode->base.width, drm_mode->base.height,
2458 output->base.x, output->base.y);
2459 }
2460 }
2461}
2462
2463static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002464session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002465{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002466 struct weston_compositor *compositor = data;
2467 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002468 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002469 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002470
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002471 if (ec->base.session_active) {
2472 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002473 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002474 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002475 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002476 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002477 } else {
2478 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002479 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002480
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002481 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002482 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002483
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002484 /* If we have a repaint scheduled (either from a
2485 * pending pageflip or the idle handler), make sure we
2486 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002487 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002488 * further attemps at repainting. When we switch
2489 * back, we schedule a repaint, which will process
2490 * pending frame callbacks. */
2491
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002492 wl_list_for_each(output, &ec->base.output_list, base.link) {
2493 output->base.repaint_needed = 0;
2494 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002495 }
2496
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002497 output = container_of(ec->base.output_list.next,
2498 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002499
2500 wl_list_for_each(sprite, &ec->sprite_list, link)
2501 drmModeSetPlane(ec->drm.fd,
2502 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002503 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002504 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002505 };
2506}
2507
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002508static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002509switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002510{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002511 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002512
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002513 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002514}
2515
David Herrmann0af066f2012-10-29 19:21:16 +01002516/*
2517 * Find primary GPU
2518 * Some systems may have multiple DRM devices attached to a single seat. This
2519 * function loops over all devices and tries to find a PCI device with the
2520 * boot_vga sysfs attribute set to 1.
2521 * If no such device is found, the first DRM device reported by udev is used.
2522 */
2523static struct udev_device*
2524find_primary_gpu(struct drm_compositor *ec, const char *seat)
2525{
2526 struct udev_enumerate *e;
2527 struct udev_list_entry *entry;
2528 const char *path, *device_seat, *id;
2529 struct udev_device *device, *drm_device, *pci;
2530
2531 e = udev_enumerate_new(ec->udev);
2532 udev_enumerate_add_match_subsystem(e, "drm");
2533 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2534
2535 udev_enumerate_scan_devices(e);
2536 drm_device = NULL;
2537 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2538 path = udev_list_entry_get_name(entry);
2539 device = udev_device_new_from_syspath(ec->udev, path);
2540 if (!device)
2541 continue;
2542 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2543 if (!device_seat)
2544 device_seat = default_seat;
2545 if (strcmp(device_seat, seat)) {
2546 udev_device_unref(device);
2547 continue;
2548 }
2549
2550 pci = udev_device_get_parent_with_subsystem_devtype(device,
2551 "pci", NULL);
2552 if (pci) {
2553 id = udev_device_get_sysattr_value(pci, "boot_vga");
2554 if (id && !strcmp(id, "1")) {
2555 if (drm_device)
2556 udev_device_unref(drm_device);
2557 drm_device = device;
2558 break;
2559 }
2560 }
2561
2562 if (!drm_device)
2563 drm_device = device;
2564 else
2565 udev_device_unref(device);
2566 }
2567
2568 udev_enumerate_unref(e);
2569 return drm_device;
2570}
2571
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002572static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002573planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002574{
2575 struct drm_compositor *c = data;
2576
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002577 switch (key) {
2578 case KEY_C:
2579 c->cursors_are_broken ^= 1;
2580 break;
2581 case KEY_V:
2582 c->sprites_are_broken ^= 1;
2583 break;
2584 case KEY_O:
2585 c->sprites_hidden ^= 1;
2586 break;
2587 default:
2588 break;
2589 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002590}
2591
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002592#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002593static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002594recorder_destroy(struct drm_output *output)
2595{
2596 vaapi_recorder_destroy(output->recorder);
2597 output->recorder = NULL;
2598
2599 output->base.disable_planes--;
2600
2601 wl_list_remove(&output->recorder_frame_listener.link);
2602 weston_log("[libva recorder] done\n");
2603}
2604
2605static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002606recorder_frame_notify(struct wl_listener *listener, void *data)
2607{
2608 struct drm_output *output;
2609 struct drm_compositor *c;
2610 int fd, ret;
2611
2612 output = container_of(listener, struct drm_output,
2613 recorder_frame_listener);
2614 c = (struct drm_compositor *) output->base.compositor;
2615
2616 if (!output->recorder)
2617 return;
2618
2619 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2620 DRM_CLOEXEC, &fd);
2621 if (ret) {
2622 weston_log("[libva recorder] "
2623 "failed to create prime fd for front buffer\n");
2624 return;
2625 }
2626
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002627 ret = vaapi_recorder_frame(output->recorder, fd,
2628 output->current->stride);
2629 if (ret < 0) {
2630 weston_log("[libva recorder] aborted: %m\n");
2631 recorder_destroy(output);
2632 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002633}
2634
2635static void *
2636create_recorder(struct drm_compositor *c, int width, int height,
2637 const char *filename)
2638{
2639 int fd;
2640 drm_magic_t magic;
2641
2642 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2643 if (fd < 0)
2644 return NULL;
2645
2646 drmGetMagic(fd, &magic);
2647 drmAuthMagic(c->drm.fd, magic);
2648
2649 return vaapi_recorder_create(fd, width, height, filename);
2650}
2651
2652static void
2653recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2654 void *data)
2655{
2656 struct drm_compositor *c = data;
2657 struct drm_output *output;
2658 int width, height;
2659
2660 output = container_of(c->base.output_list.next,
2661 struct drm_output, base.link);
2662
2663 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002664 if (output->format != GBM_FORMAT_XRGB8888) {
2665 weston_log("failed to start vaapi recorder: "
2666 "output format not supported\n");
2667 return;
2668 }
2669
Hardeningff39efa2013-09-18 23:56:35 +02002670 width = output->base.current_mode->width;
2671 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002672
2673 output->recorder =
2674 create_recorder(c, width, height, "capture.h264");
2675 if (!output->recorder) {
2676 weston_log("failed to create vaapi recorder\n");
2677 return;
2678 }
2679
2680 output->base.disable_planes++;
2681
2682 output->recorder_frame_listener.notify = recorder_frame_notify;
2683 wl_signal_add(&output->base.frame_signal,
2684 &output->recorder_frame_listener);
2685
2686 weston_output_schedule_repaint(&output->base);
2687
2688 weston_log("[libva recorder] initialized\n");
2689 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002690 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002691 }
2692}
2693#else
2694static void
2695recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2696 void *data)
2697{
2698 weston_log("Compiled without libva support\n");
2699}
2700#endif
2701
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002702static void
2703switch_to_gl_renderer(struct drm_compositor *c)
2704{
2705 struct drm_output *output;
2706
2707 if (!c->use_pixman)
2708 return;
2709
2710 weston_log("Switching to GL renderer\n");
2711
2712 c->gbm = create_gbm_device(c->drm.fd);
2713 if (!c->gbm) {
2714 weston_log("Failed to create gbm device. "
2715 "Aborting renderer switch\n");
2716 return;
2717 }
2718
2719 wl_list_for_each(output, &c->base.output_list, base.link)
2720 pixman_renderer_output_destroy(&output->base);
2721
2722 c->base.renderer->destroy(&c->base);
2723
2724 if (drm_compositor_create_gl_renderer(c) < 0) {
2725 gbm_device_destroy(c->gbm);
2726 weston_log("Failed to create GL renderer. Quitting.\n");
2727 /* FIXME: we need a function to shutdown cleanly */
2728 assert(0);
2729 }
2730
2731 wl_list_for_each(output, &c->base.output_list, base.link)
2732 drm_output_init_egl(output, c);
2733
2734 c->use_pixman = 0;
2735}
2736
2737static void
2738renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2739 void *data)
2740{
2741 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2742
2743 switch_to_gl_renderer(c);
2744}
2745
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002746static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002747drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002748 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002749 int *argc, char *argv[],
2750 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002751{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002752 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002753 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002754 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002755 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002756 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002757 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002758
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002759 weston_log("initializing drm backend\n");
2760
Peter Huttererf3d62272013-08-08 11:57:05 +10002761 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002762 if (ec == NULL)
2763 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002764
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002765 /* KMS support for sprites is not complete yet, so disable the
2766 * functionality for now. */
2767 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002768
2769 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002770 if (get_gbm_format_from_section(section,
2771 GBM_FORMAT_XRGB8888,
2772 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002773 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002774
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002775 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002776
Daniel Stone725c2c32012-06-22 14:04:36 +01002777 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002778 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002779 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002780 goto err_base;
2781 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002782
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002783 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002784 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2785 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002786 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002787 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002788 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002789 goto err_compositor;
2790 }
2791
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002792 ec->udev = udev_new();
2793 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002794 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002795 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002796 }
2797
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002798 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002799 ec->session_listener.notify = session_notify;
2800 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002801
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002802 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002803 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002804 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002805 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002806 }
David Herrmann0af066f2012-10-29 19:21:16 +01002807 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002808
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002809 if (init_drm(ec, drm_device) < 0) {
2810 weston_log("failed to initialize kms\n");
2811 goto err_udev_dev;
2812 }
2813
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002814 if (ec->use_pixman) {
2815 if (init_pixman(ec) < 0) {
2816 weston_log("failed to initialize pixman renderer\n");
2817 goto err_udev_dev;
2818 }
2819 } else {
2820 if (init_egl(ec) < 0) {
2821 weston_log("failed to initialize egl\n");
2822 goto err_udev_dev;
2823 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002824 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002825
2826 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002827 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002828
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002829 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002830
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002831 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002832 weston_compositor_add_key_binding(&ec->base, key,
2833 MODIFIER_CTRL | MODIFIER_ALT,
2834 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002835
Jesse Barnes58ef3792012-02-23 09:45:49 -05002836 wl_list_init(&ec->sprite_list);
2837 create_sprites(ec);
2838
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002839 if (udev_input_init(&ec->input,
2840 &ec->base, ec->udev, param->seat_id) < 0) {
2841 weston_log("failed to create input devices\n");
2842 goto err_sprite;
2843 }
2844
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002845 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002846 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002847 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002848 }
2849
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002850 /* A this point we have some idea of whether or not we have a working
2851 * cursor plane. */
2852 if (!ec->cursors_are_broken)
2853 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2854
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002855 path = NULL;
2856
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002857 loop = wl_display_get_event_loop(ec->base.wl_display);
2858 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002859 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002860 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002861
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002862 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2863 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002864 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002865 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002866 }
2867 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2868 "drm", NULL);
2869 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002870 wl_event_loop_add_fd(loop,
2871 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002872 WL_EVENT_READABLE, udev_drm_event, ec);
2873
2874 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002875 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002876 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002877 }
2878
Daniel Stonea96b93c2012-06-22 14:04:37 +01002879 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002880
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002881 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002882 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002883 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002884 planes_binding, ec);
2885 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2886 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002887 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2888 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002889 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2890 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002891
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002892 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002893
2894err_udev_monitor:
2895 wl_event_source_remove(ec->udev_drm_source);
2896 udev_monitor_unref(ec->udev_monitor);
2897err_drm_source:
2898 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002899err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002900 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002901err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002902 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002903 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002904 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002905err_udev_dev:
2906 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002907err_launcher:
2908 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002909err_udev:
2910 udev_unref(ec->udev);
2911err_compositor:
2912 weston_compositor_shutdown(&ec->base);
2913err_base:
2914 free(ec);
2915 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002916}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002917
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002918WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002919backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002920 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002921{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002922 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002923
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002924 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002925 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2926 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2927 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002928 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002929 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002930 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002931
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002932 param.seat_id = default_seat;
2933
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002934 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002935
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002936 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002937}