blob: 33e2af6b78428a0a17b0c12f83771c6b77b5d5dd [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 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07005 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040012 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070013 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040025 */
26
Daniel Stonec228e232013-05-22 18:03:19 +030027#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040028
Jesse Barnes58ef3792012-02-23 09:45:49 -050029#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040030#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010031#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040032#include <string.h>
33#include <fcntl.h>
34#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040035#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070036#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030037#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020038#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030039#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030040#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040041
Benjamin Franzkec649a922011-03-02 11:56:04 +010042#include <xf86drm.h>
43#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050044#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010045
Benjamin Franzke060cf802011-04-30 09:32:11 +020046#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040047#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020048
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080049#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040050#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010051#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020052#include "pixman-renderer.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100053#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010054#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030055#include "vaapi-recorder.h"
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020056#include "presentation_timing-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040057
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030058#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
59#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
60#endif
61
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030062#ifndef DRM_CAP_CURSOR_WIDTH
63#define DRM_CAP_CURSOR_WIDTH 0x8
64#endif
65
66#ifndef DRM_CAP_CURSOR_HEIGHT
67#define DRM_CAP_CURSOR_HEIGHT 0x9
68#endif
69
70#ifndef GBM_BO_USE_CURSOR
71#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
72#endif
73
Kristian Høgsberg061c4252012-06-28 11:28:15 -040074static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060075
76enum output_config {
77 OUTPUT_CONFIG_INVALID = 0,
78 OUTPUT_CONFIG_OFF,
79 OUTPUT_CONFIG_PREFERRED,
80 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060081 OUTPUT_CONFIG_MODE,
82 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060083};
84
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040085struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050086 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040087
88 struct udev *udev;
89 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040090
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010091 struct udev_monitor *udev_monitor;
92 struct wl_event_source *udev_drm_source;
93
Benjamin Franzke2af7f102011-03-02 11:14:59 +010094 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010095 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010096 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030097 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010098 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020099 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500100 uint32_t *crtcs;
101 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -0500102 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100103 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700104 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700105 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106
Rob Clark4339add2012-08-09 14:18:28 -0500107 /* we need these parameters in order to not fail drmModeAddFB2()
108 * due to out of bounds dimensions, and then mistakenly set
109 * sprites_are_broken:
110 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200111 uint32_t min_width, max_width;
112 uint32_t min_height, max_height;
113 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500114
Jesse Barnes58ef3792012-02-23 09:45:49 -0500115 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500116 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200117 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500118
Rob Clarkab5b1e32012-08-09 13:24:45 -0500119 int cursors_are_broken;
120
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200121 int use_pixman;
122
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200123 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300124
Rob Bradfordd355b802013-05-31 18:09:55 +0100125 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300126
127 uint32_t cursor_width;
128 uint32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400129};
130
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400131struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500132 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400133 drmModeModeInfo mode_info;
134};
135
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300136struct drm_output;
137
138struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300139 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200140 uint32_t fb_id, stride, handle, size;
141 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300142 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200143 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200144
145 /* Used by gbm fbs */
146 struct gbm_bo *bo;
147
148 /* Used by dumb fbs */
149 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300150};
151
Richard Hughes2b2092a2013-04-24 14:58:02 +0100152struct drm_edid {
153 char eisa_id[13];
154 char monitor_name[13];
155 char pnp_id[5];
156 char serial_number[13];
157};
158
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500160 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400161
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400162 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500163 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400164 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700165 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100166 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300167 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000168 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200169
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300170 int vblank_pending;
171 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800172 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300173
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400174 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400175 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400176 struct weston_plane cursor_plane;
177 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500178 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400179 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300180 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200181 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200182
183 struct drm_fb *dumb[2];
184 pixman_image_t *image[2];
185 int current_image;
186 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300187
188 struct vaapi_recorder *recorder;
189 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400190};
191
Jesse Barnes58ef3792012-02-23 09:45:49 -0500192/*
193 * An output has a primary display plane plus zero or more sprites for
194 * blending display contents.
195 */
196struct drm_sprite {
197 struct wl_list link;
198
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400199 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500200
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200201 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300202 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500203 struct drm_compositor *compositor;
204
Jesse Barnes58ef3792012-02-23 09:45:49 -0500205 uint32_t possible_crtcs;
206 uint32_t plane_id;
207 uint32_t count_formats;
208
209 int32_t src_x, src_y;
210 uint32_t src_w, src_h;
211 uint32_t dest_x, dest_y;
212 uint32_t dest_w, dest_h;
213
214 uint32_t formats[];
215};
216
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700217struct drm_parameters {
218 int connector;
219 int tty;
220 int use_pixman;
221 const char *seat_id;
222};
223
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300224static struct gl_renderer_interface *gl_renderer;
225
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500226static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400227
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400228static void
229drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400230
Jesse Barnes58ef3792012-02-23 09:45:49 -0500231static int
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200232drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500233{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200234 struct weston_compositor *ec = output->base.compositor;
235 struct drm_compositor *c = (struct drm_compositor *)ec;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500236 int crtc;
237
238 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
239 if (c->crtcs[crtc] != output->crtc_id)
240 continue;
241
242 if (supported & (1 << crtc))
243 return -1;
244 }
245
246 return 0;
247}
248
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300249static void
250drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
251{
252 struct drm_fb *fb = data;
253 struct gbm_device *gbm = gbm_bo_get_device(bo);
254
255 if (fb->fb_id)
256 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
257
Pekka Paalanende685b82012-12-04 15:58:12 +0200258 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300259
260 free(data);
261}
262
263static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200264drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
265{
266 struct drm_fb *fb;
267 int ret;
268
269 struct drm_mode_create_dumb create_arg;
270 struct drm_mode_destroy_dumb destroy_arg;
271 struct drm_mode_map_dumb map_arg;
272
Peter Huttererf3d62272013-08-08 11:57:05 +1000273 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200274 if (!fb)
275 return NULL;
276
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700277 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200278 create_arg.bpp = 32;
279 create_arg.width = width;
280 create_arg.height = height;
281
282 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
283 if (ret)
284 goto err_fb;
285
286 fb->handle = create_arg.handle;
287 fb->stride = create_arg.pitch;
288 fb->size = create_arg.size;
289 fb->fd = ec->drm.fd;
290
291 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
292 fb->stride, fb->handle, &fb->fb_id);
293 if (ret)
294 goto err_bo;
295
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700296 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200297 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400298 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200299 if (ret)
300 goto err_add_fb;
301
302 fb->map = mmap(0, fb->size, PROT_WRITE,
303 MAP_SHARED, ec->drm.fd, map_arg.offset);
304 if (fb->map == MAP_FAILED)
305 goto err_add_fb;
306
307 return fb;
308
309err_add_fb:
310 drmModeRmFB(ec->drm.fd, fb->fb_id);
311err_bo:
312 memset(&destroy_arg, 0, sizeof(destroy_arg));
313 destroy_arg.handle = create_arg.handle;
314 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
315err_fb:
316 free(fb);
317 return NULL;
318}
319
320static void
321drm_fb_destroy_dumb(struct drm_fb *fb)
322{
323 struct drm_mode_destroy_dumb destroy_arg;
324
325 if (!fb->map)
326 return;
327
328 if (fb->fb_id)
329 drmModeRmFB(fb->fd, fb->fb_id);
330
331 weston_buffer_reference(&fb->buffer_ref, NULL);
332
333 munmap(fb->map, fb->size);
334
335 memset(&destroy_arg, 0, sizeof(destroy_arg));
336 destroy_arg.handle = fb->handle;
337 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
338
339 free(fb);
340}
341
342static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500343drm_fb_get_from_bo(struct gbm_bo *bo,
344 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300345{
346 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200347 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200348 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300349 int ret;
350
351 if (fb)
352 return fb;
353
Bryce Harringtonde16d892014-11-20 22:21:57 -0800354 fb = zalloc(sizeof *fb);
355 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200356 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300357
358 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359
360 width = gbm_bo_get_width(bo);
361 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200362 fb->stride = gbm_bo_get_stride(bo);
363 fb->handle = gbm_bo_get_handle(bo).u32;
364 fb->size = fb->stride * height;
365 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200367 if (compositor->min_width > width || width > compositor->max_width ||
368 compositor->min_height > height ||
369 height > compositor->max_height) {
370 weston_log("bo geometry out of bounds\n");
371 goto err_free;
372 }
373
374 ret = -1;
375
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200377 handles[0] = fb->handle;
378 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 offsets[0] = 0;
380
381 ret = drmModeAddFB2(compositor->drm.fd, width, height,
382 format, handles, pitches, offsets,
383 &fb->fb_id, 0);
384 if (ret) {
385 weston_log("addfb2 failed: %m\n");
386 compositor->no_addfb2 = 1;
387 compositor->sprites_are_broken = 1;
388 }
389 }
390
391 if (ret)
392 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200393 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200394
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300395 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200396 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300398 }
399
400 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
401
402 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200403
404err_free:
405 free(fb);
406 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300407}
408
409static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500410drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200411{
Pekka Paalanende685b82012-12-04 15:58:12 +0200412 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200413
414 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200415
Pekka Paalanende685b82012-12-04 15:58:12 +0200416 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200417}
418
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200419static void
420drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
421{
422 if (!fb)
423 return;
424
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200425 if (fb->map &&
426 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200427 drm_fb_destroy_dumb(fb);
428 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200429 if (fb->is_client_buffer)
430 gbm_bo_destroy(fb->bo);
431 else
432 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600433 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200434 }
435}
436
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500437static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200438drm_output_check_scanout_format(struct drm_output *output,
439 struct weston_surface *es, struct gbm_bo *bo)
440{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200441 uint32_t format;
442 pixman_region32_t r;
443
444 format = gbm_bo_get_format(bo);
445
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700446 if (format == GBM_FORMAT_ARGB8888) {
447 /* We can scanout an ARGB buffer if the surface's
448 * opaque region covers the whole output, but we have
449 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800450 pixman_region32_init_rect(&r, 0, 0,
451 output->base.width,
452 output->base.height);
453 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200454
455 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500456 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200457
458 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500459 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700460
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000461 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700462 return format;
463
464 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200465}
466
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400467static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200468drm_output_prepare_scanout_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500469 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500470{
471 struct drm_compositor *c =
472 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500473 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200474 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300475 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500476 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500477
Jason Ekstranda7af7042013-10-12 22:38:11 -0500478 if (ev->geometry.x != output->base.x ||
479 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200480 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200481 buffer->width != output->base.current_mode->width ||
482 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200483 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500484 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400485 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500486
Pekka Paalanen5580f222015-02-17 16:33:18 +0200487 if (ev->geometry.scissor_enabled)
488 return NULL;
489
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400490 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700491 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500492
Rob Bradford9b101872012-09-14 23:25:41 +0100493 /* Unable to use the buffer for scanout */
494 if (!bo)
495 return NULL;
496
Jason Ekstranda7af7042013-10-12 22:38:11 -0500497 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500498 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300499 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400500 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300501 }
502
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500503 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300504 if (!output->next) {
505 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400506 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300507 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500508
Pekka Paalanende685b82012-12-04 15:58:12 +0200509 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500510
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400511 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500512}
513
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500514static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200515drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400516{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200517 struct drm_compositor *c =
518 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300519 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400520
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200521 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400522
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300523 bo = gbm_surface_lock_front_buffer(output->surface);
524 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200525 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400526 return;
527 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300528
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000529 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300530 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200531 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300532 gbm_surface_release_buffer(output->surface, bo);
533 return;
534 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400535}
536
537static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200538drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
539{
540 struct weston_compositor *ec = output->base.compositor;
541 pixman_region32_t total_damage, previous_damage;
542
543 pixman_region32_init(&total_damage);
544 pixman_region32_init(&previous_damage);
545
546 pixman_region32_copy(&previous_damage, damage);
547
548 pixman_region32_union(&total_damage, damage, &output->previous_damage);
549 pixman_region32_copy(&output->previous_damage, &previous_damage);
550
551 output->current_image ^= 1;
552
553 output->next = output->dumb[output->current_image];
554 pixman_renderer_output_set_buffer(&output->base,
555 output->image[output->current_image]);
556
557 ec->renderer->repaint_output(&output->base, &total_damage);
558
559 pixman_region32_fini(&total_damage);
560 pixman_region32_fini(&previous_damage);
561}
562
563static void
564drm_output_render(struct drm_output *output, pixman_region32_t *damage)
565{
566 struct drm_compositor *c =
567 (struct drm_compositor *) output->base.compositor;
568
569 if (c->use_pixman)
570 drm_output_render_pixman(output, damage);
571 else
572 drm_output_render_gl(output, damage);
573
574 pixman_region32_subtract(&c->base.primary_plane.damage,
575 &c->base.primary_plane.damage, damage);
576}
577
578static void
Richard Hughese7299962013-05-01 21:52:12 +0100579drm_output_set_gamma(struct weston_output *output_base,
580 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
581{
582 int rc;
583 struct drm_output *output = (struct drm_output *) output_base;
584 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
585
586 /* check */
587 if (output_base->gamma_size != size)
588 return;
589 if (!output->original_crtc)
590 return;
591
592 rc = drmModeCrtcSetGamma(compositor->drm.fd,
593 output->crtc_id,
594 size, r, g, b);
595 if (rc)
596 weston_log("set gamma failed: %m\n");
597}
598
David Herrmann1edf44c2013-10-22 17:11:26 +0200599static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500600drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400601 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100602{
603 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500604 struct drm_compositor *compositor =
605 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500606 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400607 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100609
Xiong Zhangabd5d472013-10-11 14:43:07 +0800610 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200611 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800612
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300613 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400614 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300615 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200616 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100617
Hardeningff39efa2013-09-18 23:56:35 +0200618 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200619 if (!output->current ||
620 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400621 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300622 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400623 &output->connector_id, 1,
624 &mode->mode_info);
625 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200626 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200627 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400628 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300629 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200630 }
631
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500632 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300633 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500634 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200635 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200636 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500637 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100638
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300639 output->page_flip_pending = 1;
640
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400641 drm_output_set_cursor(output);
642
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 /*
644 * Now, update all the sprite surfaces
645 */
646 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200647 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500648 drmVBlank vbl = {
649 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
650 .request.sequence = 1,
651 };
652
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200653 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200654 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655 continue;
656
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200657 if (s->next && !compositor->sprites_hidden)
658 fb_id = s->next->fb_id;
659
Jesse Barnes58ef3792012-02-23 09:45:49 -0500660 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200661 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500662 s->dest_x, s->dest_y,
663 s->dest_w, s->dest_h,
664 s->src_x, s->src_y,
665 s->src_w, s->src_h);
666 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200667 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500668 ret, strerror(errno));
669
Rob Clark5ca1a472012-08-08 20:27:37 -0500670 if (output->pipe > 0)
671 vbl.request.type |= DRM_VBLANK_SECONDARY;
672
Jesse Barnes58ef3792012-02-23 09:45:49 -0500673 /*
674 * Queue a vblank signal so we know when the surface
675 * becomes active on the display or has been replaced.
676 */
677 vbl.request.signal = (unsigned long)s;
678 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
679 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200680 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681 ret, strerror(errno));
682 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300683
684 s->output = output;
685 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500686 }
687
David Herrmann1edf44c2013-10-22 17:11:26 +0200688 return 0;
689
690err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800691 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200692 if (output->next) {
693 drm_output_release_fb(output, output->next);
694 output->next = NULL;
695 }
696
697 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400698}
699
700static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200701drm_output_start_repaint_loop(struct weston_output *output_base)
702{
703 struct drm_output *output = (struct drm_output *) output_base;
704 struct drm_compositor *compositor = (struct drm_compositor *)
705 output_base->compositor;
706 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300707 struct timespec ts;
708
Xiong Zhangabd5d472013-10-11 14:43:07 +0800709 if (output->destroy_pending)
710 return;
711
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300712 if (!output->current) {
713 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200714 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300715 }
716
717 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200718
719 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
720 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
721 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200722 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200723 }
David Herrmann3c688c52013-10-22 17:11:25 +0200724
725 return;
726
727finish_frame:
728 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanen662f3842015-03-18 12:17:26 +0200729 weston_compositor_read_presentation_clock(&compositor->base, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200730 weston_output_finish_frame(output_base, &ts,
731 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200732}
733
734static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400735drm_output_update_msc(struct drm_output *output, unsigned int seq)
736{
737 uint64_t msc_hi = output->base.msc >> 32;
738
739 if (seq < (output->base.msc & 0xffffffff))
740 msc_hi++;
741
742 output->base.msc = (msc_hi << 32) + seq;
743}
744
745static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500746vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
747 void *data)
748{
749 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300750 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400751 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200752 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
753 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300754
Pekka Paalanen641307c2014-09-23 22:08:47 -0400755 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300756 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500757
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200758 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200759 s->current = s->next;
760 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300761
762 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400763 ts.tv_sec = sec;
764 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200765 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300766 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500767}
768
769static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800770drm_output_destroy(struct weston_output *output_base);
771
772static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400773page_flip_handler(int fd, unsigned int frame,
774 unsigned int sec, unsigned int usec, void *data)
775{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200776 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400777 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200778 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
779 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
780 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400781
Pekka Paalanen641307c2014-09-23 22:08:47 -0400782 drm_output_update_msc(output, frame);
783
Jonas Ådahle5a12252013-04-05 23:07:11 +0200784 /* We don't set page_flip_pending on start_repaint_loop, in that case
785 * we just want to page flip to the current buffer to get an accurate
786 * timestamp */
787 if (output->page_flip_pending) {
788 drm_output_release_fb(output, output->current);
789 output->current = output->next;
790 output->next = NULL;
791 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300792
Jonas Ådahle5a12252013-04-05 23:07:11 +0200793 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400794
Xiong Zhangabd5d472013-10-11 14:43:07 +0800795 if (output->destroy_pending)
796 drm_output_destroy(&output->base);
797 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400798 ts.tv_sec = sec;
799 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200800 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300801
802 /* We can't call this from frame_notify, because the output's
803 * repaint needed flag is cleared just after that */
804 if (output->recorder)
805 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300806 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200807}
808
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500809static uint32_t
810drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500811 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500813 uint32_t i, format;
814
815 format = gbm_bo_get_format(bo);
816
817 if (format == GBM_FORMAT_ARGB8888) {
818 pixman_region32_t r;
819
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500820 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600821 ev->surface->width,
822 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500823 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500824
825 if (!pixman_region32_not_empty(&r))
826 format = GBM_FORMAT_XRGB8888;
827
828 pixman_region32_fini(&r);
829 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500830
831 for (i = 0; i < s->count_formats; i++)
832 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500833 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834
835 return 0;
836}
837
838static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500839drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500840{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500841 return !ev->transform.enabled ||
842 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500843}
844
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400845static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200846drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500847 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500848{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200849 struct weston_compositor *ec = output->base.compositor;
850 struct drm_compositor *c = (struct drm_compositor *)ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200851 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500852 struct drm_sprite *s;
853 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500854 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500855 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200856 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500857 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400858 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500859
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200860 if (c->gbm == NULL)
861 return NULL;
862
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200863 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200864 return NULL;
865
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200866 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200867 return NULL;
868
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500869 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400870 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500871
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200872 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400873 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300874
Jason Ekstranda7af7042013-10-12 22:38:11 -0500875 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400876 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500877
Jason Ekstranda7af7042013-10-12 22:38:11 -0500878 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200879 return NULL;
880
Jason Ekstranda7af7042013-10-12 22:38:11 -0500881 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500882 return NULL;
883
Jason Ekstranda7af7042013-10-12 22:38:11 -0500884 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400885 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500886
Jesse Barnes58ef3792012-02-23 09:45:49 -0500887 wl_list_for_each(s, &c->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200888 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500889 continue;
890
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200891 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500892 found = 1;
893 break;
894 }
895 }
896
897 /* No sprites available */
898 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400899 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500900
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400901 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500902 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700903 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400904 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400905 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400906
Jason Ekstranda7af7042013-10-12 22:38:11 -0500907 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500908 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200909 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400910 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500911 }
912
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200913 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200914 if (!s->next) {
915 gbm_bo_destroy(bo);
916 return NULL;
917 }
918
Jason Ekstranda7af7042013-10-12 22:38:11 -0500919 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500920
Jason Ekstranda7af7042013-10-12 22:38:11 -0500921 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400922 s->plane.x = box->x1;
923 s->plane.y = box->y1;
924
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925 /*
926 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500927 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500928 * for us already).
929 */
930 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500931 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200932 &output->base.region);
933 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500934 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200935 tbox = weston_transformed_rect(output->base.width,
936 output->base.height,
937 output->base.transform,
938 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200939 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200940 s->dest_x = tbox.x1;
941 s->dest_y = tbox.y1;
942 s->dest_w = tbox.x2 - tbox.x1;
943 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500944 pixman_region32_fini(&dest_rect);
945
946 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500947 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200948 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500949 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400950
Jason Ekstranda7af7042013-10-12 22:38:11 -0500951 weston_view_from_global_fixed(ev,
952 wl_fixed_from_int(box->x1),
953 wl_fixed_from_int(box->y1),
954 &sx1, &sy1);
955 weston_view_from_global_fixed(ev,
956 wl_fixed_from_int(box->x2),
957 wl_fixed_from_int(box->y2),
958 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400959
960 if (sx1 < 0)
961 sx1 = 0;
962 if (sy1 < 0)
963 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600964 if (sx2 > wl_fixed_from_int(ev->surface->width))
965 sx2 = wl_fixed_from_int(ev->surface->width);
966 if (sy2 > wl_fixed_from_int(ev->surface->height))
967 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400968
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200969 tbox.x1 = sx1;
970 tbox.y1 = sy1;
971 tbox.x2 = sx2;
972 tbox.y2 = sy2;
973
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600974 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
975 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200976 viewport->buffer.transform,
977 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100978 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200979
980 s->src_x = tbox.x1 << 8;
981 s->src_y = tbox.y1 << 8;
982 s->src_w = (tbox.x2 - tbox.x1) << 8;
983 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500984 pixman_region32_fini(&src_rect);
985
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400986 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500987}
988
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400989static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200990drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500991 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500992{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400993 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200994 (struct drm_compositor *)output->base.compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100995 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400996
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200997 if (c->gbm == NULL)
998 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200999 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1000 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001001 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001002 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001003 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001004 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001005 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001006 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001007 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001008 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001009 if (ev->geometry.scissor_enabled)
1010 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001011 if (ev->surface->buffer_ref.buffer == NULL ||
1012 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001013 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001014 return NULL;
1015
Jason Ekstranda7af7042013-10-12 22:38:11 -05001016 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001017
1018 return &output->cursor_plane;
1019}
1020
1021static void
1022drm_output_set_cursor(struct drm_output *output)
1023{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001024 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001025 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001026 struct drm_compositor *c =
1027 (struct drm_compositor *) output->base.compositor;
1028 EGLint handle, stride;
1029 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001030 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001031 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001032 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001033
Jason Ekstranda7af7042013-10-12 22:38:11 -05001034 output->cursor_view = NULL;
1035 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001036 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1037 return;
1038 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001039
Neil Robertse5051712013-11-13 15:44:06 +00001040 buffer = ev->surface->buffer_ref.buffer;
1041
1042 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001043 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001044 pixman_region32_fini(&output->cursor_plane.damage);
1045 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001046 output->current_cursor ^= 1;
1047 bo = output->cursor_bo[output->current_cursor];
1048 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001049 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1050 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1051 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001052 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001053 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001054 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001055 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001056
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001057 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001058 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001059
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001060 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001061 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1062 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001063 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001064 c->cursors_are_broken = 1;
1065 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001066 }
1067
Jason Ekstranda7af7042013-10-12 22:38:11 -05001068 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1069 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001070 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001071 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001072 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001073 c->cursors_are_broken = 1;
1074 }
1075
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001076 output->cursor_plane.x = x;
1077 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001078 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001079}
1080
Jesse Barnes58ef3792012-02-23 09:45:49 -05001081static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001082drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001083{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001084 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001085 (struct drm_compositor *)output_base->compositor;
1086 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001087 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001088 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001089 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001090
1091 /*
1092 * Find a surface for each sprite in the output using some heuristics:
1093 * 1) size
1094 * 2) frequency of update
1095 * 3) opacity (though some hw might support alpha blending)
1096 * 4) clipping (this can be fixed with color keys)
1097 *
1098 * The idea is to save on blitting since this should save power.
1099 * If we can get a large video surface on the sprite for example,
1100 * the main display surface may not need to update at all, and
1101 * the client buffer can be used directly for the sprite surface
1102 * as we do for flipping full screen surfaces.
1103 */
1104 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001105 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001106
Jason Ekstranda7af7042013-10-12 22:38:11 -05001107 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001108 struct weston_surface *es = ev->surface;
1109
1110 /* Test whether this buffer can ever go into a plane:
1111 * non-shm, or small enough to be a cursor.
1112 *
1113 * Also, keep a reference when using the pixman renderer.
1114 * That makes it possible to do a seamless switch to the GL
1115 * renderer and since the pixman renderer keeps a reference
1116 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001117 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001118 if (c->use_pixman ||
1119 (es->buffer_ref.buffer &&
1120 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001121 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001122 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001123 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001124 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001125
Jesse Barnes58ef3792012-02-23 09:45:49 -05001126 pixman_region32_init(&surface_overlap);
1127 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001128 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001129
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001130 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001131 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001132 next_plane = primary;
1133 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001134 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001135 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001136 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001137 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001138 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001139 if (next_plane == NULL)
1140 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001141
Jason Ekstranda7af7042013-10-12 22:38:11 -05001142 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001143
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001144 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001145 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001146 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001147
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001148 if (next_plane == primary ||
1149 next_plane == &output->cursor_plane) {
1150 /* cursor plane involves a copy */
1151 ev->psf_flags = 0;
1152 } else {
1153 /* All other planes are a direct scanout of a
1154 * single client buffer.
1155 */
1156 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1157 }
1158
Jesse Barnes58ef3792012-02-23 09:45:49 -05001159 pixman_region32_fini(&surface_overlap);
1160 }
1161 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001162}
1163
Matt Roper361d2ad2011-08-29 13:52:23 -07001164static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001165drm_output_fini_pixman(struct drm_output *output);
1166
1167static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001168drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001169{
1170 struct drm_output *output = (struct drm_output *) output_base;
1171 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001172 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001173 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001174
Xiong Zhangabd5d472013-10-11 14:43:07 +08001175 if (output->page_flip_pending) {
1176 output->destroy_pending = 1;
1177 weston_log("destroy output while page flip pending\n");
1178 return;
1179 }
1180
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001181 if (output->backlight)
1182 backlight_destroy(output->backlight);
1183
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001184 drmModeFreeProperty(output->dpms_prop);
1185
Matt Roper361d2ad2011-08-29 13:52:23 -07001186 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001187 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001188
1189 /* Restore original CRTC state */
1190 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001191 origcrtc->x, origcrtc->y,
1192 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001193 drmModeFreeCrtc(origcrtc);
1194
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001195 c->crtc_allocator &= ~(1 << output->crtc_id);
1196 c->connector_allocator &= ~(1 << output->connector_id);
1197
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001198 if (c->use_pixman) {
1199 drm_output_fini_pixman(output);
1200 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001201 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001202 gbm_surface_destroy(output->surface);
1203 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001204
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001205 weston_plane_release(&output->fb_plane);
1206 weston_plane_release(&output->cursor_plane);
1207
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001208 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001209
Matt Roper361d2ad2011-08-29 13:52:23 -07001210 free(output);
1211}
1212
Alex Wub7b8bda2012-04-17 17:20:48 +08001213static struct drm_mode *
1214choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1215{
1216 struct drm_mode *tmp_mode = NULL, *mode;
1217
Hardeningff39efa2013-09-18 23:56:35 +02001218 if (output->base.current_mode->width == target_mode->width &&
1219 output->base.current_mode->height == target_mode->height &&
1220 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001221 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001222 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001223
1224 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1225 if (mode->mode_info.hdisplay == target_mode->width &&
1226 mode->mode_info.vdisplay == target_mode->height) {
Daniel Stonef556ebe2015-05-21 08:28:58 +01001227 if (mode->mode_info.vrefresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001228 target_mode->refresh == 0) {
1229 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001230 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001231 tmp_mode = mode;
1232 }
1233 }
1234
1235 return tmp_mode;
1236}
1237
1238static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001239drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001240static int
1241drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001242
1243static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001244drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1245{
1246 struct drm_output *output;
1247 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001248 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001249
1250 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001251 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001252 return -1;
1253 }
1254
1255 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001256 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001257 return -1;
1258 }
1259
1260 ec = (struct drm_compositor *)output_base->compositor;
1261 output = (struct drm_output *)output_base;
1262 drm_mode = choose_mode (output, mode);
1263
1264 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001265 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001266 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001267 }
1268
Hardeningff39efa2013-09-18 23:56:35 +02001269 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001270 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001271
Hardeningff39efa2013-09-18 23:56:35 +02001272 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001273
Hardeningff39efa2013-09-18 23:56:35 +02001274 output->base.current_mode = &drm_mode->base;
1275 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001276 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1277
Alex Wub7b8bda2012-04-17 17:20:48 +08001278 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001279 drm_output_release_fb(output, output->current);
1280 drm_output_release_fb(output, output->next);
1281 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001282
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001283 if (ec->use_pixman) {
1284 drm_output_fini_pixman(output);
1285 if (drm_output_init_pixman(output, ec) < 0) {
1286 weston_log("failed to init output pixman state with "
1287 "new mode\n");
1288 return -1;
1289 }
1290 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001291 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001292 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001293
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001294 if (drm_output_init_egl(output, ec) < 0) {
1295 weston_log("failed to init output egl state with "
1296 "new mode");
1297 return -1;
1298 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001299 }
1300
Alex Wub7b8bda2012-04-17 17:20:48 +08001301 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001302}
1303
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001304static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001305on_drm_input(int fd, uint32_t mask, void *data)
1306{
1307 drmEventContext evctx;
1308
1309 memset(&evctx, 0, sizeof evctx);
1310 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1311 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001312 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001313 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001314
1315 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001316}
1317
1318static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001319init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001320{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001321 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001322 uint64_t cap;
1323 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001324 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001325
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001326 sysnum = udev_device_get_sysnum(device);
1327 if (sysnum)
1328 ec->drm.id = atoi(sysnum);
1329 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001330 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001331 return -1;
1332 }
1333
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001334 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001335 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001336 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001337 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001338 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001339 udev_device_get_devnode(device));
1340 return -1;
1341 }
1342
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001343 weston_log("using %s\n", filename);
1344
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001345 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001346 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001347
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001348 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1349 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001350 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001351 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001352 clk_id = CLOCK_REALTIME;
1353
1354 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1355 weston_log("Error: failed to set presentation clock %d.\n",
1356 clk_id);
1357 return -1;
1358 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001359
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001360 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1361 if (ret == 0)
1362 ec->cursor_width = cap;
1363 else
1364 ec->cursor_width = 64;
1365
1366 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1367 if (ret == 0)
1368 ec->cursor_height = cap;
1369 else
1370 ec->cursor_height = 64;
1371
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001372 return 0;
1373}
1374
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001375static struct gbm_device *
1376create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001377{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001378 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001379
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001380 gl_renderer = weston_load_module("gl-renderer.so",
1381 "gl_renderer_interface");
1382 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001383 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001384
1385 /* GBM will load a dri driver, but even though they need symbols from
1386 * libglapi, in some version of Mesa they are not linked to it. Since
1387 * only the gl-renderer module links to it, the call above won't make
1388 * these symbols globally available, and loading the DRI driver fails.
1389 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1390 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1391
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001392 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001393
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001394 return gbm;
1395}
1396
Bryce Harringtonc056a982015-05-19 15:25:18 -07001397/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001398 * we may be able to susbstitute an ARGB format for an XRGB one.
1399 *
1400 * This returns 0 if substitution isn't possible, but 0 might be a
1401 * legitimate format for other EGL platforms, so the caller is
1402 * responsible for checking for 0 before calling gl_renderer->create().
1403 *
1404 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1405 * but it's entirely possible we'll see this again on other implementations.
1406 */
1407static int
1408fallback_format_for(uint32_t format)
1409{
1410 switch (format) {
1411 case GBM_FORMAT_XRGB8888:
1412 return GBM_FORMAT_ARGB8888;
1413 case GBM_FORMAT_XRGB2101010:
1414 return GBM_FORMAT_ARGB2101010;
1415 default:
1416 return 0;
1417 }
1418}
1419
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001420static int
1421drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1422{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001423 EGLint format[2] = {
1424 ec->format,
1425 fallback_format_for(ec->format),
1426 };
1427 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001428
Derek Foremanc4cfe852015-05-15 12:12:40 -05001429 if (format[1])
1430 n_formats = 2;
1431 if (gl_renderer->create(&ec->base,
1432 EGL_PLATFORM_GBM_KHR,
1433 (void *)ec->gbm,
1434 gl_renderer->opaque_attribs,
1435 format,
1436 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001437 return -1;
1438 }
1439
1440 return 0;
1441}
1442
1443static int
1444init_egl(struct drm_compositor *ec)
1445{
1446 ec->gbm = create_gbm_device(ec->drm.fd);
1447
1448 if (!ec->gbm)
1449 return -1;
1450
1451 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001452 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001453 return -1;
1454 }
1455
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001456 return 0;
1457}
1458
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001459static int
1460init_pixman(struct drm_compositor *ec)
1461{
1462 return pixman_renderer_init(&ec->base);
1463}
1464
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001465static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001466drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001467{
1468 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001469 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001470
1471 mode = malloc(sizeof *mode);
1472 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001473 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001474
1475 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001476 mode->base.width = info->hdisplay;
1477 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001478
1479 /* Calculate higher precision (mHz) refresh rate */
1480 refresh = (info->clock * 1000000LL / info->htotal +
1481 info->vtotal / 2) / info->vtotal;
1482
1483 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1484 refresh *= 2;
1485 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1486 refresh /= 2;
1487 if (info->vscan > 1)
1488 refresh /= info->vscan;
1489
1490 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001491 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001492
1493 if (info->type & DRM_MODE_TYPE_PREFERRED)
1494 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1495
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001496 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1497
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001498 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001499}
1500
1501static int
1502drm_subpixel_to_wayland(int drm_value)
1503{
1504 switch (drm_value) {
1505 default:
1506 case DRM_MODE_SUBPIXEL_UNKNOWN:
1507 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1508 case DRM_MODE_SUBPIXEL_NONE:
1509 return WL_OUTPUT_SUBPIXEL_NONE;
1510 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1511 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1512 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1513 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1514 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1515 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1516 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1517 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1518 }
1519}
1520
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001521/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001522static uint32_t
1523drm_get_backlight(struct drm_output *output)
1524{
1525 long brightness, max_brightness, norm;
1526
1527 brightness = backlight_get_brightness(output->backlight);
1528 max_brightness = backlight_get_max_brightness(output->backlight);
1529
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001530 /* convert it on a scale of 0 to 255 */
1531 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001532
1533 return (uint32_t) norm;
1534}
1535
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001536/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001537static void
1538drm_set_backlight(struct weston_output *output_base, uint32_t value)
1539{
1540 struct drm_output *output = (struct drm_output *) output_base;
1541 long max_brightness, new_brightness;
1542
1543 if (!output->backlight)
1544 return;
1545
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001546 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001547 return;
1548
1549 max_brightness = backlight_get_max_brightness(output->backlight);
1550
1551 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001552 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001553
1554 backlight_set_brightness(output->backlight, new_brightness);
1555}
1556
1557static drmModePropertyPtr
1558drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1559{
1560 drmModePropertyPtr props;
1561 int i;
1562
1563 for (i = 0; i < connector->count_props; i++) {
1564 props = drmModeGetProperty(fd, connector->props[i]);
1565 if (!props)
1566 continue;
1567
1568 if (!strcmp(props->name, name))
1569 return props;
1570
1571 drmModeFreeProperty(props);
1572 }
1573
1574 return NULL;
1575}
1576
1577static void
1578drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1579{
1580 struct drm_output *output = (struct drm_output *) output_base;
1581 struct weston_compositor *ec = output_base->compositor;
1582 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001583
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001584 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001585 return;
1586
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001587 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1588 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001589}
1590
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001591static const char *connector_type_names[] = {
1592 "None",
1593 "VGA",
1594 "DVI",
1595 "DVI",
1596 "DVI",
1597 "Composite",
1598 "TV",
1599 "LVDS",
1600 "CTV",
1601 "DIN",
1602 "DP",
1603 "HDMI",
1604 "HDMI",
1605 "TV",
1606 "eDP",
1607};
1608
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001609static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001610find_crtc_for_connector(struct drm_compositor *ec,
1611 drmModeRes *resources, drmModeConnector *connector)
1612{
1613 drmModeEncoder *encoder;
1614 uint32_t possible_crtcs;
1615 int i, j;
1616
1617 for (j = 0; j < connector->count_encoders; j++) {
1618 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1619 if (encoder == NULL) {
1620 weston_log("Failed to get encoder.\n");
1621 return -1;
1622 }
1623 possible_crtcs = encoder->possible_crtcs;
1624 drmModeFreeEncoder(encoder);
1625
1626 for (i = 0; i < resources->count_crtcs; i++) {
1627 if (possible_crtcs & (1 << i) &&
1628 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1629 return i;
1630 }
1631 }
1632
1633 return -1;
1634}
1635
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001636/* Init output state that depends on gl or gbm */
1637static int
1638drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1639{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001640 EGLint format[2] = {
1641 output->format,
1642 fallback_format_for(output->format),
1643 };
1644 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001645
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001646 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001647 output->base.current_mode->width,
1648 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001649 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001650 GBM_BO_USE_SCANOUT |
1651 GBM_BO_USE_RENDERING);
1652 if (!output->surface) {
1653 weston_log("failed to create gbm surface\n");
1654 return -1;
1655 }
1656
Derek Foremanc4cfe852015-05-15 12:12:40 -05001657 if (format[1])
1658 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001659 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001660 (EGLNativeDisplayType)output->surface,
1661 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001662 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001663 format,
1664 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001665 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001666 gbm_surface_destroy(output->surface);
1667 return -1;
1668 }
1669
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001670 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001671
1672 for (i = 0; i < 2; i++) {
1673 if (output->cursor_bo[i])
1674 continue;
1675
1676 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001677 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1678 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001679 }
1680
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001681 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1682 weston_log("cursor buffers unavailable, using gl cursors\n");
1683 ec->cursors_are_broken = 1;
1684 }
1685
1686 return 0;
1687}
1688
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001689static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001690drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1691{
Hardeningff39efa2013-09-18 23:56:35 +02001692 int w = output->base.current_mode->width;
1693 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001694 unsigned int i;
1695
1696 /* FIXME error checking */
1697
1698 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001699 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001700 if (!output->dumb[i])
1701 goto err;
1702
1703 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001704 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001705 output->dumb[i]->map,
1706 output->dumb[i]->stride);
1707 if (!output->image[i])
1708 goto err;
1709 }
1710
1711 if (pixman_renderer_output_create(&output->base) < 0)
1712 goto err;
1713
1714 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001715 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001716
1717 return 0;
1718
1719err:
1720 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1721 if (output->dumb[i])
1722 drm_fb_destroy_dumb(output->dumb[i]);
1723 if (output->image[i])
1724 pixman_image_unref(output->image[i]);
1725
1726 output->dumb[i] = NULL;
1727 output->image[i] = NULL;
1728 }
1729
1730 return -1;
1731}
1732
1733static void
1734drm_output_fini_pixman(struct drm_output *output)
1735{
1736 unsigned int i;
1737
1738 pixman_renderer_output_destroy(&output->base);
1739 pixman_region32_fini(&output->previous_damage);
1740
1741 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1742 drm_fb_destroy_dumb(output->dumb[i]);
1743 pixman_image_unref(output->image[i]);
1744 output->dumb[i] = NULL;
1745 output->image[i] = NULL;
1746 }
1747}
1748
Richard Hughes2b2092a2013-04-24 14:58:02 +01001749static void
1750edid_parse_string(const uint8_t *data, char text[])
1751{
1752 int i;
1753 int replaced = 0;
1754
1755 /* this is always 12 bytes, but we can't guarantee it's null
1756 * terminated or not junk. */
1757 strncpy(text, (const char *) data, 12);
1758
1759 /* remove insane chars */
1760 for (i = 0; text[i] != '\0'; i++) {
1761 if (text[i] == '\n' ||
1762 text[i] == '\r') {
1763 text[i] = '\0';
1764 break;
1765 }
1766 }
1767
1768 /* ensure string is printable */
1769 for (i = 0; text[i] != '\0'; i++) {
1770 if (!isprint(text[i])) {
1771 text[i] = '-';
1772 replaced++;
1773 }
1774 }
1775
1776 /* if the string is random junk, ignore the string */
1777 if (replaced > 4)
1778 text[0] = '\0';
1779}
1780
1781#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1782#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1783#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1784#define EDID_OFFSET_DATA_BLOCKS 0x36
1785#define EDID_OFFSET_LAST_BLOCK 0x6c
1786#define EDID_OFFSET_PNPID 0x08
1787#define EDID_OFFSET_SERIAL 0x0c
1788
1789static int
1790edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1791{
1792 int i;
1793 uint32_t serial_number;
1794
1795 /* check header */
1796 if (length < 128)
1797 return -1;
1798 if (data[0] != 0x00 || data[1] != 0xff)
1799 return -1;
1800
1801 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1802 * /--08--\/--09--\
1803 * 7654321076543210
1804 * |\---/\---/\---/
1805 * R C1 C2 C3 */
1806 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1807 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1808 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1809 edid->pnp_id[3] = '\0';
1810
1811 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1812 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1813 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1814 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1815 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1816 if (serial_number > 0)
1817 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1818
1819 /* parse EDID data */
1820 for (i = EDID_OFFSET_DATA_BLOCKS;
1821 i <= EDID_OFFSET_LAST_BLOCK;
1822 i += 18) {
1823 /* ignore pixel clock data */
1824 if (data[i] != 0)
1825 continue;
1826 if (data[i+2] != 0)
1827 continue;
1828
1829 /* any useful blocks? */
1830 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1831 edid_parse_string(&data[i+5],
1832 edid->monitor_name);
1833 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1834 edid_parse_string(&data[i+5],
1835 edid->serial_number);
1836 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1837 edid_parse_string(&data[i+5],
1838 edid->eisa_id);
1839 }
1840 }
1841 return 0;
1842}
1843
1844static void
1845find_and_parse_output_edid(struct drm_compositor *ec,
1846 struct drm_output *output,
1847 drmModeConnector *connector)
1848{
1849 drmModePropertyBlobPtr edid_blob = NULL;
1850 drmModePropertyPtr property;
1851 int i;
1852 int rc;
1853
1854 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1855 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1856 if (!property)
1857 continue;
1858 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1859 !strcmp(property->name, "EDID")) {
1860 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1861 connector->prop_values[i]);
1862 }
1863 drmModeFreeProperty(property);
1864 }
1865 if (!edid_blob)
1866 return;
1867
1868 rc = edid_parse(&output->edid,
1869 edid_blob->data,
1870 edid_blob->length);
1871 if (!rc) {
1872 weston_log("EDID data '%s', '%s', '%s'\n",
1873 output->edid.pnp_id,
1874 output->edid.monitor_name,
1875 output->edid.serial_number);
1876 if (output->edid.pnp_id[0] != '\0')
1877 output->base.make = output->edid.pnp_id;
1878 if (output->edid.monitor_name[0] != '\0')
1879 output->base.model = output->edid.monitor_name;
1880 if (output->edid.serial_number[0] != '\0')
1881 output->base.serial_number = output->edid.serial_number;
1882 }
1883 drmModeFreePropertyBlob(edid_blob);
1884}
1885
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001886
1887
1888static int
1889parse_modeline(const char *s, drmModeModeInfo *mode)
1890{
1891 char hsync[16];
1892 char vsync[16];
1893 float fclock;
1894
1895 mode->type = DRM_MODE_TYPE_USERDEF;
1896 mode->hskew = 0;
1897 mode->vscan = 0;
1898 mode->vrefresh = 0;
1899 mode->flags = 0;
1900
Rob Bradford307e09e2013-07-26 16:29:40 +01001901 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001902 &fclock,
1903 &mode->hdisplay,
1904 &mode->hsync_start,
1905 &mode->hsync_end,
1906 &mode->htotal,
1907 &mode->vdisplay,
1908 &mode->vsync_start,
1909 &mode->vsync_end,
1910 &mode->vtotal, hsync, vsync) != 11)
1911 return -1;
1912
1913 mode->clock = fclock * 1000;
1914 if (strcmp(hsync, "+hsync") == 0)
1915 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1916 else if (strcmp(hsync, "-hsync") == 0)
1917 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1918 else
1919 return -1;
1920
1921 if (strcmp(vsync, "+vsync") == 0)
1922 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1923 else if (strcmp(vsync, "-vsync") == 0)
1924 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1925 else
1926 return -1;
1927
1928 return 0;
1929}
1930
Rob Bradford66bd9f52013-06-25 18:56:42 +01001931static void
1932setup_output_seat_constraint(struct drm_compositor *ec,
1933 struct weston_output *output,
1934 const char *s)
1935{
1936 if (strcmp(s, "") != 0) {
1937 struct udev_seat *seat;
1938
Jonas Ådahl58e15862014-03-12 22:08:40 +01001939 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001940 if (seat)
1941 seat->base.output = output;
1942
1943 if (seat && seat->base.pointer)
1944 weston_pointer_clamp(seat->base.pointer,
1945 &seat->base.pointer->x,
1946 &seat->base.pointer->y);
1947 }
1948}
1949
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001950static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001951get_gbm_format_from_section(struct weston_config_section *section,
1952 uint32_t default_value,
1953 uint32_t *format)
1954{
1955 char *s;
1956 int ret = 0;
1957
1958 weston_config_section_get_string(section,
1959 "gbm-format", &s, NULL);
1960
1961 if (s == NULL)
1962 *format = default_value;
1963 else if (strcmp(s, "xrgb8888") == 0)
1964 *format = GBM_FORMAT_XRGB8888;
1965 else if (strcmp(s, "rgb565") == 0)
1966 *format = GBM_FORMAT_RGB565;
1967 else if (strcmp(s, "xrgb2101010") == 0)
1968 *format = GBM_FORMAT_XRGB2101010;
1969 else {
1970 weston_log("fatal: unrecognized pixel format: %s\n", s);
1971 ret = -1;
1972 }
1973
1974 free(s);
1975
1976 return ret;
1977}
1978
1979static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001980create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001981 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001982 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001983 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001984{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001985 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001986 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001987 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001988 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001989 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001990 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001991 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001992 int i, width, height, scale;
1993 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001994 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001995 enum output_config config;
1996 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001997
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001998 i = find_crtc_for_connector(ec, resources, connector);
1999 if (i < 0) {
2000 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002001 return -1;
2002 }
2003
Peter Huttererf3d62272013-08-08 11:57:05 +10002004 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002005 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002006 return -1;
2007
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002008 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
2009 output->base.make = "unknown";
2010 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002011 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002012 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002013
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002014 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
2015 type_name = connector_type_names[connector->connector_type];
2016 else
2017 type_name = "UNKNOWN";
2018 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01002019 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002020
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002021 section = weston_config_get_section(ec->base.config, "output", "name",
2022 output->base.name);
2023 weston_config_section_get_string(section, "mode", &s, "preferred");
2024 if (strcmp(s, "off") == 0)
2025 config = OUTPUT_CONFIG_OFF;
2026 else if (strcmp(s, "preferred") == 0)
2027 config = OUTPUT_CONFIG_PREFERRED;
2028 else if (strcmp(s, "current") == 0)
2029 config = OUTPUT_CONFIG_CURRENT;
2030 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2031 config = OUTPUT_CONFIG_MODE;
2032 else if (parse_modeline(s, &modeline) == 0)
2033 config = OUTPUT_CONFIG_MODELINE;
2034 else {
2035 weston_log("Invalid mode \"%s\" for output %s\n",
2036 s, output->base.name);
2037 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002038 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002039 free(s);
2040
2041 weston_config_section_get_int(section, "scale", &scale, 1);
2042 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002043 if (weston_parse_transform(s, &transform) < 0)
2044 weston_log("Invalid transform \"%s\" for output %s\n",
2045 s, output->base.name);
2046
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002047 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002048
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002049 if (get_gbm_format_from_section(section,
2050 ec->format,
2051 &output->format) == -1)
2052 output->format = ec->format;
2053
Rob Bradford66bd9f52013-06-25 18:56:42 +01002054 weston_config_section_get_string(section, "seat", &s, "");
2055 setup_output_seat_constraint(ec, &output->base, s);
2056 free(s);
2057
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002058 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002059 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002060 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002061 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002062 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002063
Matt Roper361d2ad2011-08-29 13:52:23 -07002064 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002065 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002066
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002067 /* Get the current mode on the crtc that's currently driving
2068 * this connector. */
2069 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002070 memset(&crtc_mode, 0, sizeof crtc_mode);
2071 if (encoder != NULL) {
2072 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2073 drmModeFreeEncoder(encoder);
2074 if (crtc == NULL)
2075 goto err_free;
2076 if (crtc->mode_valid)
2077 crtc_mode = crtc->mode;
2078 drmModeFreeCrtc(crtc);
2079 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002080
David Herrmann0f0d54e2011-12-08 17:05:45 +01002081 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002082 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002083 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002084 goto err_free;
2085 }
2086
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002087 if (config == OUTPUT_CONFIG_OFF) {
2088 weston_log("Disabling output %s\n", output->base.name);
2089 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2090 0, 0, 0, 0, 0, NULL);
2091 goto err_free;
2092 }
2093
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002094 preferred = NULL;
2095 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002096 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002097 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002098
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002099 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002100 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002101 width == drm_mode->base.width &&
2102 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002103 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002104 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002105 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002106 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002107 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002108 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002109 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002110
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002111 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002112 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002113 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002114 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002115 }
2116
Wang Quanxianacb805a2012-07-30 18:09:46 -04002117 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002118 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002119 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002120 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002121 }
2122
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002123 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002124 configured = current;
2125
Wang Quanxianacb805a2012-07-30 18:09:46 -04002126 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002127 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002128 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002129 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002130 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002131 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002132 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002133 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002134 else if (best)
2135 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002136
Hardeningff39efa2013-09-18 23:56:35 +02002137 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002138 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002139 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002140 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002141
Hardeningff39efa2013-09-18 23:56:35 +02002142 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002143
John Kåre Alsaker94659272012-11-13 19:10:18 +01002144 weston_output_init(&output->base, &ec->base, x, y,
2145 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002146 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002147
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002148 if (ec->use_pixman) {
2149 if (drm_output_init_pixman(output, ec) < 0) {
2150 weston_log("Failed to init output pixman state\n");
2151 goto err_output;
2152 }
2153 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002154 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002155 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002156 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002157
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002158 output->backlight = backlight_init(drm_device,
2159 connector->connector_type);
2160 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002161 weston_log("Initialized backlight, device %s\n",
2162 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002163 output->base.set_backlight = drm_set_backlight;
2164 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002165 } else {
2166 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002167 }
2168
Giulio Camuffob1147152015-05-06 21:41:57 +03002169 weston_compositor_add_output(&ec->base, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002170
Richard Hughes2b2092a2013-04-24 14:58:02 +01002171 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002172 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2173 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002174
Jonas Ådahle5a12252013-04-05 23:07:11 +02002175 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002176 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002177 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002178 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002179 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002180 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002181
Richard Hughese7299962013-05-01 21:52:12 +01002182 output->base.gamma_size = output->original_crtc->gamma_size;
2183 output->base.set_gamma = drm_output_set_gamma;
2184
Xiong Zhang97116532013-10-23 13:58:31 +08002185 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2186 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002187
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002188 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2189 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2190 &ec->base.primary_plane);
2191
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002192 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002193 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002194 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002195 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002196 m->width, m->height, m->refresh / 1000.0,
2197 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2198 ", preferred" : "",
2199 m->flags & WL_OUTPUT_MODE_CURRENT ?
2200 ", current" : "",
2201 connector->count_modes == 0 ?
2202 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002203
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002205
John Kåre Alsaker94659272012-11-13 19:10:18 +01002206err_output:
2207 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002208err_free:
2209 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2210 base.link) {
2211 wl_list_remove(&drm_mode->base.link);
2212 free(drm_mode);
2213 }
2214
2215 drmModeFreeCrtc(output->original_crtc);
2216 ec->crtc_allocator &= ~(1 << output->crtc_id);
2217 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002218 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002219
David Herrmann0f0d54e2011-12-08 17:05:45 +01002220 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002221}
2222
Jesse Barnes58ef3792012-02-23 09:45:49 -05002223static void
2224create_sprites(struct drm_compositor *ec)
2225{
2226 struct drm_sprite *sprite;
2227 drmModePlaneRes *plane_res;
2228 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002229 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002230
2231 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2232 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002233 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002234 strerror(errno));
2235 return;
2236 }
2237
2238 for (i = 0; i < plane_res->count_planes; i++) {
2239 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2240 if (!plane)
2241 continue;
2242
Peter Huttererf3d62272013-08-08 11:57:05 +10002243 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002244 plane->count_formats));
2245 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002246 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002247 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002248 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002249 continue;
2250 }
2251
Jesse Barnes58ef3792012-02-23 09:45:49 -05002252 sprite->possible_crtcs = plane->possible_crtcs;
2253 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002254 sprite->current = NULL;
2255 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002256 sprite->compositor = ec;
2257 sprite->count_formats = plane->count_formats;
2258 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002259 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002260 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002261 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002262 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2263 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002264
2265 wl_list_insert(&ec->sprite_list, &sprite->link);
2266 }
2267
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002268 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002269}
2270
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002271static void
2272destroy_sprites(struct drm_compositor *compositor)
2273{
2274 struct drm_sprite *sprite, *next;
2275 struct drm_output *output;
2276
2277 output = container_of(compositor->base.output_list.next,
2278 struct drm_output, base.link);
2279
2280 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2281 drmModeSetPlane(compositor->drm.fd,
2282 sprite->plane_id,
2283 output->crtc_id, 0, 0,
2284 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002285 drm_output_release_fb(output, sprite->current);
2286 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002287 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002288 free(sprite);
2289 }
2290}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002291
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002292static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002293create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002294 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002295{
2296 drmModeConnector *connector;
2297 drmModeRes *resources;
2298 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002299 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002300
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002301 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002302 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002303 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002304 return -1;
2305 }
2306
Jesse Barnes58ef3792012-02-23 09:45:49 -05002307 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002308 if (!ec->crtcs) {
2309 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002310 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002311 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002312
Rob Clark4339add2012-08-09 14:18:28 -05002313 ec->min_width = resources->min_width;
2314 ec->max_width = resources->max_width;
2315 ec->min_height = resources->min_height;
2316 ec->max_height = resources->max_height;
2317
Jesse Barnes58ef3792012-02-23 09:45:49 -05002318 ec->num_crtcs = resources->count_crtcs;
2319 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2320
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002321 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002322 connector = drmModeGetConnector(ec->drm.fd,
2323 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002324 if (connector == NULL)
2325 continue;
2326
2327 if (connector->connection == DRM_MODE_CONNECTED &&
2328 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002329 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002330 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002331 connector, x, y,
2332 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002333 drmModeFreeConnector(connector);
2334 continue;
2335 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002336
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002337 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002338 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002339 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002340 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002341
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002342 drmModeFreeConnector(connector);
2343 }
2344
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002345 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002346 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002347 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002348 return -1;
2349 }
2350
2351 drmModeFreeResources(resources);
2352
2353 return 0;
2354}
2355
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002356static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002357update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002358{
2359 drmModeConnector *connector;
2360 drmModeRes *resources;
2361 struct drm_output *output, *next;
2362 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002363 uint32_t connected = 0, disconnects = 0;
2364 int i;
2365
2366 resources = drmModeGetResources(ec->drm.fd);
2367 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002368 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002369 return;
2370 }
2371
2372 /* collect new connects */
2373 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002374 int connector_id = resources->connectors[i];
2375
2376 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002377 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002378 continue;
2379
David Herrmann7551cff2011-12-08 17:05:43 +01002380 if (connector->connection != DRM_MODE_CONNECTED) {
2381 drmModeFreeConnector(connector);
2382 continue;
2383 }
2384
Benjamin Franzke117483d2011-08-30 11:38:26 +02002385 connected |= (1 << connector_id);
2386
2387 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002388 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002389 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002390 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002391
2392 /* XXX: not yet needed, we die with 0 outputs */
2393 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002394 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002395 else
2396 x = 0;
2397 y = 0;
2398 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002399 connector, x, y,
2400 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002401 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002402
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002403 }
2404 drmModeFreeConnector(connector);
2405 }
2406 drmModeFreeResources(resources);
2407
2408 disconnects = ec->connector_allocator & ~connected;
2409 if (disconnects) {
2410 wl_list_for_each_safe(output, next, &ec->base.output_list,
2411 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002412 if (disconnects & (1 << output->connector_id)) {
2413 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002414 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002415 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002416 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002417 }
2418 }
2419 }
2420
Daniel Stonef556ebe2015-05-21 08:28:58 +01002421 /* FIXME: handle zero outputs, without terminating */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002422 if (ec->connector_allocator == 0)
2423 wl_display_terminate(ec->base.wl_display);
2424}
2425
2426static int
David Herrmannd7488c22012-03-11 20:05:21 +01002427udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002428{
David Herrmannd7488c22012-03-11 20:05:21 +01002429 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002430 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002431
2432 sysnum = udev_device_get_sysnum(device);
2433 if (!sysnum || atoi(sysnum) != ec->drm.id)
2434 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002435
David Herrmann6ac52db2012-03-11 20:05:22 +01002436 val = udev_device_get_property_value(device, "HOTPLUG");
2437 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002438 return 0;
2439
David Herrmann6ac52db2012-03-11 20:05:22 +01002440 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002441}
2442
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002443static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002444udev_drm_event(int fd, uint32_t mask, void *data)
2445{
2446 struct drm_compositor *ec = data;
2447 struct udev_device *event;
2448
2449 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002450
David Herrmannd7488c22012-03-11 20:05:21 +01002451 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002452 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002453
2454 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002455
2456 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002457}
2458
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002459static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002460drm_restore(struct weston_compositor *ec)
2461{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002462 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002463}
2464
2465static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002466drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002467{
2468 struct drm_compositor *d = (struct drm_compositor *) ec;
2469
Rob Bradfordd355b802013-05-31 18:09:55 +01002470 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002471
2472 wl_event_source_remove(d->udev_drm_source);
2473 wl_event_source_remove(d->drm_source);
2474
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002475 destroy_sprites(d);
2476
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002477 weston_compositor_shutdown(ec);
2478
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002479 if (d->gbm)
2480 gbm_device_destroy(d->gbm);
2481
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002482 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002483
Rob Bradford45c15b82013-07-26 16:29:35 +01002484 close(d->drm.fd);
2485
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002486 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002487}
2488
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002489static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002490drm_compositor_set_modes(struct drm_compositor *compositor)
2491{
2492 struct drm_output *output;
2493 struct drm_mode *drm_mode;
2494 int ret;
2495
2496 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002497 if (!output->current) {
2498 /* If something that would cause the output to
2499 * switch mode happened while in another vt, we
2500 * might not have a current drm_fb. In that case,
2501 * schedule a repaint and let drm_output_repaint
2502 * handle setting the mode. */
2503 weston_output_schedule_repaint(&output->base);
2504 continue;
2505 }
2506
Hardeningff39efa2013-09-18 23:56:35 +02002507 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002508 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002509 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002510 &output->connector_id, 1,
2511 &drm_mode->mode_info);
2512 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002513 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002514 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002515 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002516 output->base.x, output->base.y);
2517 }
2518 }
2519}
2520
2521static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002522session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002523{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002524 struct weston_compositor *compositor = data;
2525 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002526 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002527 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002528
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002529 if (ec->base.session_active) {
2530 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002531 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002532 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002533 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002534 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002535 } else {
2536 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002537 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002538
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002539 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002540 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002541
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002542 /* If we have a repaint scheduled (either from a
2543 * pending pageflip or the idle handler), make sure we
2544 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002545 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002546 * further attemps at repainting. When we switch
2547 * back, we schedule a repaint, which will process
2548 * pending frame callbacks. */
2549
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002550 wl_list_for_each(output, &ec->base.output_list, base.link) {
2551 output->base.repaint_needed = 0;
2552 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002553 }
2554
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002555 output = container_of(ec->base.output_list.next,
2556 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002557
2558 wl_list_for_each(sprite, &ec->sprite_list, link)
2559 drmModeSetPlane(ec->drm.fd,
2560 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002561 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002562 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002563 };
2564}
2565
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002566static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002567switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002568{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002569 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002570
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002571 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002572}
2573
David Herrmann0af066f2012-10-29 19:21:16 +01002574/*
2575 * Find primary GPU
2576 * Some systems may have multiple DRM devices attached to a single seat. This
2577 * function loops over all devices and tries to find a PCI device with the
2578 * boot_vga sysfs attribute set to 1.
2579 * If no such device is found, the first DRM device reported by udev is used.
2580 */
2581static struct udev_device*
2582find_primary_gpu(struct drm_compositor *ec, const char *seat)
2583{
2584 struct udev_enumerate *e;
2585 struct udev_list_entry *entry;
2586 const char *path, *device_seat, *id;
2587 struct udev_device *device, *drm_device, *pci;
2588
2589 e = udev_enumerate_new(ec->udev);
2590 udev_enumerate_add_match_subsystem(e, "drm");
2591 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2592
2593 udev_enumerate_scan_devices(e);
2594 drm_device = NULL;
2595 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2596 path = udev_list_entry_get_name(entry);
2597 device = udev_device_new_from_syspath(ec->udev, path);
2598 if (!device)
2599 continue;
2600 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2601 if (!device_seat)
2602 device_seat = default_seat;
2603 if (strcmp(device_seat, seat)) {
2604 udev_device_unref(device);
2605 continue;
2606 }
2607
2608 pci = udev_device_get_parent_with_subsystem_devtype(device,
2609 "pci", NULL);
2610 if (pci) {
2611 id = udev_device_get_sysattr_value(pci, "boot_vga");
2612 if (id && !strcmp(id, "1")) {
2613 if (drm_device)
2614 udev_device_unref(drm_device);
2615 drm_device = device;
2616 break;
2617 }
2618 }
2619
2620 if (!drm_device)
2621 drm_device = device;
2622 else
2623 udev_device_unref(device);
2624 }
2625
2626 udev_enumerate_unref(e);
2627 return drm_device;
2628}
2629
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002630static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002631planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002632{
2633 struct drm_compositor *c = data;
2634
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002635 switch (key) {
2636 case KEY_C:
2637 c->cursors_are_broken ^= 1;
2638 break;
2639 case KEY_V:
2640 c->sprites_are_broken ^= 1;
2641 break;
2642 case KEY_O:
2643 c->sprites_hidden ^= 1;
2644 break;
2645 default:
2646 break;
2647 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002648}
2649
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002650#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002651static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002652recorder_destroy(struct drm_output *output)
2653{
2654 vaapi_recorder_destroy(output->recorder);
2655 output->recorder = NULL;
2656
2657 output->base.disable_planes--;
2658
2659 wl_list_remove(&output->recorder_frame_listener.link);
2660 weston_log("[libva recorder] done\n");
2661}
2662
2663static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002664recorder_frame_notify(struct wl_listener *listener, void *data)
2665{
2666 struct drm_output *output;
2667 struct drm_compositor *c;
2668 int fd, ret;
2669
2670 output = container_of(listener, struct drm_output,
2671 recorder_frame_listener);
2672 c = (struct drm_compositor *) output->base.compositor;
2673
2674 if (!output->recorder)
2675 return;
2676
2677 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2678 DRM_CLOEXEC, &fd);
2679 if (ret) {
2680 weston_log("[libva recorder] "
2681 "failed to create prime fd for front buffer\n");
2682 return;
2683 }
2684
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002685 ret = vaapi_recorder_frame(output->recorder, fd,
2686 output->current->stride);
2687 if (ret < 0) {
2688 weston_log("[libva recorder] aborted: %m\n");
2689 recorder_destroy(output);
2690 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002691}
2692
2693static void *
2694create_recorder(struct drm_compositor *c, int width, int height,
2695 const char *filename)
2696{
2697 int fd;
2698 drm_magic_t magic;
2699
2700 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2701 if (fd < 0)
2702 return NULL;
2703
2704 drmGetMagic(fd, &magic);
2705 drmAuthMagic(c->drm.fd, magic);
2706
2707 return vaapi_recorder_create(fd, width, height, filename);
2708}
2709
2710static void
2711recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2712 void *data)
2713{
2714 struct drm_compositor *c = data;
2715 struct drm_output *output;
2716 int width, height;
2717
2718 output = container_of(c->base.output_list.next,
2719 struct drm_output, base.link);
2720
2721 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002722 if (output->format != GBM_FORMAT_XRGB8888) {
2723 weston_log("failed to start vaapi recorder: "
2724 "output format not supported\n");
2725 return;
2726 }
2727
Hardeningff39efa2013-09-18 23:56:35 +02002728 width = output->base.current_mode->width;
2729 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002730
2731 output->recorder =
2732 create_recorder(c, width, height, "capture.h264");
2733 if (!output->recorder) {
2734 weston_log("failed to create vaapi recorder\n");
2735 return;
2736 }
2737
2738 output->base.disable_planes++;
2739
2740 output->recorder_frame_listener.notify = recorder_frame_notify;
2741 wl_signal_add(&output->base.frame_signal,
2742 &output->recorder_frame_listener);
2743
2744 weston_output_schedule_repaint(&output->base);
2745
2746 weston_log("[libva recorder] initialized\n");
2747 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002748 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002749 }
2750}
2751#else
2752static void
2753recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2754 void *data)
2755{
2756 weston_log("Compiled without libva support\n");
2757}
2758#endif
2759
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002760static void
2761switch_to_gl_renderer(struct drm_compositor *c)
2762{
2763 struct drm_output *output;
2764
2765 if (!c->use_pixman)
2766 return;
2767
2768 weston_log("Switching to GL renderer\n");
2769
2770 c->gbm = create_gbm_device(c->drm.fd);
2771 if (!c->gbm) {
2772 weston_log("Failed to create gbm device. "
2773 "Aborting renderer switch\n");
2774 return;
2775 }
2776
2777 wl_list_for_each(output, &c->base.output_list, base.link)
2778 pixman_renderer_output_destroy(&output->base);
2779
2780 c->base.renderer->destroy(&c->base);
2781
2782 if (drm_compositor_create_gl_renderer(c) < 0) {
2783 gbm_device_destroy(c->gbm);
2784 weston_log("Failed to create GL renderer. Quitting.\n");
2785 /* FIXME: we need a function to shutdown cleanly */
2786 assert(0);
2787 }
2788
2789 wl_list_for_each(output, &c->base.output_list, base.link)
2790 drm_output_init_egl(output, c);
2791
2792 c->use_pixman = 0;
2793}
2794
2795static void
2796renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2797 void *data)
2798{
2799 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2800
2801 switch_to_gl_renderer(c);
2802}
2803
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002804static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002805drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002806 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002807 int *argc, char *argv[],
2808 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002809{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002810 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002811 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002812 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002813 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002814 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002815 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002816
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002817 weston_log("initializing drm backend\n");
2818
Peter Huttererf3d62272013-08-08 11:57:05 +10002819 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002820 if (ec == NULL)
2821 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002822
Pekka Paalanen68583832015-05-19 09:53:16 +03002823 /*
2824 * KMS support for hardware planes cannot properly synchronize
2825 * without nuclear page flip. Without nuclear/atomic, hw plane
2826 * and cursor plane updates would either tear or cause extra
2827 * waits for vblanks which means dropping the compositor framerate
2828 * to a fraction.
2829 *
2830 * These can be enabled again when nuclear/atomic support lands.
2831 */
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002832 ec->sprites_are_broken = 1;
Pekka Paalanen68583832015-05-19 09:53:16 +03002833 ec->cursors_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002834
2835 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002836 if (get_gbm_format_from_section(section,
2837 GBM_FORMAT_XRGB8888,
2838 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002839 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002840
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002841 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002842
Daniel Stone725c2c32012-06-22 14:04:36 +01002843 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002844 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002845 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002846 goto err_base;
2847 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002848
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002849 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002850 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002851 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002852 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002853 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002854 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002855 goto err_compositor;
2856 }
2857
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002858 ec->udev = udev_new();
2859 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002860 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002861 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002862 }
2863
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002864 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002865 ec->session_listener.notify = session_notify;
2866 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002867
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002868 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002869 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002870 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002871 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002872 }
David Herrmann0af066f2012-10-29 19:21:16 +01002873 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002874
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002875 if (init_drm(ec, drm_device) < 0) {
2876 weston_log("failed to initialize kms\n");
2877 goto err_udev_dev;
2878 }
2879
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002880 if (ec->use_pixman) {
2881 if (init_pixman(ec) < 0) {
2882 weston_log("failed to initialize pixman renderer\n");
2883 goto err_udev_dev;
2884 }
2885 } else {
2886 if (init_egl(ec) < 0) {
2887 weston_log("failed to initialize egl\n");
2888 goto err_udev_dev;
2889 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002890 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002891
2892 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002893 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002894
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002895 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002896
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002897 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002898 weston_compositor_add_key_binding(&ec->base, key,
2899 MODIFIER_CTRL | MODIFIER_ALT,
2900 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002901
Jesse Barnes58ef3792012-02-23 09:45:49 -05002902 wl_list_init(&ec->sprite_list);
2903 create_sprites(ec);
2904
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002905 if (udev_input_init(&ec->input,
2906 &ec->base, ec->udev, param->seat_id) < 0) {
2907 weston_log("failed to create input devices\n");
2908 goto err_sprite;
2909 }
2910
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002911 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002912 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002913 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002914 }
2915
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002916 /* A this point we have some idea of whether or not we have a working
2917 * cursor plane. */
2918 if (!ec->cursors_are_broken)
2919 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2920
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002921 path = NULL;
2922
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002923 loop = wl_display_get_event_loop(ec->base.wl_display);
2924 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002925 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002926 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002927
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002928 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2929 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002930 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002931 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002932 }
2933 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2934 "drm", NULL);
2935 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002936 wl_event_loop_add_fd(loop,
2937 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002938 WL_EVENT_READABLE, udev_drm_event, ec);
2939
2940 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002941 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002942 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002943 }
2944
Daniel Stonea96b93c2012-06-22 14:04:37 +01002945 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002946
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002947 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002948 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002949 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002950 planes_binding, ec);
2951 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2952 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002953 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2954 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002955 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2956 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002957
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002958 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002959
2960err_udev_monitor:
2961 wl_event_source_remove(ec->udev_drm_source);
2962 udev_monitor_unref(ec->udev_monitor);
2963err_drm_source:
2964 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002965err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002966 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002967err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002968 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002969 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002970 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002971err_udev_dev:
2972 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002973err_launcher:
2974 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002975err_udev:
2976 udev_unref(ec->udev);
2977err_compositor:
2978 weston_compositor_shutdown(&ec->base);
2979err_base:
2980 free(ec);
2981 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002982}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002983
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002984WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002985backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002986 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002987{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002988 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002989
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002990 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002991 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2992 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2993 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002994 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002995 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002996 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002997
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002998 param.seat_id = default_seat;
2999
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003000 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003001
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003002 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003003}