blob: b4ca916ec6feb5f11c8b65a0d43f23365fb19443 [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
Jon Cruz35b2eaa2015-06-15 15:37:08 -070049#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020050#include "shared/timespec-util.h"
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080051#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040052#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010053#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020054#include "pixman-renderer.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100055#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010056#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030057#include "vaapi-recorder.h"
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020058#include "presentation_timing-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040059
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030060#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
61#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
62#endif
63
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030064#ifndef DRM_CAP_CURSOR_WIDTH
65#define DRM_CAP_CURSOR_WIDTH 0x8
66#endif
67
68#ifndef DRM_CAP_CURSOR_HEIGHT
69#define DRM_CAP_CURSOR_HEIGHT 0x9
70#endif
71
72#ifndef GBM_BO_USE_CURSOR
73#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
74#endif
75
Kristian Høgsberg061c4252012-06-28 11:28:15 -040076static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060077
78enum output_config {
79 OUTPUT_CONFIG_INVALID = 0,
80 OUTPUT_CONFIG_OFF,
81 OUTPUT_CONFIG_PREFERRED,
82 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060083 OUTPUT_CONFIG_MODE,
84 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060085};
86
Giulio Camuffo954f1832014-10-11 18:27:30 +030087struct drm_backend {
88 struct weston_backend base;
89 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040090
91 struct udev *udev;
92 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040093
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010094 struct udev_monitor *udev_monitor;
95 struct wl_event_source *udev_drm_source;
96
Benjamin Franzke2af7f102011-03-02 11:14:59 +010097 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010098 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010099 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300100 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100101 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200102 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500103 uint32_t *crtcs;
104 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -0500105 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100106 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700107 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700108 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200109
Rob Clark4339add2012-08-09 14:18:28 -0500110 /* we need these parameters in order to not fail drmModeAddFB2()
111 * due to out of bounds dimensions, and then mistakenly set
112 * sprites_are_broken:
113 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200114 uint32_t min_width, max_width;
115 uint32_t min_height, max_height;
116 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500117
Jesse Barnes58ef3792012-02-23 09:45:49 -0500118 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500119 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200120 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500121
Rob Clarkab5b1e32012-08-09 13:24:45 -0500122 int cursors_are_broken;
123
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200124 int use_pixman;
125
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200126 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300127
Rob Bradfordd355b802013-05-31 18:09:55 +0100128 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300129
Daniel Stone70d337d2015-06-16 18:42:23 +0100130 int32_t cursor_width;
131 int32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400132};
133
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400134struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500135 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400136 drmModeModeInfo mode_info;
137};
138
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300139struct drm_output;
140
141struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300142 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200143 uint32_t fb_id, stride, handle, size;
144 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300145 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200146 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200147
148 /* Used by gbm fbs */
149 struct gbm_bo *bo;
150
151 /* Used by dumb fbs */
152 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300153};
154
Richard Hughes2b2092a2013-04-24 14:58:02 +0100155struct drm_edid {
156 char eisa_id[13];
157 char monitor_name[13];
158 char pnp_id[5];
159 char serial_number[13];
160};
161
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400162struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500163 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400164
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400165 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500166 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400167 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700168 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100169 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300170 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000171 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200172
Daniel Stone36609c72015-06-18 07:49:02 +0100173 enum dpms_enum dpms;
174
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300175 int vblank_pending;
176 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800177 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300178
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400179 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400180 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400181 struct weston_plane cursor_plane;
182 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500183 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400184 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300185 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200186 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200187
188 struct drm_fb *dumb[2];
189 pixman_image_t *image[2];
190 int current_image;
191 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300192
193 struct vaapi_recorder *recorder;
194 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400195};
196
Jesse Barnes58ef3792012-02-23 09:45:49 -0500197/*
198 * An output has a primary display plane plus zero or more sprites for
199 * blending display contents.
200 */
201struct drm_sprite {
202 struct wl_list link;
203
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400204 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500205
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200206 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300207 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300208 struct drm_backend *backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500209
Jesse Barnes58ef3792012-02-23 09:45:49 -0500210 uint32_t possible_crtcs;
211 uint32_t plane_id;
212 uint32_t count_formats;
213
214 int32_t src_x, src_y;
215 uint32_t src_w, src_h;
216 uint32_t dest_x, dest_y;
217 uint32_t dest_w, dest_h;
218
219 uint32_t formats[];
220};
221
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700222struct drm_parameters {
223 int connector;
224 int tty;
225 int use_pixman;
226 const char *seat_id;
227};
228
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300229static struct gl_renderer_interface *gl_renderer;
230
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500231static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400232
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400233static void
234drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400235
Mario Kleinerf507ec32015-06-21 21:25:14 +0200236static void
237drm_output_update_msc(struct drm_output *output, unsigned int seq);
238
Jesse Barnes58ef3792012-02-23 09:45:49 -0500239static int
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200240drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500241{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200242 struct weston_compositor *ec = output->base.compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300243 struct drm_backend *b =(struct drm_backend *)ec->backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500244 int crtc;
245
Giulio Camuffo954f1832014-10-11 18:27:30 +0300246 for (crtc = 0; crtc < b->num_crtcs; crtc++) {
247 if (b->crtcs[crtc] != output->crtc_id)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500248 continue;
249
250 if (supported & (1 << crtc))
251 return -1;
252 }
253
254 return 0;
255}
256
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300257static void
258drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
259{
260 struct drm_fb *fb = data;
261 struct gbm_device *gbm = gbm_bo_get_device(bo);
262
263 if (fb->fb_id)
264 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
265
Pekka Paalanende685b82012-12-04 15:58:12 +0200266 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300267
268 free(data);
269}
270
271static struct drm_fb *
Giulio Camuffo954f1832014-10-11 18:27:30 +0300272drm_fb_create_dumb(struct drm_backend *b, unsigned width, unsigned height)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200273{
274 struct drm_fb *fb;
275 int ret;
276
277 struct drm_mode_create_dumb create_arg;
278 struct drm_mode_destroy_dumb destroy_arg;
279 struct drm_mode_map_dumb map_arg;
280
Peter Huttererf3d62272013-08-08 11:57:05 +1000281 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200282 if (!fb)
283 return NULL;
284
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700285 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200286 create_arg.bpp = 32;
287 create_arg.width = width;
288 create_arg.height = height;
289
Giulio Camuffo954f1832014-10-11 18:27:30 +0300290 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200291 if (ret)
292 goto err_fb;
293
294 fb->handle = create_arg.handle;
295 fb->stride = create_arg.pitch;
296 fb->size = create_arg.size;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300297 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200298
Giulio Camuffo954f1832014-10-11 18:27:30 +0300299 ret = drmModeAddFB(b->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200300 fb->stride, fb->handle, &fb->fb_id);
301 if (ret)
302 goto err_bo;
303
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700304 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200305 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400306 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200307 if (ret)
308 goto err_add_fb;
309
310 fb->map = mmap(0, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300311 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200312 if (fb->map == MAP_FAILED)
313 goto err_add_fb;
314
315 return fb;
316
317err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300318 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200319err_bo:
320 memset(&destroy_arg, 0, sizeof(destroy_arg));
321 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300322 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200323err_fb:
324 free(fb);
325 return NULL;
326}
327
328static void
329drm_fb_destroy_dumb(struct drm_fb *fb)
330{
331 struct drm_mode_destroy_dumb destroy_arg;
332
333 if (!fb->map)
334 return;
335
336 if (fb->fb_id)
337 drmModeRmFB(fb->fd, fb->fb_id);
338
339 weston_buffer_reference(&fb->buffer_ref, NULL);
340
341 munmap(fb->map, fb->size);
342
343 memset(&destroy_arg, 0, sizeof(destroy_arg));
344 destroy_arg.handle = fb->handle;
345 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
346
347 free(fb);
348}
349
350static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500351drm_fb_get_from_bo(struct gbm_bo *bo,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300352 struct drm_backend *backend, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300353{
354 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200355 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200356 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300357 int ret;
358
359 if (fb)
360 return fb;
361
Bryce Harringtonde16d892014-11-20 22:21:57 -0800362 fb = zalloc(sizeof *fb);
363 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200364 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365
366 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367
368 width = gbm_bo_get_width(bo);
369 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200370 fb->stride = gbm_bo_get_stride(bo);
371 fb->handle = gbm_bo_get_handle(bo).u32;
372 fb->size = fb->stride * height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300373 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300374
Giulio Camuffo954f1832014-10-11 18:27:30 +0300375 if (backend->min_width > width || width > backend->max_width ||
376 backend->min_height > height ||
377 height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200378 weston_log("bo geometry out of bounds\n");
379 goto err_free;
380 }
381
382 ret = -1;
383
Giulio Camuffo954f1832014-10-11 18:27:30 +0300384 if (format && !backend->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200385 handles[0] = fb->handle;
386 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200387 offsets[0] = 0;
388
Giulio Camuffo954f1832014-10-11 18:27:30 +0300389 ret = drmModeAddFB2(backend->drm.fd, width, height,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200390 format, handles, pitches, offsets,
391 &fb->fb_id, 0);
392 if (ret) {
393 weston_log("addfb2 failed: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300394 backend->no_addfb2 = 1;
395 backend->sprites_are_broken = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200396 }
397 }
398
399 if (ret)
Giulio Camuffo954f1832014-10-11 18:27:30 +0300400 ret = drmModeAddFB(backend->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200401 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200402
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300403 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200404 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200405 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300406 }
407
408 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
409
410 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200411
412err_free:
413 free(fb);
414 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300415}
416
417static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500418drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200419{
Pekka Paalanende685b82012-12-04 15:58:12 +0200420 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200421
422 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200423
Pekka Paalanende685b82012-12-04 15:58:12 +0200424 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200425}
426
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200427static void
428drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
429{
430 if (!fb)
431 return;
432
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200433 if (fb->map &&
434 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200435 drm_fb_destroy_dumb(fb);
436 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200437 if (fb->is_client_buffer)
438 gbm_bo_destroy(fb->bo);
439 else
440 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600441 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200442 }
443}
444
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500445static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200446drm_output_check_scanout_format(struct drm_output *output,
447 struct weston_surface *es, struct gbm_bo *bo)
448{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200449 uint32_t format;
450 pixman_region32_t r;
451
452 format = gbm_bo_get_format(bo);
453
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700454 if (format == GBM_FORMAT_ARGB8888) {
455 /* We can scanout an ARGB buffer if the surface's
456 * opaque region covers the whole output, but we have
457 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800458 pixman_region32_init_rect(&r, 0, 0,
459 output->base.width,
460 output->base.height);
461 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200462
463 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500464 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200465
466 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500467 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700468
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000469 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700470 return format;
471
472 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200473}
474
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400475static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200476drm_output_prepare_scanout_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500477 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500478{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300479 struct drm_backend *b =
480 (struct drm_backend *)output->base.compositor->backend;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500481 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200482 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300483 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500484 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500485
Jason Ekstranda7af7042013-10-12 22:38:11 -0500486 if (ev->geometry.x != output->base.x ||
487 ev->geometry.y != output->base.y ||
Giulio Camuffo954f1832014-10-11 18:27:30 +0300488 buffer == NULL || b->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200489 buffer->width != output->base.current_mode->width ||
490 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200491 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500492 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400493 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500494
Pekka Paalanen5580f222015-02-17 16:33:18 +0200495 if (ev->geometry.scissor_enabled)
496 return NULL;
497
Giulio Camuffo954f1832014-10-11 18:27:30 +0300498 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700499 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500500
Rob Bradford9b101872012-09-14 23:25:41 +0100501 /* Unable to use the buffer for scanout */
502 if (!bo)
503 return NULL;
504
Jason Ekstranda7af7042013-10-12 22:38:11 -0500505 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500506 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300507 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400508 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300509 }
510
Giulio Camuffo954f1832014-10-11 18:27:30 +0300511 output->next = drm_fb_get_from_bo(bo, b, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300512 if (!output->next) {
513 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400514 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300515 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500516
Pekka Paalanende685b82012-12-04 15:58:12 +0200517 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500518
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400519 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500520}
521
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500522static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200523drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400524{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300525 struct drm_backend *b =
526 (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300527 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400528
Giulio Camuffo954f1832014-10-11 18:27:30 +0300529 output->base.compositor->renderer->repaint_output(&output->base,
530 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400531
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300532 bo = gbm_surface_lock_front_buffer(output->surface);
533 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200534 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400535 return;
536 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300537
Giulio Camuffo954f1832014-10-11 18:27:30 +0300538 output->next = drm_fb_get_from_bo(bo, b, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300539 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200540 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300541 gbm_surface_release_buffer(output->surface, bo);
542 return;
543 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400544}
545
546static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200547drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
548{
549 struct weston_compositor *ec = output->base.compositor;
550 pixman_region32_t total_damage, previous_damage;
551
552 pixman_region32_init(&total_damage);
553 pixman_region32_init(&previous_damage);
554
555 pixman_region32_copy(&previous_damage, damage);
556
557 pixman_region32_union(&total_damage, damage, &output->previous_damage);
558 pixman_region32_copy(&output->previous_damage, &previous_damage);
559
560 output->current_image ^= 1;
561
562 output->next = output->dumb[output->current_image];
563 pixman_renderer_output_set_buffer(&output->base,
564 output->image[output->current_image]);
565
566 ec->renderer->repaint_output(&output->base, &total_damage);
567
568 pixman_region32_fini(&total_damage);
569 pixman_region32_fini(&previous_damage);
570}
571
572static void
573drm_output_render(struct drm_output *output, pixman_region32_t *damage)
574{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300575 struct weston_compositor *c = output->base.compositor;
576 struct drm_backend *b = (struct drm_backend *)c->backend;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200577
Giulio Camuffo954f1832014-10-11 18:27:30 +0300578 if (b->use_pixman)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200579 drm_output_render_pixman(output, damage);
580 else
581 drm_output_render_gl(output, damage);
582
Giulio Camuffo954f1832014-10-11 18:27:30 +0300583 pixman_region32_subtract(&c->primary_plane.damage,
584 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200585}
586
587static void
Richard Hughese7299962013-05-01 21:52:12 +0100588drm_output_set_gamma(struct weston_output *output_base,
589 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
590{
591 int rc;
592 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300593 struct drm_backend *backend =
594 (struct drm_backend *) output->base.compositor->backend;
Richard Hughese7299962013-05-01 21:52:12 +0100595
596 /* check */
597 if (output_base->gamma_size != size)
598 return;
599 if (!output->original_crtc)
600 return;
601
Giulio Camuffo954f1832014-10-11 18:27:30 +0300602 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +0100603 output->crtc_id,
604 size, r, g, b);
605 if (rc)
606 weston_log("set gamma failed: %m\n");
607}
608
Bryce Harringtonada4f072015-06-30 13:25:46 -0700609/* Determine the type of vblank synchronization to use for the output.
610 *
611 * The pipe parameter indicates which CRTC is in use. Knowing this, we
612 * can determine which vblank sequence type to use for it. Traditional
613 * cards had only two CRTCs, with CRTC 0 using no special flags, and
614 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
615 * parameter indicates this.
616 *
617 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
618 * 0-31. If this is non-zero it indicates we're dealing with a
619 * multi-gpu situation and we need to calculate the vblank sync
620 * using DRM_BLANK_HIGH_CRTC_MASK.
621 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +0300622static unsigned int
623drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200624{
625 if (output->pipe > 1)
626 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
627 DRM_VBLANK_HIGH_CRTC_MASK;
628 else if (output->pipe > 0)
629 return DRM_VBLANK_SECONDARY;
630 else
631 return 0;
632}
633
David Herrmann1edf44c2013-10-22 17:11:26 +0200634static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500635drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400636 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100637{
638 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300639 struct drm_backend *backend =
640 (struct drm_backend *)output->base.compositor->backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400642 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100644
Xiong Zhangabd5d472013-10-11 14:43:07 +0800645 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200646 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800647
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300648 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400649 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300650 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200651 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100652
Hardeningff39efa2013-09-18 23:56:35 +0200653 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200654 if (!output->current ||
655 output->current->stride != output->next->stride) {
Giulio Camuffo954f1832014-10-11 18:27:30 +0300656 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300657 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400658 &output->connector_id, 1,
659 &mode->mode_info);
660 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200661 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200662 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400663 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300664 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200665 }
666
Giulio Camuffo954f1832014-10-11 18:27:30 +0300667 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300668 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500669 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200670 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200671 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500672 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100673
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300674 output->page_flip_pending = 1;
675
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400676 drm_output_set_cursor(output);
677
Jesse Barnes58ef3792012-02-23 09:45:49 -0500678 /*
679 * Now, update all the sprite surfaces
680 */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300681 wl_list_for_each(s, &backend->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200682 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500683 drmVBlank vbl = {
684 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
685 .request.sequence = 1,
686 };
687
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200688 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200689 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500690 continue;
691
Giulio Camuffo954f1832014-10-11 18:27:30 +0300692 if (s->next && !backend->sprites_hidden)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200693 fb_id = s->next->fb_id;
694
Giulio Camuffo954f1832014-10-11 18:27:30 +0300695 ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200696 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500697 s->dest_x, s->dest_y,
698 s->dest_w, s->dest_h,
699 s->src_x, s->src_y,
700 s->src_w, s->src_h);
701 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200702 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500703 ret, strerror(errno));
704
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200705 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -0500706
Jesse Barnes58ef3792012-02-23 09:45:49 -0500707 /*
708 * Queue a vblank signal so we know when the surface
709 * becomes active on the display or has been replaced.
710 */
711 vbl.request.signal = (unsigned long)s;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300712 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500713 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200714 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500715 ret, strerror(errno));
716 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300717
718 s->output = output;
719 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500720 }
721
David Herrmann1edf44c2013-10-22 17:11:26 +0200722 return 0;
723
724err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800725 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200726 if (output->next) {
727 drm_output_release_fb(output, output->next);
728 output->next = NULL;
729 }
730
731 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400732}
733
734static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200735drm_output_start_repaint_loop(struct weston_output *output_base)
736{
737 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300738 struct drm_backend *backend = (struct drm_backend *)
739 output_base->compositor->backend;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200740 uint32_t fb_id;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200741 struct timespec ts, tnow;
742 struct timespec vbl2now;
743 int64_t refresh_nsec;
744 int ret;
745 drmVBlank vbl = {
746 .request.type = DRM_VBLANK_RELATIVE,
747 .request.sequence = 0,
748 .request.signal = 0,
749 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300750
Xiong Zhangabd5d472013-10-11 14:43:07 +0800751 if (output->destroy_pending)
752 return;
753
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300754 if (!output->current) {
755 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200756 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300757 }
758
Mario Kleinerf507ec32015-06-21 21:25:14 +0200759 /* Try to get current msc and timestamp via instant query */
760 vbl.request.type |= drm_waitvblank_pipe(output);
761 ret = drmWaitVBlank(backend->drm.fd, &vbl);
762
763 /* Error ret or zero timestamp means failure to get valid timestamp */
764 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
765 ts.tv_sec = vbl.reply.tval_sec;
766 ts.tv_nsec = vbl.reply.tval_usec * 1000;
767
768 /* Valid timestamp for most recent vblank - not stale?
769 * Stale ts could happen on Linux 3.17+, so make sure it
770 * is not older than 1 refresh duration since now.
771 */
772 weston_compositor_read_presentation_clock(backend->compositor,
773 &tnow);
774 timespec_sub(&vbl2now, &tnow, &ts);
775 refresh_nsec =
776 millihz_to_nsec(output->base.current_mode->refresh);
777 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
778 drm_output_update_msc(output, vbl.reply.sequence);
779 weston_output_finish_frame(output_base, &ts,
780 PRESENTATION_FEEDBACK_INVALID);
781 return;
782 }
783 }
784
785 /* Immediate query didn't provide valid timestamp.
786 * Use pageflip fallback.
787 */
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300788 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200789
Giulio Camuffo954f1832014-10-11 18:27:30 +0300790 if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
Jonas Ådahle5a12252013-04-05 23:07:11 +0200791 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
792 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200793 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200794 }
David Herrmann3c688c52013-10-22 17:11:25 +0200795
796 return;
797
798finish_frame:
799 /* if we cannot page-flip, immediately finish frame */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300800 weston_compositor_read_presentation_clock(output_base->compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200801 weston_output_finish_frame(output_base, &ts,
802 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200803}
804
805static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400806drm_output_update_msc(struct drm_output *output, unsigned int seq)
807{
808 uint64_t msc_hi = output->base.msc >> 32;
809
810 if (seq < (output->base.msc & 0xffffffff))
811 msc_hi++;
812
813 output->base.msc = (msc_hi << 32) + seq;
814}
815
816static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
818 void *data)
819{
820 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300821 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400822 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200823 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
824 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300825
Pekka Paalanen641307c2014-09-23 22:08:47 -0400826 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300827 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500828
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200829 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200830 s->current = s->next;
831 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300832
833 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400834 ts.tv_sec = sec;
835 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200836 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300837 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500838}
839
840static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800841drm_output_destroy(struct weston_output *output_base);
842
843static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400844page_flip_handler(int fd, unsigned int frame,
845 unsigned int sec, unsigned int usec, void *data)
846{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200847 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400848 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200849 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
850 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
851 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400852
Pekka Paalanen641307c2014-09-23 22:08:47 -0400853 drm_output_update_msc(output, frame);
854
Jonas Ådahle5a12252013-04-05 23:07:11 +0200855 /* We don't set page_flip_pending on start_repaint_loop, in that case
856 * we just want to page flip to the current buffer to get an accurate
857 * timestamp */
858 if (output->page_flip_pending) {
859 drm_output_release_fb(output, output->current);
860 output->current = output->next;
861 output->next = NULL;
862 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300863
Jonas Ådahle5a12252013-04-05 23:07:11 +0200864 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400865
Xiong Zhangabd5d472013-10-11 14:43:07 +0800866 if (output->destroy_pending)
867 drm_output_destroy(&output->base);
868 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400869 ts.tv_sec = sec;
870 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200871 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300872
873 /* We can't call this from frame_notify, because the output's
874 * repaint needed flag is cleared just after that */
875 if (output->recorder)
876 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300877 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200878}
879
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500880static uint32_t
881drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500882 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500883{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500884 uint32_t i, format;
885
886 format = gbm_bo_get_format(bo);
887
888 if (format == GBM_FORMAT_ARGB8888) {
889 pixman_region32_t r;
890
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500891 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600892 ev->surface->width,
893 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500894 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500895
896 if (!pixman_region32_not_empty(&r))
897 format = GBM_FORMAT_XRGB8888;
898
899 pixman_region32_fini(&r);
900 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500901
902 for (i = 0; i < s->count_formats; i++)
903 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500904 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500905
906 return 0;
907}
908
909static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500910drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500911{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500912 return !ev->transform.enabled ||
913 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500914}
915
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400916static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200917drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500918 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500919{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200920 struct weston_compositor *ec = output->base.compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300921 struct drm_backend *b = (struct drm_backend *)ec->backend;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200922 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500923 struct drm_sprite *s;
924 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500926 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200927 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500928 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400929 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500930
Giulio Camuffo954f1832014-10-11 18:27:30 +0300931 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200932 return NULL;
933
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200934 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200935 return NULL;
936
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200937 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200938 return NULL;
939
Giulio Camuffo954f1832014-10-11 18:27:30 +0300940 if (b->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400941 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500942
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200943 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400944 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300945
Jason Ekstranda7af7042013-10-12 22:38:11 -0500946 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400947 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500948
Jason Ekstranda7af7042013-10-12 22:38:11 -0500949 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200950 return NULL;
951
Jason Ekstranda7af7042013-10-12 22:38:11 -0500952 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500953 return NULL;
954
Jason Ekstranda7af7042013-10-12 22:38:11 -0500955 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400956 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500957
Giulio Camuffo954f1832014-10-11 18:27:30 +0300958 wl_list_for_each(s, &b->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200959 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500960 continue;
961
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200962 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500963 found = 1;
964 break;
965 }
966 }
967
968 /* No sprites available */
969 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400970 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500971
Giulio Camuffo954f1832014-10-11 18:27:30 +0300972 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500973 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700974 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400975 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400976 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400977
Jason Ekstranda7af7042013-10-12 22:38:11 -0500978 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500979 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200980 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400981 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500982 }
983
Giulio Camuffo954f1832014-10-11 18:27:30 +0300984 s->next = drm_fb_get_from_bo(bo, b, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200985 if (!s->next) {
986 gbm_bo_destroy(bo);
987 return NULL;
988 }
989
Jason Ekstranda7af7042013-10-12 22:38:11 -0500990 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500991
Jason Ekstranda7af7042013-10-12 22:38:11 -0500992 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400993 s->plane.x = box->x1;
994 s->plane.y = box->y1;
995
Jesse Barnes58ef3792012-02-23 09:45:49 -0500996 /*
997 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500998 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500999 * for us already).
1000 */
1001 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001002 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001003 &output->base.region);
1004 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001005 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001006 tbox = weston_transformed_rect(output->base.width,
1007 output->base.height,
1008 output->base.transform,
1009 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001010 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001011 s->dest_x = tbox.x1;
1012 s->dest_y = tbox.y1;
1013 s->dest_w = tbox.x2 - tbox.x1;
1014 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001015 pixman_region32_fini(&dest_rect);
1016
1017 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001018 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001019 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001020 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001021
Jason Ekstranda7af7042013-10-12 22:38:11 -05001022 weston_view_from_global_fixed(ev,
1023 wl_fixed_from_int(box->x1),
1024 wl_fixed_from_int(box->y1),
1025 &sx1, &sy1);
1026 weston_view_from_global_fixed(ev,
1027 wl_fixed_from_int(box->x2),
1028 wl_fixed_from_int(box->y2),
1029 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001030
1031 if (sx1 < 0)
1032 sx1 = 0;
1033 if (sy1 < 0)
1034 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001035 if (sx2 > wl_fixed_from_int(ev->surface->width))
1036 sx2 = wl_fixed_from_int(ev->surface->width);
1037 if (sy2 > wl_fixed_from_int(ev->surface->height))
1038 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001039
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001040 tbox.x1 = sx1;
1041 tbox.y1 = sy1;
1042 tbox.x2 = sx2;
1043 tbox.y2 = sy2;
1044
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001045 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
1046 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001047 viewport->buffer.transform,
1048 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01001049 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001050
1051 s->src_x = tbox.x1 << 8;
1052 s->src_y = tbox.y1 << 8;
1053 s->src_w = (tbox.x2 - tbox.x1) << 8;
1054 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001055 pixman_region32_fini(&src_rect);
1056
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001057 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001058}
1059
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001060static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001061drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001062 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001063{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001064 struct drm_backend *b =
1065 (struct drm_backend *)output->base.compositor->backend;
Neil Robertsf37f82c2014-05-01 18:00:41 +01001066 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001067
Giulio Camuffo954f1832014-10-11 18:27:30 +03001068 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001069 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +02001070 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1071 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001072 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001073 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001074 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001075 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001076 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001077 return NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001078 if (b->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001079 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001080 if (ev->geometry.scissor_enabled)
1081 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001082 if (ev->surface->buffer_ref.buffer == NULL ||
1083 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Daniel Stone70d337d2015-06-16 18:42:23 +01001084 ev->surface->width > b->cursor_width ||
1085 ev->surface->height > b->cursor_height)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001086 return NULL;
1087
Jason Ekstranda7af7042013-10-12 22:38:11 -05001088 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001089
1090 return &output->cursor_plane;
1091}
1092
Pekka Paalanend0ead482014-06-16 12:05:40 +03001093/**
1094 * Update the image for the current cursor surface
1095 *
1096 * @param b DRM backend structure
1097 * @param bo GBM buffer object to write into
1098 * @param ev View to use for cursor image
1099 */
1100static void
1101cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
1102 struct weston_view *ev)
1103{
1104 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
1105 uint32_t buf[b->cursor_width * b->cursor_height];
1106 int32_t stride;
1107 uint8_t *s;
1108 int i;
1109
1110 assert(buffer && buffer->shm_buffer);
1111 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
1112 assert(ev->surface->width <= b->cursor_width);
1113 assert(ev->surface->height <= b->cursor_height);
1114
1115 memset(buf, 0, sizeof buf);
1116 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1117 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1118
1119 wl_shm_buffer_begin_access(buffer->shm_buffer);
1120 for (i = 0; i < ev->surface->height; i++)
1121 memcpy(buf + i * b->cursor_width,
1122 s + i * stride,
1123 ev->surface->width * 4);
1124 wl_shm_buffer_end_access(buffer->shm_buffer);
1125
1126 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
1127 weston_log("failed update cursor: %m\n");
1128}
1129
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001130static void
1131drm_output_set_cursor(struct drm_output *output)
1132{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001133 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001134 struct weston_buffer *buffer;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001135 struct drm_backend *b =
1136 (struct drm_backend *) output->base.compositor->backend;
Pekka Paalanend0ead482014-06-16 12:05:40 +03001137 EGLint handle;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001138 struct gbm_bo *bo;
Pekka Paalanend0ead482014-06-16 12:05:40 +03001139 int x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001140
Jason Ekstranda7af7042013-10-12 22:38:11 -05001141 output->cursor_view = NULL;
1142 if (ev == NULL) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001143 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001144 return;
1145 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001146
Neil Robertse5051712013-11-13 15:44:06 +00001147 buffer = ev->surface->buffer_ref.buffer;
1148
1149 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001150 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001151 pixman_region32_fini(&output->cursor_plane.damage);
1152 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001153 output->current_cursor ^= 1;
1154 bo = output->cursor_bo[output->current_cursor];
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001155
Pekka Paalanend0ead482014-06-16 12:05:40 +03001156 cursor_bo_update(b, bo, ev);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001157 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001158 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
1159 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001160 weston_log("failed to set cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001161 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001162 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001163 }
1164
Jason Ekstranda7af7042013-10-12 22:38:11 -05001165 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1166 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001167 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001168 if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001169 weston_log("failed to move cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001170 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001171 }
1172
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001173 output->cursor_plane.x = x;
1174 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001175 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001176}
1177
Jesse Barnes58ef3792012-02-23 09:45:49 -05001178static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001179drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001180{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001181 struct drm_backend *b =
1182 (struct drm_backend *)output_base->compositor->backend;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001183 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001184 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001185 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001186 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001187
1188 /*
1189 * Find a surface for each sprite in the output using some heuristics:
1190 * 1) size
1191 * 2) frequency of update
1192 * 3) opacity (though some hw might support alpha blending)
1193 * 4) clipping (this can be fixed with color keys)
1194 *
1195 * The idea is to save on blitting since this should save power.
1196 * If we can get a large video surface on the sprite for example,
1197 * the main display surface may not need to update at all, and
1198 * the client buffer can be used directly for the sprite surface
1199 * as we do for flipping full screen surfaces.
1200 */
1201 pixman_region32_init(&overlap);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001202 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001203
Giulio Camuffo954f1832014-10-11 18:27:30 +03001204 wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001205 struct weston_surface *es = ev->surface;
1206
1207 /* Test whether this buffer can ever go into a plane:
1208 * non-shm, or small enough to be a cursor.
1209 *
1210 * Also, keep a reference when using the pixman renderer.
1211 * That makes it possible to do a seamless switch to the GL
1212 * renderer and since the pixman renderer keeps a reference
1213 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001214 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001215 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001216 (es->buffer_ref.buffer &&
1217 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001218 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001219 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001220 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001221 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001222
Jesse Barnes58ef3792012-02-23 09:45:49 -05001223 pixman_region32_init(&surface_overlap);
1224 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001225 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001226
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001227 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001228 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001229 next_plane = primary;
1230 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001231 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001232 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001233 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001234 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001235 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001236 if (next_plane == NULL)
1237 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001238
Jason Ekstranda7af7042013-10-12 22:38:11 -05001239 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001240
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001241 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001242 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001243 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001244
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001245 if (next_plane == primary ||
1246 next_plane == &output->cursor_plane) {
1247 /* cursor plane involves a copy */
1248 ev->psf_flags = 0;
1249 } else {
1250 /* All other planes are a direct scanout of a
1251 * single client buffer.
1252 */
1253 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1254 }
1255
Jesse Barnes58ef3792012-02-23 09:45:49 -05001256 pixman_region32_fini(&surface_overlap);
1257 }
1258 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001259}
1260
Matt Roper361d2ad2011-08-29 13:52:23 -07001261static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001262drm_output_fini_pixman(struct drm_output *output);
1263
1264static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001265drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001266{
1267 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001268 struct drm_backend *b =
1269 (struct drm_backend *)output->base.compositor->backend;
Matt Roper361d2ad2011-08-29 13:52:23 -07001270 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001271
Xiong Zhangabd5d472013-10-11 14:43:07 +08001272 if (output->page_flip_pending) {
1273 output->destroy_pending = 1;
1274 weston_log("destroy output while page flip pending\n");
1275 return;
1276 }
1277
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001278 if (output->backlight)
1279 backlight_destroy(output->backlight);
1280
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001281 drmModeFreeProperty(output->dpms_prop);
1282
Matt Roper361d2ad2011-08-29 13:52:23 -07001283 /* Turn off hardware cursor */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001284 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001285
1286 /* Restore original CRTC state */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001287 drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001288 origcrtc->x, origcrtc->y,
1289 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001290 drmModeFreeCrtc(origcrtc);
1291
Giulio Camuffo954f1832014-10-11 18:27:30 +03001292 b->crtc_allocator &= ~(1 << output->crtc_id);
1293 b->connector_allocator &= ~(1 << output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001294
Giulio Camuffo954f1832014-10-11 18:27:30 +03001295 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001296 drm_output_fini_pixman(output);
1297 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001298 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001299 gbm_surface_destroy(output->surface);
1300 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001301
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001302 weston_plane_release(&output->fb_plane);
1303 weston_plane_release(&output->cursor_plane);
1304
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001305 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001306
Matt Roper361d2ad2011-08-29 13:52:23 -07001307 free(output);
1308}
1309
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001310/**
1311 * Find the closest-matching mode for a given target
1312 *
1313 * Given a target mode, find the most suitable mode amongst the output's
1314 * current mode list to use, preferring the current mode if possible, to
1315 * avoid an expensive mode switch.
1316 *
1317 * @param output DRM output
1318 * @param target_mode Mode to attempt to match
1319 * @returns Pointer to a mode from the output's mode list
1320 */
Alex Wub7b8bda2012-04-17 17:20:48 +08001321static struct drm_mode *
1322choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1323{
1324 struct drm_mode *tmp_mode = NULL, *mode;
1325
Hardeningff39efa2013-09-18 23:56:35 +02001326 if (output->base.current_mode->width == target_mode->width &&
1327 output->base.current_mode->height == target_mode->height &&
1328 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001329 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001330 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001331
1332 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1333 if (mode->mode_info.hdisplay == target_mode->width &&
1334 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001335 if (mode->base.refresh == target_mode->refresh ||
1336 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001337 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001338 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001339 tmp_mode = mode;
1340 }
1341 }
1342
1343 return tmp_mode;
1344}
1345
1346static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001347drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001348static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001349drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001350
1351static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001352drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1353{
1354 struct drm_output *output;
1355 struct drm_mode *drm_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001356 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08001357
1358 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001359 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001360 return -1;
1361 }
1362
1363 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001364 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001365 return -1;
1366 }
1367
Giulio Camuffo954f1832014-10-11 18:27:30 +03001368 b = (struct drm_backend *)output_base->compositor->backend;
Alex Wub7b8bda2012-04-17 17:20:48 +08001369 output = (struct drm_output *)output_base;
1370 drm_mode = choose_mode (output, mode);
1371
1372 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001373 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001374 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001375 }
1376
Hardeningff39efa2013-09-18 23:56:35 +02001377 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001378 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001379
Hardeningff39efa2013-09-18 23:56:35 +02001380 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001381
Hardeningff39efa2013-09-18 23:56:35 +02001382 output->base.current_mode = &drm_mode->base;
1383 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001384 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1385
Alex Wub7b8bda2012-04-17 17:20:48 +08001386 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001387 drm_output_release_fb(output, output->current);
1388 drm_output_release_fb(output, output->next);
1389 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001390
Giulio Camuffo954f1832014-10-11 18:27:30 +03001391 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001392 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001393 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001394 weston_log("failed to init output pixman state with "
1395 "new mode\n");
1396 return -1;
1397 }
1398 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001399 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001400 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001401
Giulio Camuffo954f1832014-10-11 18:27:30 +03001402 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001403 weston_log("failed to init output egl state with "
1404 "new mode");
1405 return -1;
1406 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001407 }
1408
Alex Wub7b8bda2012-04-17 17:20:48 +08001409 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001410}
1411
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001412static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001413on_drm_input(int fd, uint32_t mask, void *data)
1414{
1415 drmEventContext evctx;
1416
1417 memset(&evctx, 0, sizeof evctx);
1418 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1419 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001420 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001421 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001422
1423 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001424}
1425
1426static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001427init_drm(struct drm_backend *b, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001428{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001429 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001430 uint64_t cap;
1431 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001432 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001433
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001434 sysnum = udev_device_get_sysnum(device);
1435 if (sysnum)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001436 b->drm.id = atoi(sysnum);
1437 if (!sysnum || b->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001438 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001439 return -1;
1440 }
1441
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001442 filename = udev_device_get_devnode(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001443 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001444 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001445 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001446 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001447 udev_device_get_devnode(device));
1448 return -1;
1449 }
1450
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001451 weston_log("using %s\n", filename);
1452
Giulio Camuffo954f1832014-10-11 18:27:30 +03001453 b->drm.fd = fd;
1454 b->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001455
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001456 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1457 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001458 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001459 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001460 clk_id = CLOCK_REALTIME;
1461
Giulio Camuffo954f1832014-10-11 18:27:30 +03001462 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001463 weston_log("Error: failed to set presentation clock %d.\n",
1464 clk_id);
1465 return -1;
1466 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001467
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001468 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1469 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001470 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001471 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001472 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001473
1474 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1475 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001476 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001477 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001478 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001479
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001480 return 0;
1481}
1482
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001483static struct gbm_device *
1484create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001485{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001486 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001487
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001488 gl_renderer = weston_load_module("gl-renderer.so",
1489 "gl_renderer_interface");
1490 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001491 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001492
1493 /* GBM will load a dri driver, but even though they need symbols from
1494 * libglapi, in some version of Mesa they are not linked to it. Since
1495 * only the gl-renderer module links to it, the call above won't make
1496 * these symbols globally available, and loading the DRI driver fails.
1497 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1498 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1499
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001500 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001501
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001502 return gbm;
1503}
1504
Bryce Harringtonc056a982015-05-19 15:25:18 -07001505/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001506 * we may be able to susbstitute an ARGB format for an XRGB one.
1507 *
1508 * This returns 0 if substitution isn't possible, but 0 might be a
1509 * legitimate format for other EGL platforms, so the caller is
1510 * responsible for checking for 0 before calling gl_renderer->create().
1511 *
1512 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1513 * but it's entirely possible we'll see this again on other implementations.
1514 */
1515static int
1516fallback_format_for(uint32_t format)
1517{
1518 switch (format) {
1519 case GBM_FORMAT_XRGB8888:
1520 return GBM_FORMAT_ARGB8888;
1521 case GBM_FORMAT_XRGB2101010:
1522 return GBM_FORMAT_ARGB2101010;
1523 default:
1524 return 0;
1525 }
1526}
1527
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001528static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001529drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001530{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001531 EGLint format[2] = {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001532 b->format,
1533 fallback_format_for(b->format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05001534 };
1535 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001536
Derek Foremanc4cfe852015-05-15 12:12:40 -05001537 if (format[1])
1538 n_formats = 2;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001539 if (gl_renderer->create(b->compositor,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001540 EGL_PLATFORM_GBM_KHR,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001541 (void *)b->gbm,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001542 gl_renderer->opaque_attribs,
1543 format,
1544 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001545 return -1;
1546 }
1547
1548 return 0;
1549}
1550
1551static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001552init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001553{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001554 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001555
Giulio Camuffo954f1832014-10-11 18:27:30 +03001556 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001557 return -1;
1558
Giulio Camuffo954f1832014-10-11 18:27:30 +03001559 if (drm_backend_create_gl_renderer(b) < 0) {
1560 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001561 return -1;
1562 }
1563
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001564 return 0;
1565}
1566
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001567static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001568init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001569{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001570 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001571}
1572
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001573/**
1574 * Add a mode to output's mode list
1575 *
1576 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
1577 * output's mode list.
1578 *
1579 * @param output DRM output to add mode to
1580 * @param info DRM mode structure to add
1581 * @returns Newly-allocated Weston/DRM mode structure
1582 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001583static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001584drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001585{
1586 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001587 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001588
1589 mode = malloc(sizeof *mode);
1590 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001591 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001592
1593 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001594 mode->base.width = info->hdisplay;
1595 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001596
1597 /* Calculate higher precision (mHz) refresh rate */
1598 refresh = (info->clock * 1000000LL / info->htotal +
1599 info->vtotal / 2) / info->vtotal;
1600
1601 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1602 refresh *= 2;
1603 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1604 refresh /= 2;
1605 if (info->vscan > 1)
1606 refresh /= info->vscan;
1607
1608 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001609 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001610
1611 if (info->type & DRM_MODE_TYPE_PREFERRED)
1612 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1613
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001614 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1615
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001616 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001617}
1618
1619static int
1620drm_subpixel_to_wayland(int drm_value)
1621{
1622 switch (drm_value) {
1623 default:
1624 case DRM_MODE_SUBPIXEL_UNKNOWN:
1625 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1626 case DRM_MODE_SUBPIXEL_NONE:
1627 return WL_OUTPUT_SUBPIXEL_NONE;
1628 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1629 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1630 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1631 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1632 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1633 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1634 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1635 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1636 }
1637}
1638
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001639/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001640static uint32_t
1641drm_get_backlight(struct drm_output *output)
1642{
1643 long brightness, max_brightness, norm;
1644
1645 brightness = backlight_get_brightness(output->backlight);
1646 max_brightness = backlight_get_max_brightness(output->backlight);
1647
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001648 /* convert it on a scale of 0 to 255 */
1649 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001650
1651 return (uint32_t) norm;
1652}
1653
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001654/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001655static void
1656drm_set_backlight(struct weston_output *output_base, uint32_t value)
1657{
1658 struct drm_output *output = (struct drm_output *) output_base;
1659 long max_brightness, new_brightness;
1660
1661 if (!output->backlight)
1662 return;
1663
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001664 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001665 return;
1666
1667 max_brightness = backlight_get_max_brightness(output->backlight);
1668
1669 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001670 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001671
1672 backlight_set_brightness(output->backlight, new_brightness);
1673}
1674
1675static drmModePropertyPtr
1676drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1677{
1678 drmModePropertyPtr props;
1679 int i;
1680
1681 for (i = 0; i < connector->count_props; i++) {
1682 props = drmModeGetProperty(fd, connector->props[i]);
1683 if (!props)
1684 continue;
1685
1686 if (!strcmp(props->name, name))
1687 return props;
1688
1689 drmModeFreeProperty(props);
1690 }
1691
1692 return NULL;
1693}
1694
1695static void
1696drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1697{
1698 struct drm_output *output = (struct drm_output *) output_base;
1699 struct weston_compositor *ec = output_base->compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001700 struct drm_backend *b = (struct drm_backend *)ec->backend;
Daniel Stone36609c72015-06-18 07:49:02 +01001701 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001702
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001703 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001704 return;
1705
Daniel Stone36609c72015-06-18 07:49:02 +01001706 ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
1707 output->dpms_prop->prop_id, level);
1708 if (ret) {
1709 weston_log("DRM: DPMS: failed property set for %s\n",
1710 output->base.name);
1711 return;
1712 }
1713
1714 output->dpms = level;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001715}
1716
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001717static const char * const connector_type_names[] = {
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001718 "None",
1719 "VGA",
1720 "DVI",
1721 "DVI",
1722 "DVI",
1723 "Composite",
1724 "TV",
1725 "LVDS",
1726 "CTV",
1727 "DIN",
1728 "DP",
1729 "HDMI",
1730 "HDMI",
1731 "TV",
1732 "eDP",
1733};
1734
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001735static char *
1736make_connector_name(const drmModeConnector *con)
1737{
1738 char name[32];
1739 const char *type_name;
1740
1741 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1742 type_name = connector_type_names[con->connector_type];
1743 else
1744 type_name = "UNKNOWN";
1745 snprintf(name, sizeof name, "%s%d", type_name, con->connector_type_id);
1746
1747 return strdup(name);
1748}
1749
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001750static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001751find_crtc_for_connector(struct drm_backend *b,
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001752 drmModeRes *resources, drmModeConnector *connector)
1753{
1754 drmModeEncoder *encoder;
1755 uint32_t possible_crtcs;
1756 int i, j;
1757
1758 for (j = 0; j < connector->count_encoders; j++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001759 encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001760 if (encoder == NULL) {
1761 weston_log("Failed to get encoder.\n");
1762 return -1;
1763 }
1764 possible_crtcs = encoder->possible_crtcs;
1765 drmModeFreeEncoder(encoder);
1766
1767 for (i = 0; i < resources->count_crtcs; i++) {
1768 if (possible_crtcs & (1 << i) &&
Giulio Camuffo954f1832014-10-11 18:27:30 +03001769 !(b->crtc_allocator & (1 << resources->crtcs[i])))
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001770 return i;
1771 }
1772 }
1773
1774 return -1;
1775}
1776
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001777/* Init output state that depends on gl or gbm */
1778static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001779drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001780{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001781 EGLint format[2] = {
1782 output->format,
1783 fallback_format_for(output->format),
1784 };
1785 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001786
Giulio Camuffo954f1832014-10-11 18:27:30 +03001787 output->surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001788 output->base.current_mode->width,
1789 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001790 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001791 GBM_BO_USE_SCANOUT |
1792 GBM_BO_USE_RENDERING);
1793 if (!output->surface) {
1794 weston_log("failed to create gbm surface\n");
1795 return -1;
1796 }
1797
Derek Foremanc4cfe852015-05-15 12:12:40 -05001798 if (format[1])
1799 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001800 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001801 (EGLNativeDisplayType)output->surface,
1802 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001803 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001804 format,
1805 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001806 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001807 gbm_surface_destroy(output->surface);
1808 return -1;
1809 }
1810
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001811 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001812
1813 for (i = 0; i < 2; i++) {
1814 if (output->cursor_bo[i])
1815 continue;
1816
1817 output->cursor_bo[i] =
Giulio Camuffo954f1832014-10-11 18:27:30 +03001818 gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001819 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001820 }
1821
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001822 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1823 weston_log("cursor buffers unavailable, using gl cursors\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001824 b->cursors_are_broken = 1;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001825 }
1826
1827 return 0;
1828}
1829
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001830static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001831drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001832{
Hardeningff39efa2013-09-18 23:56:35 +02001833 int w = output->base.current_mode->width;
1834 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001835 unsigned int i;
1836
1837 /* FIXME error checking */
1838
1839 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001840 output->dumb[i] = drm_fb_create_dumb(b, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001841 if (!output->dumb[i])
1842 goto err;
1843
1844 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001845 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001846 output->dumb[i]->map,
1847 output->dumb[i]->stride);
1848 if (!output->image[i])
1849 goto err;
1850 }
1851
1852 if (pixman_renderer_output_create(&output->base) < 0)
1853 goto err;
1854
1855 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001856 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001857
1858 return 0;
1859
1860err:
1861 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1862 if (output->dumb[i])
1863 drm_fb_destroy_dumb(output->dumb[i]);
1864 if (output->image[i])
1865 pixman_image_unref(output->image[i]);
1866
1867 output->dumb[i] = NULL;
1868 output->image[i] = NULL;
1869 }
1870
1871 return -1;
1872}
1873
1874static void
1875drm_output_fini_pixman(struct drm_output *output)
1876{
1877 unsigned int i;
1878
1879 pixman_renderer_output_destroy(&output->base);
1880 pixman_region32_fini(&output->previous_damage);
1881
1882 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1883 drm_fb_destroy_dumb(output->dumb[i]);
1884 pixman_image_unref(output->image[i]);
1885 output->dumb[i] = NULL;
1886 output->image[i] = NULL;
1887 }
1888}
1889
Richard Hughes2b2092a2013-04-24 14:58:02 +01001890static void
1891edid_parse_string(const uint8_t *data, char text[])
1892{
1893 int i;
1894 int replaced = 0;
1895
1896 /* this is always 12 bytes, but we can't guarantee it's null
1897 * terminated or not junk. */
1898 strncpy(text, (const char *) data, 12);
1899
1900 /* remove insane chars */
1901 for (i = 0; text[i] != '\0'; i++) {
1902 if (text[i] == '\n' ||
1903 text[i] == '\r') {
1904 text[i] = '\0';
1905 break;
1906 }
1907 }
1908
1909 /* ensure string is printable */
1910 for (i = 0; text[i] != '\0'; i++) {
1911 if (!isprint(text[i])) {
1912 text[i] = '-';
1913 replaced++;
1914 }
1915 }
1916
1917 /* if the string is random junk, ignore the string */
1918 if (replaced > 4)
1919 text[0] = '\0';
1920}
1921
1922#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1923#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1924#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1925#define EDID_OFFSET_DATA_BLOCKS 0x36
1926#define EDID_OFFSET_LAST_BLOCK 0x6c
1927#define EDID_OFFSET_PNPID 0x08
1928#define EDID_OFFSET_SERIAL 0x0c
1929
1930static int
1931edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1932{
1933 int i;
1934 uint32_t serial_number;
1935
1936 /* check header */
1937 if (length < 128)
1938 return -1;
1939 if (data[0] != 0x00 || data[1] != 0xff)
1940 return -1;
1941
1942 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1943 * /--08--\/--09--\
1944 * 7654321076543210
1945 * |\---/\---/\---/
1946 * R C1 C2 C3 */
1947 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1948 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1949 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1950 edid->pnp_id[3] = '\0';
1951
1952 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1953 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1954 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1955 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1956 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1957 if (serial_number > 0)
1958 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1959
1960 /* parse EDID data */
1961 for (i = EDID_OFFSET_DATA_BLOCKS;
1962 i <= EDID_OFFSET_LAST_BLOCK;
1963 i += 18) {
1964 /* ignore pixel clock data */
1965 if (data[i] != 0)
1966 continue;
1967 if (data[i+2] != 0)
1968 continue;
1969
1970 /* any useful blocks? */
1971 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1972 edid_parse_string(&data[i+5],
1973 edid->monitor_name);
1974 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1975 edid_parse_string(&data[i+5],
1976 edid->serial_number);
1977 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1978 edid_parse_string(&data[i+5],
1979 edid->eisa_id);
1980 }
1981 }
1982 return 0;
1983}
1984
1985static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001986find_and_parse_output_edid(struct drm_backend *b,
Richard Hughes2b2092a2013-04-24 14:58:02 +01001987 struct drm_output *output,
1988 drmModeConnector *connector)
1989{
1990 drmModePropertyBlobPtr edid_blob = NULL;
1991 drmModePropertyPtr property;
1992 int i;
1993 int rc;
1994
1995 for (i = 0; i < connector->count_props && !edid_blob; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001996 property = drmModeGetProperty(b->drm.fd, connector->props[i]);
Richard Hughes2b2092a2013-04-24 14:58:02 +01001997 if (!property)
1998 continue;
1999 if ((property->flags & DRM_MODE_PROP_BLOB) &&
2000 !strcmp(property->name, "EDID")) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002001 edid_blob = drmModeGetPropertyBlob(b->drm.fd,
Richard Hughes2b2092a2013-04-24 14:58:02 +01002002 connector->prop_values[i]);
2003 }
2004 drmModeFreeProperty(property);
2005 }
2006 if (!edid_blob)
2007 return;
2008
2009 rc = edid_parse(&output->edid,
2010 edid_blob->data,
2011 edid_blob->length);
2012 if (!rc) {
2013 weston_log("EDID data '%s', '%s', '%s'\n",
2014 output->edid.pnp_id,
2015 output->edid.monitor_name,
2016 output->edid.serial_number);
2017 if (output->edid.pnp_id[0] != '\0')
2018 output->base.make = output->edid.pnp_id;
2019 if (output->edid.monitor_name[0] != '\0')
2020 output->base.model = output->edid.monitor_name;
2021 if (output->edid.serial_number[0] != '\0')
2022 output->base.serial_number = output->edid.serial_number;
2023 }
2024 drmModeFreePropertyBlob(edid_blob);
2025}
2026
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002027
2028
2029static int
2030parse_modeline(const char *s, drmModeModeInfo *mode)
2031{
2032 char hsync[16];
2033 char vsync[16];
2034 float fclock;
2035
2036 mode->type = DRM_MODE_TYPE_USERDEF;
2037 mode->hskew = 0;
2038 mode->vscan = 0;
2039 mode->vrefresh = 0;
2040 mode->flags = 0;
2041
Rob Bradford307e09e2013-07-26 16:29:40 +01002042 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002043 &fclock,
2044 &mode->hdisplay,
2045 &mode->hsync_start,
2046 &mode->hsync_end,
2047 &mode->htotal,
2048 &mode->vdisplay,
2049 &mode->vsync_start,
2050 &mode->vsync_end,
2051 &mode->vtotal, hsync, vsync) != 11)
2052 return -1;
2053
2054 mode->clock = fclock * 1000;
2055 if (strcmp(hsync, "+hsync") == 0)
2056 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2057 else if (strcmp(hsync, "-hsync") == 0)
2058 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2059 else
2060 return -1;
2061
2062 if (strcmp(vsync, "+vsync") == 0)
2063 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2064 else if (strcmp(vsync, "-vsync") == 0)
2065 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2066 else
2067 return -1;
2068
2069 return 0;
2070}
2071
Rob Bradford66bd9f52013-06-25 18:56:42 +01002072static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002073setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01002074 struct weston_output *output,
2075 const char *s)
2076{
2077 if (strcmp(s, "") != 0) {
2078 struct udev_seat *seat;
2079
Giulio Camuffo954f1832014-10-11 18:27:30 +03002080 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05002081 if (!seat)
2082 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01002083
Derek Foreman0720ea32015-07-15 13:00:35 -05002084 seat->base.output = output;
2085
2086 if (seat->base.pointer)
Rob Bradford66bd9f52013-06-25 18:56:42 +01002087 weston_pointer_clamp(seat->base.pointer,
2088 &seat->base.pointer->x,
2089 &seat->base.pointer->y);
2090 }
2091}
2092
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002093static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002094get_gbm_format_from_section(struct weston_config_section *section,
2095 uint32_t default_value,
2096 uint32_t *format)
2097{
2098 char *s;
2099 int ret = 0;
2100
2101 weston_config_section_get_string(section,
2102 "gbm-format", &s, NULL);
2103
2104 if (s == NULL)
2105 *format = default_value;
2106 else if (strcmp(s, "xrgb8888") == 0)
2107 *format = GBM_FORMAT_XRGB8888;
2108 else if (strcmp(s, "rgb565") == 0)
2109 *format = GBM_FORMAT_RGB565;
2110 else if (strcmp(s, "xrgb2101010") == 0)
2111 *format = GBM_FORMAT_XRGB2101010;
2112 else {
2113 weston_log("fatal: unrecognized pixel format: %s\n", s);
2114 ret = -1;
2115 }
2116
2117 free(s);
2118
2119 return ret;
2120}
2121
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002122/**
2123 * Choose suitable mode for an output
2124 *
2125 * Find the most suitable mode to use for initial setup (or reconfiguration on
2126 * hotplug etc) for a DRM output.
2127 *
2128 * @param output DRM output to choose mode for
2129 * @param kind Strategy and preference to use when choosing mode
2130 * @param width Desired width for this output
2131 * @param height Desired height for this output
2132 * @param current_mode Mode currently being displayed on this output
2133 * @param modeline Manually-entered mode (may be NULL)
2134 * @returns A mode from the output's mode list, or NULL if none available
2135 */
2136static struct drm_mode *
2137drm_output_choose_initial_mode(struct drm_output *output,
2138 enum output_config kind,
2139 int width, int height,
2140 const drmModeModeInfo *current_mode,
2141 const drmModeModeInfo *modeline)
2142{
2143 struct drm_mode *preferred = NULL;
2144 struct drm_mode *current = NULL;
2145 struct drm_mode *configured = NULL;
2146 struct drm_mode *best = NULL;
2147 struct drm_mode *drm_mode;
2148
2149 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
2150 if (kind == OUTPUT_CONFIG_MODE &&
2151 width == drm_mode->base.width &&
2152 height == drm_mode->base.height)
2153 configured = drm_mode;
2154
2155 if (memcmp(&current_mode, &drm_mode->mode_info,
2156 sizeof *current_mode) == 0)
2157 current = drm_mode;
2158
2159 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
2160 preferred = drm_mode;
2161
2162 best = drm_mode;
2163 }
2164
2165 if (kind == OUTPUT_CONFIG_MODELINE) {
2166 configured = drm_output_add_mode(output, modeline);
2167 if (!configured)
2168 return NULL;
2169 }
2170
2171 if (current == NULL && current_mode->clock != 0) {
2172 current = drm_output_add_mode(output, current_mode);
2173 if (!current)
2174 return NULL;
2175 }
2176
2177 if (kind == OUTPUT_CONFIG_CURRENT)
2178 configured = current;
2179
2180 if (option_current_mode && current)
2181 return current;
2182
2183 if (configured)
2184 return configured;
2185
2186 if (preferred)
2187 return preferred;
2188
2189 if (current)
2190 return current;
2191
2192 if (best)
2193 return best;
2194
2195 weston_log("no available modes for %s\n", output->base.name);
2196 return NULL;
2197}
2198
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002199static int
2200connector_get_current_mode(drmModeConnector *connector, int drm_fd,
2201 drmModeModeInfo *mode)
2202{
2203 drmModeEncoder *encoder;
2204 drmModeCrtc *crtc;
2205
2206 /* Get the current mode on the crtc that's currently driving
2207 * this connector. */
2208 encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
2209 memset(mode, 0, sizeof *mode);
2210 if (encoder != NULL) {
2211 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
2212 drmModeFreeEncoder(encoder);
2213 if (crtc == NULL)
2214 return -1;
2215 if (crtc->mode_valid)
2216 *mode = crtc->mode;
2217 drmModeFreeCrtc(crtc);
2218 }
2219
2220 return 0;
2221}
2222
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002223/**
2224 * Create and configure a Weston output structure
2225 *
2226 * Given a DRM connector, create a matching drm_output structure and add it
2227 * to Weston's output list.
2228 *
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002229 * @param b Weston backend structure structure
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002230 * @param resources DRM resources for this device
2231 * @param connector DRM connector to use for this new output
2232 * @param x Horizontal offset to use into global co-ordinate space
2233 * @param y Vertical offset to use into global co-ordinate space
2234 * @param drm_device udev device pointer
2235 * @returns 0 on success, or -1 on failure
2236 */
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002237static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002238create_output_for_connector(struct drm_backend *b,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002239 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002240 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002241 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002242{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002243 struct drm_output *output;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002244 struct drm_mode *drm_mode, *next, *current;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002245 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002246 struct weston_config_section *section;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002247 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002248 int i, width, height, scale;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002249 char *s;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002250 enum output_config config;
2251 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002252
Giulio Camuffo954f1832014-10-11 18:27:30 +03002253 i = find_crtc_for_connector(b, resources, connector);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002254 if (i < 0) {
2255 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002256 return -1;
2257 }
2258
Peter Huttererf3d62272013-08-08 11:57:05 +10002259 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002260 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002261 return -1;
2262
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002263 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002264 output->base.name = make_connector_name(connector);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002265 output->base.make = "unknown";
2266 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002267 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002268 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002269
Giulio Camuffo954f1832014-10-11 18:27:30 +03002270 section = weston_config_get_section(b->compositor->config, "output", "name",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002271 output->base.name);
2272 weston_config_section_get_string(section, "mode", &s, "preferred");
2273 if (strcmp(s, "off") == 0)
2274 config = OUTPUT_CONFIG_OFF;
2275 else if (strcmp(s, "preferred") == 0)
2276 config = OUTPUT_CONFIG_PREFERRED;
2277 else if (strcmp(s, "current") == 0)
2278 config = OUTPUT_CONFIG_CURRENT;
2279 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2280 config = OUTPUT_CONFIG_MODE;
2281 else if (parse_modeline(s, &modeline) == 0)
2282 config = OUTPUT_CONFIG_MODELINE;
2283 else {
2284 weston_log("Invalid mode \"%s\" for output %s\n",
2285 s, output->base.name);
2286 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002287 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002288 free(s);
2289
2290 weston_config_section_get_int(section, "scale", &scale, 1);
2291 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002292 if (weston_parse_transform(s, &transform) < 0)
2293 weston_log("Invalid transform \"%s\" for output %s\n",
2294 s, output->base.name);
2295
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002296 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002297
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002298 if (get_gbm_format_from_section(section,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002299 b->format,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002300 &output->format) == -1)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002301 output->format = b->format;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002302
Rob Bradford66bd9f52013-06-25 18:56:42 +01002303 weston_config_section_get_string(section, "seat", &s, "");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002304 setup_output_seat_constraint(b, &output->base, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002305 free(s);
2306
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002307 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002308 output->pipe = i;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002309 b->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002310 output->connector_id = connector->connector_id;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002311 b->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002312
Giulio Camuffo954f1832014-10-11 18:27:30 +03002313 output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
2314 output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002315
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002316 if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
2317 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002318
David Herrmann0f0d54e2011-12-08 17:05:45 +01002319 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002320 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002321 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002322 goto err_free;
2323 }
2324
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002325 if (config == OUTPUT_CONFIG_OFF) {
2326 weston_log("Disabling output %s\n", output->base.name);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002327 drmModeSetCrtc(b->drm.fd, output->crtc_id,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002328 0, 0, 0, 0, 0, NULL);
2329 goto err_free;
2330 }
2331
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002332 current = drm_output_choose_initial_mode(output, config,
2333 width, height,
2334 &crtc_mode, &modeline);
2335 if (!current)
Wang Quanxianacb805a2012-07-30 18:09:46 -04002336 goto err_free;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002337 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02002338 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002339
Giulio Camuffo954f1832014-10-11 18:27:30 +03002340 weston_output_init(&output->base, b->compositor, x, y,
John Kåre Alsaker94659272012-11-13 19:10:18 +01002341 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002342 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002343
Giulio Camuffo954f1832014-10-11 18:27:30 +03002344 if (b->use_pixman) {
2345 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002346 weston_log("Failed to init output pixman state\n");
2347 goto err_output;
2348 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03002349 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002350 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002351 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002352 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002353
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002354 output->backlight = backlight_init(drm_device,
2355 connector->connector_type);
2356 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002357 weston_log("Initialized backlight, device %s\n",
2358 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002359 output->base.set_backlight = drm_set_backlight;
2360 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002361 } else {
2362 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002363 }
2364
Giulio Camuffo954f1832014-10-11 18:27:30 +03002365 weston_compositor_add_output(b->compositor, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002366
Giulio Camuffo954f1832014-10-11 18:27:30 +03002367 find_and_parse_output_edid(b, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002368 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2369 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002370
Jonas Ådahle5a12252013-04-05 23:07:11 +02002371 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002372 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002373 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002374 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002375 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002376 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002377
Richard Hughese7299962013-05-01 21:52:12 +01002378 output->base.gamma_size = output->original_crtc->gamma_size;
2379 output->base.set_gamma = drm_output_set_gamma;
2380
Giulio Camuffo954f1832014-10-11 18:27:30 +03002381 weston_plane_init(&output->cursor_plane, b->compositor, 0, 0);
2382 weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002383
Giulio Camuffo954f1832014-10-11 18:27:30 +03002384 weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
2385 weston_compositor_stack_plane(b->compositor, &output->fb_plane,
2386 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002387
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002388 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002389 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002390 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002391 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002392 m->width, m->height, m->refresh / 1000.0,
2393 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2394 ", preferred" : "",
2395 m->flags & WL_OUTPUT_MODE_CURRENT ?
2396 ", current" : "",
2397 connector->count_modes == 0 ?
2398 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002399
Mario Kleiner80817042015-06-21 21:25:11 +02002400 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2401 output->base.native_mode = output->base.current_mode;
2402 output->base.native_scale = output->base.current_scale;
2403
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002404 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002405
John Kåre Alsaker94659272012-11-13 19:10:18 +01002406err_output:
2407 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002408err_free:
2409 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2410 base.link) {
2411 wl_list_remove(&drm_mode->base.link);
2412 free(drm_mode);
2413 }
2414
2415 drmModeFreeCrtc(output->original_crtc);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002416 b->crtc_allocator &= ~(1 << output->crtc_id);
2417 b->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002418 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002419
David Herrmann0f0d54e2011-12-08 17:05:45 +01002420 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002421}
2422
Jesse Barnes58ef3792012-02-23 09:45:49 -05002423static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002424create_sprites(struct drm_backend *b)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002425{
2426 struct drm_sprite *sprite;
2427 drmModePlaneRes *plane_res;
2428 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002429 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002430
Giulio Camuffo954f1832014-10-11 18:27:30 +03002431 plane_res = drmModeGetPlaneResources(b->drm.fd);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002432 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002433 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002434 strerror(errno));
2435 return;
2436 }
2437
2438 for (i = 0; i < plane_res->count_planes; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002439 plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002440 if (!plane)
2441 continue;
2442
Peter Huttererf3d62272013-08-08 11:57:05 +10002443 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002444 plane->count_formats));
2445 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002446 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002447 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002448 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002449 continue;
2450 }
2451
Jesse Barnes58ef3792012-02-23 09:45:49 -05002452 sprite->possible_crtcs = plane->possible_crtcs;
2453 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002454 sprite->current = NULL;
2455 sprite->next = NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002456 sprite->backend = b;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002457 sprite->count_formats = plane->count_formats;
2458 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002459 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002460 drmModeFreePlane(plane);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002461 weston_plane_init(&sprite->plane, b->compositor, 0, 0);
2462 weston_compositor_stack_plane(b->compositor, &sprite->plane,
2463 &b->compositor->primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002464
Giulio Camuffo954f1832014-10-11 18:27:30 +03002465 wl_list_insert(&b->sprite_list, &sprite->link);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002466 }
2467
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002468 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002469}
2470
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002471static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002472destroy_sprites(struct drm_backend *backend)
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002473{
2474 struct drm_sprite *sprite, *next;
2475 struct drm_output *output;
2476
Giulio Camuffo954f1832014-10-11 18:27:30 +03002477 output = container_of(backend->compositor->output_list.next,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002478 struct drm_output, base.link);
2479
Giulio Camuffo954f1832014-10-11 18:27:30 +03002480 wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
2481 drmModeSetPlane(backend->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002482 sprite->plane_id,
2483 output->crtc_id, 0, 0,
2484 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002485 drm_output_release_fb(output, sprite->current);
2486 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002487 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002488 free(sprite);
2489 }
2490}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002491
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002492static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002493create_outputs(struct drm_backend *b, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002494 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002495{
2496 drmModeConnector *connector;
2497 drmModeRes *resources;
2498 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002499 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002500
Giulio Camuffo954f1832014-10-11 18:27:30 +03002501 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002502 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002503 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002504 return -1;
2505 }
2506
Giulio Camuffo954f1832014-10-11 18:27:30 +03002507 b->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
2508 if (!b->crtcs) {
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002509 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002510 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002511 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002512
Giulio Camuffo954f1832014-10-11 18:27:30 +03002513 b->min_width = resources->min_width;
2514 b->max_width = resources->max_width;
2515 b->min_height = resources->min_height;
2516 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002517
Giulio Camuffo954f1832014-10-11 18:27:30 +03002518 b->num_crtcs = resources->count_crtcs;
2519 memcpy(b->crtcs, resources->crtcs, sizeof(uint32_t) * b->num_crtcs);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002520
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002521 for (i = 0; i < resources->count_connectors; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002522 connector = drmModeGetConnector(b->drm.fd,
Benjamin Franzke117483d2011-08-30 11:38:26 +02002523 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002524 if (connector == NULL)
2525 continue;
2526
2527 if (connector->connection == DRM_MODE_CONNECTED &&
2528 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002529 connector->connector_id == option_connector)) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002530 if (create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002531 connector, x, y,
2532 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002533 drmModeFreeConnector(connector);
2534 continue;
2535 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002536
Giulio Camuffo954f1832014-10-11 18:27:30 +03002537 x += container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002538 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002539 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002540 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002541
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002542 drmModeFreeConnector(connector);
2543 }
2544
Giulio Camuffo954f1832014-10-11 18:27:30 +03002545 if (wl_list_empty(&b->compositor->output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002546 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002547 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002548 return -1;
2549 }
2550
2551 drmModeFreeResources(resources);
2552
2553 return 0;
2554}
2555
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002556static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002557update_outputs(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002558{
2559 drmModeConnector *connector;
2560 drmModeRes *resources;
2561 struct drm_output *output, *next;
2562 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002563 uint32_t connected = 0, disconnects = 0;
2564 int i;
2565
Giulio Camuffo954f1832014-10-11 18:27:30 +03002566 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002567 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002568 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002569 return;
2570 }
2571
2572 /* collect new connects */
2573 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002574 int connector_id = resources->connectors[i];
2575
Giulio Camuffo954f1832014-10-11 18:27:30 +03002576 connector = drmModeGetConnector(b->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002577 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002578 continue;
2579
David Herrmann7551cff2011-12-08 17:05:43 +01002580 if (connector->connection != DRM_MODE_CONNECTED) {
2581 drmModeFreeConnector(connector);
2582 continue;
2583 }
2584
Benjamin Franzke117483d2011-08-30 11:38:26 +02002585 connected |= (1 << connector_id);
2586
Giulio Camuffo954f1832014-10-11 18:27:30 +03002587 if (!(b->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002588 struct weston_output *last =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002589 container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002590 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002591
2592 /* XXX: not yet needed, we die with 0 outputs */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002593 if (!wl_list_empty(&b->compositor->output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002594 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002595 else
2596 x = 0;
2597 y = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002598 create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002599 connector, x, y,
2600 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002601 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002602
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002603 }
2604 drmModeFreeConnector(connector);
2605 }
2606 drmModeFreeResources(resources);
2607
Giulio Camuffo954f1832014-10-11 18:27:30 +03002608 disconnects = b->connector_allocator & ~connected;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002609 if (disconnects) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002610 wl_list_for_each_safe(output, next, &b->compositor->output_list,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002611 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002612 if (disconnects & (1 << output->connector_id)) {
2613 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002614 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002615 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002616 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002617 }
2618 }
2619 }
2620
Daniel Stonef556ebe2015-05-21 08:28:58 +01002621 /* FIXME: handle zero outputs, without terminating */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002622 if (b->connector_allocator == 0)
Giulio Camuffo459137b2014-10-11 23:56:24 +03002623 weston_compositor_exit(b->compositor);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002624}
2625
2626static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002627udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002628{
David Herrmannd7488c22012-03-11 20:05:21 +01002629 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002630 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002631
2632 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002633 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002634 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002635
David Herrmann6ac52db2012-03-11 20:05:22 +01002636 val = udev_device_get_property_value(device, "HOTPLUG");
2637 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002638 return 0;
2639
David Herrmann6ac52db2012-03-11 20:05:22 +01002640 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002641}
2642
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002643static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002644udev_drm_event(int fd, uint32_t mask, void *data)
2645{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002646 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002647 struct udev_device *event;
2648
Giulio Camuffo954f1832014-10-11 18:27:30 +03002649 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002650
Giulio Camuffo954f1832014-10-11 18:27:30 +03002651 if (udev_event_is_hotplug(b, event))
2652 update_outputs(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002653
2654 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002655
2656 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002657}
2658
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002659static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002660drm_restore(struct weston_compositor *ec)
2661{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002662 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002663}
2664
2665static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002666drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002667{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002668 struct drm_backend *b = (struct drm_backend *) ec->backend;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002669
Giulio Camuffo954f1832014-10-11 18:27:30 +03002670 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002671
Giulio Camuffo954f1832014-10-11 18:27:30 +03002672 wl_event_source_remove(b->udev_drm_source);
2673 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002674
Giulio Camuffo954f1832014-10-11 18:27:30 +03002675 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002676
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002677 weston_compositor_shutdown(ec);
2678
Giulio Camuffo954f1832014-10-11 18:27:30 +03002679 if (b->gbm)
2680 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002681
Giulio Camuffo954f1832014-10-11 18:27:30 +03002682 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002683
Giulio Camuffo954f1832014-10-11 18:27:30 +03002684 close(b->drm.fd);
Rob Bradford45c15b82013-07-26 16:29:35 +01002685
Giulio Camuffo954f1832014-10-11 18:27:30 +03002686 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002687}
2688
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002689static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002690drm_backend_set_modes(struct drm_backend *backend)
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002691{
2692 struct drm_output *output;
2693 struct drm_mode *drm_mode;
2694 int ret;
2695
Giulio Camuffo954f1832014-10-11 18:27:30 +03002696 wl_list_for_each(output, &backend->compositor->output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002697 if (!output->current) {
2698 /* If something that would cause the output to
2699 * switch mode happened while in another vt, we
2700 * might not have a current drm_fb. In that case,
2701 * schedule a repaint and let drm_output_repaint
2702 * handle setting the mode. */
2703 weston_output_schedule_repaint(&output->base);
2704 continue;
2705 }
2706
Hardeningff39efa2013-09-18 23:56:35 +02002707 drm_mode = (struct drm_mode *) output->base.current_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002708 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002709 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002710 &output->connector_id, 1,
2711 &drm_mode->mode_info);
2712 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002713 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002714 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002715 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002716 output->base.x, output->base.y);
2717 }
2718 }
2719}
2720
2721static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002722session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002723{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002724 struct weston_compositor *compositor = data;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002725 struct drm_backend *b = (struct drm_backend *)compositor->backend;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002726 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002727 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002728
Giulio Camuffo954f1832014-10-11 18:27:30 +03002729 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002730 weston_log("activating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002731 compositor->state = b->prev_state;
2732 drm_backend_set_modes(b);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002733 weston_compositor_damage_all(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002734 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002735 } else {
2736 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002737 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002738
Giulio Camuffo954f1832014-10-11 18:27:30 +03002739 b->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002740 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002741
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002742 /* If we have a repaint scheduled (either from a
2743 * pending pageflip or the idle handler), make sure we
2744 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002745 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002746 * further attemps at repainting. When we switch
2747 * back, we schedule a repaint, which will process
2748 * pending frame callbacks. */
2749
Giulio Camuffo954f1832014-10-11 18:27:30 +03002750 wl_list_for_each(output, &compositor->output_list, base.link) {
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002751 output->base.repaint_needed = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002752 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002753 }
2754
Giulio Camuffo954f1832014-10-11 18:27:30 +03002755 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002756 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002757
Giulio Camuffo954f1832014-10-11 18:27:30 +03002758 wl_list_for_each(sprite, &b->sprite_list, link)
2759 drmModeSetPlane(b->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002760 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002761 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002762 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002763 };
2764}
2765
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002766static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002767switch_vt_binding(struct weston_keyboard *keyboard, uint32_t time,
2768 uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002769{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002770 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002771
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002772 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002773}
2774
David Herrmann0af066f2012-10-29 19:21:16 +01002775/*
2776 * Find primary GPU
2777 * Some systems may have multiple DRM devices attached to a single seat. This
2778 * function loops over all devices and tries to find a PCI device with the
2779 * boot_vga sysfs attribute set to 1.
2780 * If no such device is found, the first DRM device reported by udev is used.
2781 */
2782static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002783find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002784{
2785 struct udev_enumerate *e;
2786 struct udev_list_entry *entry;
2787 const char *path, *device_seat, *id;
2788 struct udev_device *device, *drm_device, *pci;
2789
Giulio Camuffo954f1832014-10-11 18:27:30 +03002790 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002791 udev_enumerate_add_match_subsystem(e, "drm");
2792 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2793
2794 udev_enumerate_scan_devices(e);
2795 drm_device = NULL;
2796 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2797 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002798 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002799 if (!device)
2800 continue;
2801 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2802 if (!device_seat)
2803 device_seat = default_seat;
2804 if (strcmp(device_seat, seat)) {
2805 udev_device_unref(device);
2806 continue;
2807 }
2808
2809 pci = udev_device_get_parent_with_subsystem_devtype(device,
2810 "pci", NULL);
2811 if (pci) {
2812 id = udev_device_get_sysattr_value(pci, "boot_vga");
2813 if (id && !strcmp(id, "1")) {
2814 if (drm_device)
2815 udev_device_unref(drm_device);
2816 drm_device = device;
2817 break;
2818 }
2819 }
2820
2821 if (!drm_device)
2822 drm_device = device;
2823 else
2824 udev_device_unref(device);
2825 }
2826
2827 udev_enumerate_unref(e);
2828 return drm_device;
2829}
2830
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002831static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002832planes_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
2833 void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002834{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002835 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002836
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002837 switch (key) {
2838 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002839 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002840 break;
2841 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002842 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002843 break;
2844 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002845 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002846 break;
2847 default:
2848 break;
2849 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002850}
2851
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002852#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002853static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002854recorder_destroy(struct drm_output *output)
2855{
2856 vaapi_recorder_destroy(output->recorder);
2857 output->recorder = NULL;
2858
2859 output->base.disable_planes--;
2860
2861 wl_list_remove(&output->recorder_frame_listener.link);
2862 weston_log("[libva recorder] done\n");
2863}
2864
2865static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002866recorder_frame_notify(struct wl_listener *listener, void *data)
2867{
2868 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002869 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002870 int fd, ret;
2871
2872 output = container_of(listener, struct drm_output,
2873 recorder_frame_listener);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002874 b = (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002875
2876 if (!output->recorder)
2877 return;
2878
Giulio Camuffo954f1832014-10-11 18:27:30 +03002879 ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002880 DRM_CLOEXEC, &fd);
2881 if (ret) {
2882 weston_log("[libva recorder] "
2883 "failed to create prime fd for front buffer\n");
2884 return;
2885 }
2886
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002887 ret = vaapi_recorder_frame(output->recorder, fd,
2888 output->current->stride);
2889 if (ret < 0) {
2890 weston_log("[libva recorder] aborted: %m\n");
2891 recorder_destroy(output);
2892 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002893}
2894
2895static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002896create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002897 const char *filename)
2898{
2899 int fd;
2900 drm_magic_t magic;
2901
Giulio Camuffo954f1832014-10-11 18:27:30 +03002902 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002903 if (fd < 0)
2904 return NULL;
2905
2906 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002907 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002908
2909 return vaapi_recorder_create(fd, width, height, filename);
2910}
2911
2912static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002913recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002914 void *data)
2915{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002916 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002917 struct drm_output *output;
2918 int width, height;
2919
Giulio Camuffo954f1832014-10-11 18:27:30 +03002920 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002921 struct drm_output, base.link);
2922
2923 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002924 if (output->format != GBM_FORMAT_XRGB8888) {
2925 weston_log("failed to start vaapi recorder: "
2926 "output format not supported\n");
2927 return;
2928 }
2929
Hardeningff39efa2013-09-18 23:56:35 +02002930 width = output->base.current_mode->width;
2931 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002932
2933 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002934 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002935 if (!output->recorder) {
2936 weston_log("failed to create vaapi recorder\n");
2937 return;
2938 }
2939
2940 output->base.disable_planes++;
2941
2942 output->recorder_frame_listener.notify = recorder_frame_notify;
2943 wl_signal_add(&output->base.frame_signal,
2944 &output->recorder_frame_listener);
2945
2946 weston_output_schedule_repaint(&output->base);
2947
2948 weston_log("[libva recorder] initialized\n");
2949 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002950 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002951 }
2952}
2953#else
2954static void
2955recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2956 void *data)
2957{
2958 weston_log("Compiled without libva support\n");
2959}
2960#endif
2961
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002962static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002963switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002964{
2965 struct drm_output *output;
2966
Giulio Camuffo954f1832014-10-11 18:27:30 +03002967 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002968 return;
2969
2970 weston_log("Switching to GL renderer\n");
2971
Giulio Camuffo954f1832014-10-11 18:27:30 +03002972 b->gbm = create_gbm_device(b->drm.fd);
2973 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002974 weston_log("Failed to create gbm device. "
2975 "Aborting renderer switch\n");
2976 return;
2977 }
2978
Giulio Camuffo954f1832014-10-11 18:27:30 +03002979 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002980 pixman_renderer_output_destroy(&output->base);
2981
Giulio Camuffo954f1832014-10-11 18:27:30 +03002982 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002983
Giulio Camuffo954f1832014-10-11 18:27:30 +03002984 if (drm_backend_create_gl_renderer(b) < 0) {
2985 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002986 weston_log("Failed to create GL renderer. Quitting.\n");
2987 /* FIXME: we need a function to shutdown cleanly */
2988 assert(0);
2989 }
2990
Giulio Camuffo954f1832014-10-11 18:27:30 +03002991 wl_list_for_each(output, &b->compositor->output_list, base.link)
2992 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002993
Giulio Camuffo954f1832014-10-11 18:27:30 +03002994 b->use_pixman = 0;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002995}
2996
2997static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002998renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
2999 uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003000{
Derek Foreman8ae2db52015-07-15 13:00:36 -05003001 struct drm_backend *b =
3002 (struct drm_backend *) keyboard->seat->compositor;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003003
Giulio Camuffo954f1832014-10-11 18:27:30 +03003004 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003005}
3006
Giulio Camuffo954f1832014-10-11 18:27:30 +03003007static struct drm_backend *
3008drm_backend_create(struct weston_compositor *compositor,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003009 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003010 int *argc, char *argv[],
3011 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003012{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003013 struct drm_backend *b;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003014 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01003015 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003016 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01003017 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003018 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003019
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04003020 weston_log("initializing drm backend\n");
3021
Giulio Camuffo954f1832014-10-11 18:27:30 +03003022 b = zalloc(sizeof *b);
3023 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003024 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01003025
Pekka Paalanen68583832015-05-19 09:53:16 +03003026 /*
3027 * KMS support for hardware planes cannot properly synchronize
3028 * without nuclear page flip. Without nuclear/atomic, hw plane
3029 * and cursor plane updates would either tear or cause extra
3030 * waits for vblanks which means dropping the compositor framerate
3031 * to a fraction.
3032 *
3033 * These can be enabled again when nuclear/atomic support lands.
3034 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003035 b->sprites_are_broken = 1;
3036 b->cursors_are_broken = 1;
3037 b->compositor = compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003038
3039 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003040 if (get_gbm_format_from_section(section,
3041 GBM_FORMAT_XRGB8888,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003042 &b->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003043 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003044
Giulio Camuffo954f1832014-10-11 18:27:30 +03003045 b->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003046
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003047 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003048 compositor->launcher = weston_launcher_connect(compositor, param->tty,
3049 param->seat_id, true);
3050 if (compositor->launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003051 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04003052 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003053 goto err_compositor;
3054 }
3055
Giulio Camuffo954f1832014-10-11 18:27:30 +03003056 b->udev = udev_new();
3057 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003058 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003059 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003060 }
3061
Giulio Camuffo954f1832014-10-11 18:27:30 +03003062 b->session_listener.notify = session_notify;
3063 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003064
Giulio Camuffo954f1832014-10-11 18:27:30 +03003065 drm_device = find_primary_gpu(b, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003066 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003067 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003068 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003069 }
David Herrmann0af066f2012-10-29 19:21:16 +01003070 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003071
Giulio Camuffo954f1832014-10-11 18:27:30 +03003072 if (init_drm(b, drm_device) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003073 weston_log("failed to initialize kms\n");
3074 goto err_udev_dev;
3075 }
3076
Giulio Camuffo954f1832014-10-11 18:27:30 +03003077 if (b->use_pixman) {
3078 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003079 weston_log("failed to initialize pixman renderer\n");
3080 goto err_udev_dev;
3081 }
3082 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003083 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003084 weston_log("failed to initialize egl\n");
3085 goto err_udev_dev;
3086 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003087 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003088
Giulio Camuffo954f1832014-10-11 18:27:30 +03003089 b->base.destroy = drm_destroy;
3090 b->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003091
Giulio Camuffo954f1832014-10-11 18:27:30 +03003092 b->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02003093
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003094 for (key = KEY_F1; key < KEY_F9; key++)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003095 weston_compositor_add_key_binding(compositor, key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003096 MODIFIER_CTRL | MODIFIER_ALT,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003097 switch_vt_binding, compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003098
Giulio Camuffo954f1832014-10-11 18:27:30 +03003099 wl_list_init(&b->sprite_list);
3100 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003101
Giulio Camuffo954f1832014-10-11 18:27:30 +03003102 if (udev_input_init(&b->input,
3103 compositor, b->udev, param->seat_id) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003104 weston_log("failed to create input devices\n");
3105 goto err_sprite;
3106 }
3107
Giulio Camuffo954f1832014-10-11 18:27:30 +03003108 if (create_outputs(b, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003109 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003110 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003111 }
3112
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003113 /* A this point we have some idea of whether or not we have a working
3114 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003115 if (!b->cursors_are_broken)
3116 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003117
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02003118 path = NULL;
3119
Giulio Camuffo954f1832014-10-11 18:27:30 +03003120 loop = wl_display_get_event_loop(compositor->wl_display);
3121 b->drm_source =
3122 wl_event_loop_add_fd(loop, b->drm.fd,
3123 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003124
Giulio Camuffo954f1832014-10-11 18:27:30 +03003125 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3126 if (b->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003127 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003128 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003129 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003130 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003131 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003132 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003133 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003134 udev_monitor_get_fd(b->udev_monitor),
3135 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003136
Giulio Camuffo954f1832014-10-11 18:27:30 +03003137 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003138 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003139 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003140 }
3141
Daniel Stonea96b93c2012-06-22 14:04:37 +01003142 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003143
Giulio Camuffo954f1832014-10-11 18:27:30 +03003144 weston_compositor_add_debug_binding(compositor, KEY_O,
3145 planes_binding, b);
3146 weston_compositor_add_debug_binding(compositor, KEY_C,
3147 planes_binding, b);
3148 weston_compositor_add_debug_binding(compositor, KEY_V,
3149 planes_binding, b);
3150 weston_compositor_add_debug_binding(compositor, KEY_Q,
3151 recorder_binding, b);
3152 weston_compositor_add_debug_binding(compositor, KEY_W,
3153 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003154
Giulio Camuffo954f1832014-10-11 18:27:30 +03003155 compositor->backend = &b->base;
3156 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003157
3158err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003159 wl_event_source_remove(b->udev_drm_source);
3160 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003161err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003162 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003163err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003164 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003165err_sprite:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003166 compositor->renderer->destroy(compositor);
3167 gbm_device_destroy(b->gbm);
3168 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003169err_udev_dev:
3170 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003171err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003172 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003173err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003174 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003175err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003176 weston_compositor_shutdown(compositor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003177err_base:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003178 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003179 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003180}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003181
Giulio Camuffo954f1832014-10-11 18:27:30 +03003182WL_EXPORT int
3183backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003184 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003185{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003186 struct drm_backend *b;
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003187 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003188
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003189 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003190 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3191 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3192 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003193 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003194 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003195 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003196
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003197 param.seat_id = default_seat;
3198
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003199 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003200
Giulio Camuffo954f1832014-10-11 18:27:30 +03003201 b = drm_backend_create(compositor, &param, argc, argv, config);
3202 if (b == NULL)
3203 return -1;
3204 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003205}