blob: c1c6f002291738066925c417d3ab10aa48e8e375 [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
1093static void
1094drm_output_set_cursor(struct drm_output *output)
1095{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001096 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001097 struct weston_buffer *buffer;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001098 struct drm_backend *b =
1099 (struct drm_backend *) output->base.compositor->backend;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001100 EGLint handle, stride;
1101 struct gbm_bo *bo;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001102 uint32_t buf[b->cursor_width * b->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001103 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001104 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001105
Jason Ekstranda7af7042013-10-12 22:38:11 -05001106 output->cursor_view = NULL;
1107 if (ev == NULL) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001108 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001109 return;
1110 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001111
Neil Robertse5051712013-11-13 15:44:06 +00001112 buffer = ev->surface->buffer_ref.buffer;
1113
1114 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001115 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001116 pixman_region32_fini(&output->cursor_plane.damage);
1117 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001118 output->current_cursor ^= 1;
1119 bo = output->cursor_bo[output->current_cursor];
1120 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001121 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1122 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1123 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001124 for (i = 0; i < ev->surface->height; i++)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001125 memcpy(buf + i * b->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001126 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001127 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001128
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001129 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001130 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001131
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001132 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001133 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
1134 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001135 weston_log("failed to set cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001136 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001137 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001138 }
1139
Jason Ekstranda7af7042013-10-12 22:38:11 -05001140 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1141 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001142 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001143 if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001144 weston_log("failed to move cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001145 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001146 }
1147
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001148 output->cursor_plane.x = x;
1149 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001150 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001151}
1152
Jesse Barnes58ef3792012-02-23 09:45:49 -05001153static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001154drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001155{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001156 struct drm_backend *b =
1157 (struct drm_backend *)output_base->compositor->backend;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001158 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001159 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001160 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001161 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001162
1163 /*
1164 * Find a surface for each sprite in the output using some heuristics:
1165 * 1) size
1166 * 2) frequency of update
1167 * 3) opacity (though some hw might support alpha blending)
1168 * 4) clipping (this can be fixed with color keys)
1169 *
1170 * The idea is to save on blitting since this should save power.
1171 * If we can get a large video surface on the sprite for example,
1172 * the main display surface may not need to update at all, and
1173 * the client buffer can be used directly for the sprite surface
1174 * as we do for flipping full screen surfaces.
1175 */
1176 pixman_region32_init(&overlap);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001177 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001178
Giulio Camuffo954f1832014-10-11 18:27:30 +03001179 wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001180 struct weston_surface *es = ev->surface;
1181
1182 /* Test whether this buffer can ever go into a plane:
1183 * non-shm, or small enough to be a cursor.
1184 *
1185 * Also, keep a reference when using the pixman renderer.
1186 * That makes it possible to do a seamless switch to the GL
1187 * renderer and since the pixman renderer keeps a reference
1188 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001189 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001190 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001191 (es->buffer_ref.buffer &&
1192 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001193 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001194 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001195 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001196 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001197
Jesse Barnes58ef3792012-02-23 09:45:49 -05001198 pixman_region32_init(&surface_overlap);
1199 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001200 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001201
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001202 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001203 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001204 next_plane = primary;
1205 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001206 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001207 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001208 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001209 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001210 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001211 if (next_plane == NULL)
1212 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001213
Jason Ekstranda7af7042013-10-12 22:38:11 -05001214 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001215
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001216 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001217 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001218 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001219
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001220 if (next_plane == primary ||
1221 next_plane == &output->cursor_plane) {
1222 /* cursor plane involves a copy */
1223 ev->psf_flags = 0;
1224 } else {
1225 /* All other planes are a direct scanout of a
1226 * single client buffer.
1227 */
1228 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1229 }
1230
Jesse Barnes58ef3792012-02-23 09:45:49 -05001231 pixman_region32_fini(&surface_overlap);
1232 }
1233 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001234}
1235
Matt Roper361d2ad2011-08-29 13:52:23 -07001236static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001237drm_output_fini_pixman(struct drm_output *output);
1238
1239static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001240drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001241{
1242 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001243 struct drm_backend *b =
1244 (struct drm_backend *)output->base.compositor->backend;
Matt Roper361d2ad2011-08-29 13:52:23 -07001245 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001246
Xiong Zhangabd5d472013-10-11 14:43:07 +08001247 if (output->page_flip_pending) {
1248 output->destroy_pending = 1;
1249 weston_log("destroy output while page flip pending\n");
1250 return;
1251 }
1252
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001253 if (output->backlight)
1254 backlight_destroy(output->backlight);
1255
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001256 drmModeFreeProperty(output->dpms_prop);
1257
Matt Roper361d2ad2011-08-29 13:52:23 -07001258 /* Turn off hardware cursor */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001259 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001260
1261 /* Restore original CRTC state */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001262 drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001263 origcrtc->x, origcrtc->y,
1264 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001265 drmModeFreeCrtc(origcrtc);
1266
Giulio Camuffo954f1832014-10-11 18:27:30 +03001267 b->crtc_allocator &= ~(1 << output->crtc_id);
1268 b->connector_allocator &= ~(1 << output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001269
Giulio Camuffo954f1832014-10-11 18:27:30 +03001270 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001271 drm_output_fini_pixman(output);
1272 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001273 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001274 gbm_surface_destroy(output->surface);
1275 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001276
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001277 weston_plane_release(&output->fb_plane);
1278 weston_plane_release(&output->cursor_plane);
1279
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001280 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001281
Matt Roper361d2ad2011-08-29 13:52:23 -07001282 free(output);
1283}
1284
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001285/**
1286 * Find the closest-matching mode for a given target
1287 *
1288 * Given a target mode, find the most suitable mode amongst the output's
1289 * current mode list to use, preferring the current mode if possible, to
1290 * avoid an expensive mode switch.
1291 *
1292 * @param output DRM output
1293 * @param target_mode Mode to attempt to match
1294 * @returns Pointer to a mode from the output's mode list
1295 */
Alex Wub7b8bda2012-04-17 17:20:48 +08001296static struct drm_mode *
1297choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1298{
1299 struct drm_mode *tmp_mode = NULL, *mode;
1300
Hardeningff39efa2013-09-18 23:56:35 +02001301 if (output->base.current_mode->width == target_mode->width &&
1302 output->base.current_mode->height == target_mode->height &&
1303 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001304 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001305 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001306
1307 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1308 if (mode->mode_info.hdisplay == target_mode->width &&
1309 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001310 if (mode->base.refresh == target_mode->refresh ||
1311 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001312 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001313 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001314 tmp_mode = mode;
1315 }
1316 }
1317
1318 return tmp_mode;
1319}
1320
1321static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001322drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001323static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001324drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001325
1326static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001327drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1328{
1329 struct drm_output *output;
1330 struct drm_mode *drm_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001331 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08001332
1333 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001334 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001335 return -1;
1336 }
1337
1338 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001339 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001340 return -1;
1341 }
1342
Giulio Camuffo954f1832014-10-11 18:27:30 +03001343 b = (struct drm_backend *)output_base->compositor->backend;
Alex Wub7b8bda2012-04-17 17:20:48 +08001344 output = (struct drm_output *)output_base;
1345 drm_mode = choose_mode (output, mode);
1346
1347 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001348 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001349 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001350 }
1351
Hardeningff39efa2013-09-18 23:56:35 +02001352 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001353 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001354
Hardeningff39efa2013-09-18 23:56:35 +02001355 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001356
Hardeningff39efa2013-09-18 23:56:35 +02001357 output->base.current_mode = &drm_mode->base;
1358 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001359 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1360
Alex Wub7b8bda2012-04-17 17:20:48 +08001361 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001362 drm_output_release_fb(output, output->current);
1363 drm_output_release_fb(output, output->next);
1364 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001365
Giulio Camuffo954f1832014-10-11 18:27:30 +03001366 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001367 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001368 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001369 weston_log("failed to init output pixman state with "
1370 "new mode\n");
1371 return -1;
1372 }
1373 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001374 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001375 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001376
Giulio Camuffo954f1832014-10-11 18:27:30 +03001377 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001378 weston_log("failed to init output egl state with "
1379 "new mode");
1380 return -1;
1381 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001382 }
1383
Alex Wub7b8bda2012-04-17 17:20:48 +08001384 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001385}
1386
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001387static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001388on_drm_input(int fd, uint32_t mask, void *data)
1389{
1390 drmEventContext evctx;
1391
1392 memset(&evctx, 0, sizeof evctx);
1393 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1394 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001395 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001396 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001397
1398 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001399}
1400
1401static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001402init_drm(struct drm_backend *b, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001403{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001404 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001405 uint64_t cap;
1406 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001407 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001408
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001409 sysnum = udev_device_get_sysnum(device);
1410 if (sysnum)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001411 b->drm.id = atoi(sysnum);
1412 if (!sysnum || b->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001413 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001414 return -1;
1415 }
1416
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001417 filename = udev_device_get_devnode(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001418 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001419 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001420 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001421 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001422 udev_device_get_devnode(device));
1423 return -1;
1424 }
1425
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001426 weston_log("using %s\n", filename);
1427
Giulio Camuffo954f1832014-10-11 18:27:30 +03001428 b->drm.fd = fd;
1429 b->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001430
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001431 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1432 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001433 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001434 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001435 clk_id = CLOCK_REALTIME;
1436
Giulio Camuffo954f1832014-10-11 18:27:30 +03001437 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001438 weston_log("Error: failed to set presentation clock %d.\n",
1439 clk_id);
1440 return -1;
1441 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001442
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001443 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1444 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001445 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001446 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001447 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001448
1449 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1450 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001451 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001452 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001453 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001454
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001455 return 0;
1456}
1457
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001458static struct gbm_device *
1459create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001460{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001461 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001462
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001463 gl_renderer = weston_load_module("gl-renderer.so",
1464 "gl_renderer_interface");
1465 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001466 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001467
1468 /* GBM will load a dri driver, but even though they need symbols from
1469 * libglapi, in some version of Mesa they are not linked to it. Since
1470 * only the gl-renderer module links to it, the call above won't make
1471 * these symbols globally available, and loading the DRI driver fails.
1472 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1473 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1474
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001475 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001476
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001477 return gbm;
1478}
1479
Bryce Harringtonc056a982015-05-19 15:25:18 -07001480/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001481 * we may be able to susbstitute an ARGB format for an XRGB one.
1482 *
1483 * This returns 0 if substitution isn't possible, but 0 might be a
1484 * legitimate format for other EGL platforms, so the caller is
1485 * responsible for checking for 0 before calling gl_renderer->create().
1486 *
1487 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1488 * but it's entirely possible we'll see this again on other implementations.
1489 */
1490static int
1491fallback_format_for(uint32_t format)
1492{
1493 switch (format) {
1494 case GBM_FORMAT_XRGB8888:
1495 return GBM_FORMAT_ARGB8888;
1496 case GBM_FORMAT_XRGB2101010:
1497 return GBM_FORMAT_ARGB2101010;
1498 default:
1499 return 0;
1500 }
1501}
1502
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001503static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001504drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001505{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001506 EGLint format[2] = {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001507 b->format,
1508 fallback_format_for(b->format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05001509 };
1510 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001511
Derek Foremanc4cfe852015-05-15 12:12:40 -05001512 if (format[1])
1513 n_formats = 2;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001514 if (gl_renderer->create(b->compositor,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001515 EGL_PLATFORM_GBM_KHR,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001516 (void *)b->gbm,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001517 gl_renderer->opaque_attribs,
1518 format,
1519 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001520 return -1;
1521 }
1522
1523 return 0;
1524}
1525
1526static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001527init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001528{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001529 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001530
Giulio Camuffo954f1832014-10-11 18:27:30 +03001531 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001532 return -1;
1533
Giulio Camuffo954f1832014-10-11 18:27:30 +03001534 if (drm_backend_create_gl_renderer(b) < 0) {
1535 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001536 return -1;
1537 }
1538
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001539 return 0;
1540}
1541
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001542static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001543init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001544{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001545 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001546}
1547
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001548/**
1549 * Add a mode to output's mode list
1550 *
1551 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
1552 * output's mode list.
1553 *
1554 * @param output DRM output to add mode to
1555 * @param info DRM mode structure to add
1556 * @returns Newly-allocated Weston/DRM mode structure
1557 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001558static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001559drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001560{
1561 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001562 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001563
1564 mode = malloc(sizeof *mode);
1565 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001566 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001567
1568 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001569 mode->base.width = info->hdisplay;
1570 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001571
1572 /* Calculate higher precision (mHz) refresh rate */
1573 refresh = (info->clock * 1000000LL / info->htotal +
1574 info->vtotal / 2) / info->vtotal;
1575
1576 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1577 refresh *= 2;
1578 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1579 refresh /= 2;
1580 if (info->vscan > 1)
1581 refresh /= info->vscan;
1582
1583 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001584 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001585
1586 if (info->type & DRM_MODE_TYPE_PREFERRED)
1587 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1588
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001589 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1590
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001591 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001592}
1593
1594static int
1595drm_subpixel_to_wayland(int drm_value)
1596{
1597 switch (drm_value) {
1598 default:
1599 case DRM_MODE_SUBPIXEL_UNKNOWN:
1600 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1601 case DRM_MODE_SUBPIXEL_NONE:
1602 return WL_OUTPUT_SUBPIXEL_NONE;
1603 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1604 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1605 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1606 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1607 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1608 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1609 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1610 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1611 }
1612}
1613
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001614/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001615static uint32_t
1616drm_get_backlight(struct drm_output *output)
1617{
1618 long brightness, max_brightness, norm;
1619
1620 brightness = backlight_get_brightness(output->backlight);
1621 max_brightness = backlight_get_max_brightness(output->backlight);
1622
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001623 /* convert it on a scale of 0 to 255 */
1624 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001625
1626 return (uint32_t) norm;
1627}
1628
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001629/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001630static void
1631drm_set_backlight(struct weston_output *output_base, uint32_t value)
1632{
1633 struct drm_output *output = (struct drm_output *) output_base;
1634 long max_brightness, new_brightness;
1635
1636 if (!output->backlight)
1637 return;
1638
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001639 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001640 return;
1641
1642 max_brightness = backlight_get_max_brightness(output->backlight);
1643
1644 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001645 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001646
1647 backlight_set_brightness(output->backlight, new_brightness);
1648}
1649
1650static drmModePropertyPtr
1651drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1652{
1653 drmModePropertyPtr props;
1654 int i;
1655
1656 for (i = 0; i < connector->count_props; i++) {
1657 props = drmModeGetProperty(fd, connector->props[i]);
1658 if (!props)
1659 continue;
1660
1661 if (!strcmp(props->name, name))
1662 return props;
1663
1664 drmModeFreeProperty(props);
1665 }
1666
1667 return NULL;
1668}
1669
1670static void
1671drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1672{
1673 struct drm_output *output = (struct drm_output *) output_base;
1674 struct weston_compositor *ec = output_base->compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001675 struct drm_backend *b = (struct drm_backend *)ec->backend;
Daniel Stone36609c72015-06-18 07:49:02 +01001676 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001677
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001678 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001679 return;
1680
Daniel Stone36609c72015-06-18 07:49:02 +01001681 ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
1682 output->dpms_prop->prop_id, level);
1683 if (ret) {
1684 weston_log("DRM: DPMS: failed property set for %s\n",
1685 output->base.name);
1686 return;
1687 }
1688
1689 output->dpms = level;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001690}
1691
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001692static const char * const connector_type_names[] = {
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001693 "None",
1694 "VGA",
1695 "DVI",
1696 "DVI",
1697 "DVI",
1698 "Composite",
1699 "TV",
1700 "LVDS",
1701 "CTV",
1702 "DIN",
1703 "DP",
1704 "HDMI",
1705 "HDMI",
1706 "TV",
1707 "eDP",
1708};
1709
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001710static char *
1711make_connector_name(const drmModeConnector *con)
1712{
1713 char name[32];
1714 const char *type_name;
1715
1716 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1717 type_name = connector_type_names[con->connector_type];
1718 else
1719 type_name = "UNKNOWN";
1720 snprintf(name, sizeof name, "%s%d", type_name, con->connector_type_id);
1721
1722 return strdup(name);
1723}
1724
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001725static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001726find_crtc_for_connector(struct drm_backend *b,
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001727 drmModeRes *resources, drmModeConnector *connector)
1728{
1729 drmModeEncoder *encoder;
1730 uint32_t possible_crtcs;
1731 int i, j;
1732
1733 for (j = 0; j < connector->count_encoders; j++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001734 encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001735 if (encoder == NULL) {
1736 weston_log("Failed to get encoder.\n");
1737 return -1;
1738 }
1739 possible_crtcs = encoder->possible_crtcs;
1740 drmModeFreeEncoder(encoder);
1741
1742 for (i = 0; i < resources->count_crtcs; i++) {
1743 if (possible_crtcs & (1 << i) &&
Giulio Camuffo954f1832014-10-11 18:27:30 +03001744 !(b->crtc_allocator & (1 << resources->crtcs[i])))
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001745 return i;
1746 }
1747 }
1748
1749 return -1;
1750}
1751
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001752/* Init output state that depends on gl or gbm */
1753static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001754drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001755{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001756 EGLint format[2] = {
1757 output->format,
1758 fallback_format_for(output->format),
1759 };
1760 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001761
Giulio Camuffo954f1832014-10-11 18:27:30 +03001762 output->surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001763 output->base.current_mode->width,
1764 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001765 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001766 GBM_BO_USE_SCANOUT |
1767 GBM_BO_USE_RENDERING);
1768 if (!output->surface) {
1769 weston_log("failed to create gbm surface\n");
1770 return -1;
1771 }
1772
Derek Foremanc4cfe852015-05-15 12:12:40 -05001773 if (format[1])
1774 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001775 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001776 (EGLNativeDisplayType)output->surface,
1777 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001778 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001779 format,
1780 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001781 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001782 gbm_surface_destroy(output->surface);
1783 return -1;
1784 }
1785
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001786 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001787
1788 for (i = 0; i < 2; i++) {
1789 if (output->cursor_bo[i])
1790 continue;
1791
1792 output->cursor_bo[i] =
Giulio Camuffo954f1832014-10-11 18:27:30 +03001793 gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001794 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001795 }
1796
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001797 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1798 weston_log("cursor buffers unavailable, using gl cursors\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001799 b->cursors_are_broken = 1;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001800 }
1801
1802 return 0;
1803}
1804
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001805static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001806drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001807{
Hardeningff39efa2013-09-18 23:56:35 +02001808 int w = output->base.current_mode->width;
1809 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001810 unsigned int i;
1811
1812 /* FIXME error checking */
1813
1814 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001815 output->dumb[i] = drm_fb_create_dumb(b, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001816 if (!output->dumb[i])
1817 goto err;
1818
1819 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001820 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001821 output->dumb[i]->map,
1822 output->dumb[i]->stride);
1823 if (!output->image[i])
1824 goto err;
1825 }
1826
1827 if (pixman_renderer_output_create(&output->base) < 0)
1828 goto err;
1829
1830 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001831 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001832
1833 return 0;
1834
1835err:
1836 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1837 if (output->dumb[i])
1838 drm_fb_destroy_dumb(output->dumb[i]);
1839 if (output->image[i])
1840 pixman_image_unref(output->image[i]);
1841
1842 output->dumb[i] = NULL;
1843 output->image[i] = NULL;
1844 }
1845
1846 return -1;
1847}
1848
1849static void
1850drm_output_fini_pixman(struct drm_output *output)
1851{
1852 unsigned int i;
1853
1854 pixman_renderer_output_destroy(&output->base);
1855 pixman_region32_fini(&output->previous_damage);
1856
1857 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1858 drm_fb_destroy_dumb(output->dumb[i]);
1859 pixman_image_unref(output->image[i]);
1860 output->dumb[i] = NULL;
1861 output->image[i] = NULL;
1862 }
1863}
1864
Richard Hughes2b2092a2013-04-24 14:58:02 +01001865static void
1866edid_parse_string(const uint8_t *data, char text[])
1867{
1868 int i;
1869 int replaced = 0;
1870
1871 /* this is always 12 bytes, but we can't guarantee it's null
1872 * terminated or not junk. */
1873 strncpy(text, (const char *) data, 12);
1874
1875 /* remove insane chars */
1876 for (i = 0; text[i] != '\0'; i++) {
1877 if (text[i] == '\n' ||
1878 text[i] == '\r') {
1879 text[i] = '\0';
1880 break;
1881 }
1882 }
1883
1884 /* ensure string is printable */
1885 for (i = 0; text[i] != '\0'; i++) {
1886 if (!isprint(text[i])) {
1887 text[i] = '-';
1888 replaced++;
1889 }
1890 }
1891
1892 /* if the string is random junk, ignore the string */
1893 if (replaced > 4)
1894 text[0] = '\0';
1895}
1896
1897#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1898#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1899#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1900#define EDID_OFFSET_DATA_BLOCKS 0x36
1901#define EDID_OFFSET_LAST_BLOCK 0x6c
1902#define EDID_OFFSET_PNPID 0x08
1903#define EDID_OFFSET_SERIAL 0x0c
1904
1905static int
1906edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1907{
1908 int i;
1909 uint32_t serial_number;
1910
1911 /* check header */
1912 if (length < 128)
1913 return -1;
1914 if (data[0] != 0x00 || data[1] != 0xff)
1915 return -1;
1916
1917 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1918 * /--08--\/--09--\
1919 * 7654321076543210
1920 * |\---/\---/\---/
1921 * R C1 C2 C3 */
1922 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1923 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1924 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1925 edid->pnp_id[3] = '\0';
1926
1927 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1928 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1929 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1930 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1931 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1932 if (serial_number > 0)
1933 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1934
1935 /* parse EDID data */
1936 for (i = EDID_OFFSET_DATA_BLOCKS;
1937 i <= EDID_OFFSET_LAST_BLOCK;
1938 i += 18) {
1939 /* ignore pixel clock data */
1940 if (data[i] != 0)
1941 continue;
1942 if (data[i+2] != 0)
1943 continue;
1944
1945 /* any useful blocks? */
1946 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1947 edid_parse_string(&data[i+5],
1948 edid->monitor_name);
1949 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1950 edid_parse_string(&data[i+5],
1951 edid->serial_number);
1952 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1953 edid_parse_string(&data[i+5],
1954 edid->eisa_id);
1955 }
1956 }
1957 return 0;
1958}
1959
1960static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001961find_and_parse_output_edid(struct drm_backend *b,
Richard Hughes2b2092a2013-04-24 14:58:02 +01001962 struct drm_output *output,
1963 drmModeConnector *connector)
1964{
1965 drmModePropertyBlobPtr edid_blob = NULL;
1966 drmModePropertyPtr property;
1967 int i;
1968 int rc;
1969
1970 for (i = 0; i < connector->count_props && !edid_blob; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001971 property = drmModeGetProperty(b->drm.fd, connector->props[i]);
Richard Hughes2b2092a2013-04-24 14:58:02 +01001972 if (!property)
1973 continue;
1974 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1975 !strcmp(property->name, "EDID")) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001976 edid_blob = drmModeGetPropertyBlob(b->drm.fd,
Richard Hughes2b2092a2013-04-24 14:58:02 +01001977 connector->prop_values[i]);
1978 }
1979 drmModeFreeProperty(property);
1980 }
1981 if (!edid_blob)
1982 return;
1983
1984 rc = edid_parse(&output->edid,
1985 edid_blob->data,
1986 edid_blob->length);
1987 if (!rc) {
1988 weston_log("EDID data '%s', '%s', '%s'\n",
1989 output->edid.pnp_id,
1990 output->edid.monitor_name,
1991 output->edid.serial_number);
1992 if (output->edid.pnp_id[0] != '\0')
1993 output->base.make = output->edid.pnp_id;
1994 if (output->edid.monitor_name[0] != '\0')
1995 output->base.model = output->edid.monitor_name;
1996 if (output->edid.serial_number[0] != '\0')
1997 output->base.serial_number = output->edid.serial_number;
1998 }
1999 drmModeFreePropertyBlob(edid_blob);
2000}
2001
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002002
2003
2004static int
2005parse_modeline(const char *s, drmModeModeInfo *mode)
2006{
2007 char hsync[16];
2008 char vsync[16];
2009 float fclock;
2010
2011 mode->type = DRM_MODE_TYPE_USERDEF;
2012 mode->hskew = 0;
2013 mode->vscan = 0;
2014 mode->vrefresh = 0;
2015 mode->flags = 0;
2016
Rob Bradford307e09e2013-07-26 16:29:40 +01002017 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002018 &fclock,
2019 &mode->hdisplay,
2020 &mode->hsync_start,
2021 &mode->hsync_end,
2022 &mode->htotal,
2023 &mode->vdisplay,
2024 &mode->vsync_start,
2025 &mode->vsync_end,
2026 &mode->vtotal, hsync, vsync) != 11)
2027 return -1;
2028
2029 mode->clock = fclock * 1000;
2030 if (strcmp(hsync, "+hsync") == 0)
2031 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2032 else if (strcmp(hsync, "-hsync") == 0)
2033 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2034 else
2035 return -1;
2036
2037 if (strcmp(vsync, "+vsync") == 0)
2038 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2039 else if (strcmp(vsync, "-vsync") == 0)
2040 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2041 else
2042 return -1;
2043
2044 return 0;
2045}
2046
Rob Bradford66bd9f52013-06-25 18:56:42 +01002047static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002048setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01002049 struct weston_output *output,
2050 const char *s)
2051{
2052 if (strcmp(s, "") != 0) {
2053 struct udev_seat *seat;
2054
Giulio Camuffo954f1832014-10-11 18:27:30 +03002055 seat = udev_seat_get_named(&b->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002056 if (seat)
2057 seat->base.output = output;
2058
2059 if (seat && seat->base.pointer)
2060 weston_pointer_clamp(seat->base.pointer,
2061 &seat->base.pointer->x,
2062 &seat->base.pointer->y);
2063 }
2064}
2065
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002066static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002067get_gbm_format_from_section(struct weston_config_section *section,
2068 uint32_t default_value,
2069 uint32_t *format)
2070{
2071 char *s;
2072 int ret = 0;
2073
2074 weston_config_section_get_string(section,
2075 "gbm-format", &s, NULL);
2076
2077 if (s == NULL)
2078 *format = default_value;
2079 else if (strcmp(s, "xrgb8888") == 0)
2080 *format = GBM_FORMAT_XRGB8888;
2081 else if (strcmp(s, "rgb565") == 0)
2082 *format = GBM_FORMAT_RGB565;
2083 else if (strcmp(s, "xrgb2101010") == 0)
2084 *format = GBM_FORMAT_XRGB2101010;
2085 else {
2086 weston_log("fatal: unrecognized pixel format: %s\n", s);
2087 ret = -1;
2088 }
2089
2090 free(s);
2091
2092 return ret;
2093}
2094
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002095/**
2096 * Choose suitable mode for an output
2097 *
2098 * Find the most suitable mode to use for initial setup (or reconfiguration on
2099 * hotplug etc) for a DRM output.
2100 *
2101 * @param output DRM output to choose mode for
2102 * @param kind Strategy and preference to use when choosing mode
2103 * @param width Desired width for this output
2104 * @param height Desired height for this output
2105 * @param current_mode Mode currently being displayed on this output
2106 * @param modeline Manually-entered mode (may be NULL)
2107 * @returns A mode from the output's mode list, or NULL if none available
2108 */
2109static struct drm_mode *
2110drm_output_choose_initial_mode(struct drm_output *output,
2111 enum output_config kind,
2112 int width, int height,
2113 const drmModeModeInfo *current_mode,
2114 const drmModeModeInfo *modeline)
2115{
2116 struct drm_mode *preferred = NULL;
2117 struct drm_mode *current = NULL;
2118 struct drm_mode *configured = NULL;
2119 struct drm_mode *best = NULL;
2120 struct drm_mode *drm_mode;
2121
2122 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
2123 if (kind == OUTPUT_CONFIG_MODE &&
2124 width == drm_mode->base.width &&
2125 height == drm_mode->base.height)
2126 configured = drm_mode;
2127
2128 if (memcmp(&current_mode, &drm_mode->mode_info,
2129 sizeof *current_mode) == 0)
2130 current = drm_mode;
2131
2132 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
2133 preferred = drm_mode;
2134
2135 best = drm_mode;
2136 }
2137
2138 if (kind == OUTPUT_CONFIG_MODELINE) {
2139 configured = drm_output_add_mode(output, modeline);
2140 if (!configured)
2141 return NULL;
2142 }
2143
2144 if (current == NULL && current_mode->clock != 0) {
2145 current = drm_output_add_mode(output, current_mode);
2146 if (!current)
2147 return NULL;
2148 }
2149
2150 if (kind == OUTPUT_CONFIG_CURRENT)
2151 configured = current;
2152
2153 if (option_current_mode && current)
2154 return current;
2155
2156 if (configured)
2157 return configured;
2158
2159 if (preferred)
2160 return preferred;
2161
2162 if (current)
2163 return current;
2164
2165 if (best)
2166 return best;
2167
2168 weston_log("no available modes for %s\n", output->base.name);
2169 return NULL;
2170}
2171
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002172static int
2173connector_get_current_mode(drmModeConnector *connector, int drm_fd,
2174 drmModeModeInfo *mode)
2175{
2176 drmModeEncoder *encoder;
2177 drmModeCrtc *crtc;
2178
2179 /* Get the current mode on the crtc that's currently driving
2180 * this connector. */
2181 encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
2182 memset(mode, 0, sizeof *mode);
2183 if (encoder != NULL) {
2184 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
2185 drmModeFreeEncoder(encoder);
2186 if (crtc == NULL)
2187 return -1;
2188 if (crtc->mode_valid)
2189 *mode = crtc->mode;
2190 drmModeFreeCrtc(crtc);
2191 }
2192
2193 return 0;
2194}
2195
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002196/**
2197 * Create and configure a Weston output structure
2198 *
2199 * Given a DRM connector, create a matching drm_output structure and add it
2200 * to Weston's output list.
2201 *
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002202 * @param b Weston backend structure structure
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002203 * @param resources DRM resources for this device
2204 * @param connector DRM connector to use for this new output
2205 * @param x Horizontal offset to use into global co-ordinate space
2206 * @param y Vertical offset to use into global co-ordinate space
2207 * @param drm_device udev device pointer
2208 * @returns 0 on success, or -1 on failure
2209 */
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002210static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002211create_output_for_connector(struct drm_backend *b,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002212 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002213 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002214 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002215{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002216 struct drm_output *output;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002217 struct drm_mode *drm_mode, *next, *current;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002218 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002219 struct weston_config_section *section;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002220 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002221 int i, width, height, scale;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002222 char *s;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002223 enum output_config config;
2224 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002225
Giulio Camuffo954f1832014-10-11 18:27:30 +03002226 i = find_crtc_for_connector(b, resources, connector);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002227 if (i < 0) {
2228 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002229 return -1;
2230 }
2231
Peter Huttererf3d62272013-08-08 11:57:05 +10002232 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002233 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002234 return -1;
2235
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002236 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002237 output->base.name = make_connector_name(connector);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002238 output->base.make = "unknown";
2239 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002240 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002241 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002242
Giulio Camuffo954f1832014-10-11 18:27:30 +03002243 section = weston_config_get_section(b->compositor->config, "output", "name",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002244 output->base.name);
2245 weston_config_section_get_string(section, "mode", &s, "preferred");
2246 if (strcmp(s, "off") == 0)
2247 config = OUTPUT_CONFIG_OFF;
2248 else if (strcmp(s, "preferred") == 0)
2249 config = OUTPUT_CONFIG_PREFERRED;
2250 else if (strcmp(s, "current") == 0)
2251 config = OUTPUT_CONFIG_CURRENT;
2252 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2253 config = OUTPUT_CONFIG_MODE;
2254 else if (parse_modeline(s, &modeline) == 0)
2255 config = OUTPUT_CONFIG_MODELINE;
2256 else {
2257 weston_log("Invalid mode \"%s\" for output %s\n",
2258 s, output->base.name);
2259 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002260 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002261 free(s);
2262
2263 weston_config_section_get_int(section, "scale", &scale, 1);
2264 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002265 if (weston_parse_transform(s, &transform) < 0)
2266 weston_log("Invalid transform \"%s\" for output %s\n",
2267 s, output->base.name);
2268
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002269 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002270
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002271 if (get_gbm_format_from_section(section,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002272 b->format,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002273 &output->format) == -1)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002274 output->format = b->format;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002275
Rob Bradford66bd9f52013-06-25 18:56:42 +01002276 weston_config_section_get_string(section, "seat", &s, "");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002277 setup_output_seat_constraint(b, &output->base, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002278 free(s);
2279
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002280 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002281 output->pipe = i;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002282 b->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002283 output->connector_id = connector->connector_id;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002284 b->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002285
Giulio Camuffo954f1832014-10-11 18:27:30 +03002286 output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
2287 output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002288
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002289 if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
2290 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002291
David Herrmann0f0d54e2011-12-08 17:05:45 +01002292 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002293 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002294 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002295 goto err_free;
2296 }
2297
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002298 if (config == OUTPUT_CONFIG_OFF) {
2299 weston_log("Disabling output %s\n", output->base.name);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002300 drmModeSetCrtc(b->drm.fd, output->crtc_id,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002301 0, 0, 0, 0, 0, NULL);
2302 goto err_free;
2303 }
2304
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002305 current = drm_output_choose_initial_mode(output, config,
2306 width, height,
2307 &crtc_mode, &modeline);
2308 if (!current)
Wang Quanxianacb805a2012-07-30 18:09:46 -04002309 goto err_free;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002310 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02002311 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002312
Giulio Camuffo954f1832014-10-11 18:27:30 +03002313 weston_output_init(&output->base, b->compositor, x, y,
John Kåre Alsaker94659272012-11-13 19:10:18 +01002314 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002315 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002316
Giulio Camuffo954f1832014-10-11 18:27:30 +03002317 if (b->use_pixman) {
2318 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002319 weston_log("Failed to init output pixman state\n");
2320 goto err_output;
2321 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03002322 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002323 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002324 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002325 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002326
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002327 output->backlight = backlight_init(drm_device,
2328 connector->connector_type);
2329 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002330 weston_log("Initialized backlight, device %s\n",
2331 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002332 output->base.set_backlight = drm_set_backlight;
2333 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002334 } else {
2335 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002336 }
2337
Giulio Camuffo954f1832014-10-11 18:27:30 +03002338 weston_compositor_add_output(b->compositor, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002339
Giulio Camuffo954f1832014-10-11 18:27:30 +03002340 find_and_parse_output_edid(b, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002341 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2342 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002343
Jonas Ådahle5a12252013-04-05 23:07:11 +02002344 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002345 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002346 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002347 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002348 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002349 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002350
Richard Hughese7299962013-05-01 21:52:12 +01002351 output->base.gamma_size = output->original_crtc->gamma_size;
2352 output->base.set_gamma = drm_output_set_gamma;
2353
Giulio Camuffo954f1832014-10-11 18:27:30 +03002354 weston_plane_init(&output->cursor_plane, b->compositor, 0, 0);
2355 weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002356
Giulio Camuffo954f1832014-10-11 18:27:30 +03002357 weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
2358 weston_compositor_stack_plane(b->compositor, &output->fb_plane,
2359 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002360
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002361 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002362 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002363 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002364 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002365 m->width, m->height, m->refresh / 1000.0,
2366 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2367 ", preferred" : "",
2368 m->flags & WL_OUTPUT_MODE_CURRENT ?
2369 ", current" : "",
2370 connector->count_modes == 0 ?
2371 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002372
Mario Kleiner80817042015-06-21 21:25:11 +02002373 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2374 output->base.native_mode = output->base.current_mode;
2375 output->base.native_scale = output->base.current_scale;
2376
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002377 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002378
John Kåre Alsaker94659272012-11-13 19:10:18 +01002379err_output:
2380 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002381err_free:
2382 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2383 base.link) {
2384 wl_list_remove(&drm_mode->base.link);
2385 free(drm_mode);
2386 }
2387
2388 drmModeFreeCrtc(output->original_crtc);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002389 b->crtc_allocator &= ~(1 << output->crtc_id);
2390 b->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002391 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002392
David Herrmann0f0d54e2011-12-08 17:05:45 +01002393 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002394}
2395
Jesse Barnes58ef3792012-02-23 09:45:49 -05002396static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002397create_sprites(struct drm_backend *b)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002398{
2399 struct drm_sprite *sprite;
2400 drmModePlaneRes *plane_res;
2401 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002402 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002403
Giulio Camuffo954f1832014-10-11 18:27:30 +03002404 plane_res = drmModeGetPlaneResources(b->drm.fd);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002405 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002406 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002407 strerror(errno));
2408 return;
2409 }
2410
2411 for (i = 0; i < plane_res->count_planes; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002412 plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002413 if (!plane)
2414 continue;
2415
Peter Huttererf3d62272013-08-08 11:57:05 +10002416 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002417 plane->count_formats));
2418 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002419 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002420 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002421 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002422 continue;
2423 }
2424
Jesse Barnes58ef3792012-02-23 09:45:49 -05002425 sprite->possible_crtcs = plane->possible_crtcs;
2426 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002427 sprite->current = NULL;
2428 sprite->next = NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002429 sprite->backend = b;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002430 sprite->count_formats = plane->count_formats;
2431 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002432 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002433 drmModeFreePlane(plane);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002434 weston_plane_init(&sprite->plane, b->compositor, 0, 0);
2435 weston_compositor_stack_plane(b->compositor, &sprite->plane,
2436 &b->compositor->primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002437
Giulio Camuffo954f1832014-10-11 18:27:30 +03002438 wl_list_insert(&b->sprite_list, &sprite->link);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002439 }
2440
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002441 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002442}
2443
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002444static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002445destroy_sprites(struct drm_backend *backend)
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002446{
2447 struct drm_sprite *sprite, *next;
2448 struct drm_output *output;
2449
Giulio Camuffo954f1832014-10-11 18:27:30 +03002450 output = container_of(backend->compositor->output_list.next,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002451 struct drm_output, base.link);
2452
Giulio Camuffo954f1832014-10-11 18:27:30 +03002453 wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
2454 drmModeSetPlane(backend->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002455 sprite->plane_id,
2456 output->crtc_id, 0, 0,
2457 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002458 drm_output_release_fb(output, sprite->current);
2459 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002460 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002461 free(sprite);
2462 }
2463}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002464
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002465static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002466create_outputs(struct drm_backend *b, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002467 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002468{
2469 drmModeConnector *connector;
2470 drmModeRes *resources;
2471 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002472 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002473
Giulio Camuffo954f1832014-10-11 18:27:30 +03002474 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002475 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002476 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002477 return -1;
2478 }
2479
Giulio Camuffo954f1832014-10-11 18:27:30 +03002480 b->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
2481 if (!b->crtcs) {
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002482 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002483 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002484 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002485
Giulio Camuffo954f1832014-10-11 18:27:30 +03002486 b->min_width = resources->min_width;
2487 b->max_width = resources->max_width;
2488 b->min_height = resources->min_height;
2489 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002490
Giulio Camuffo954f1832014-10-11 18:27:30 +03002491 b->num_crtcs = resources->count_crtcs;
2492 memcpy(b->crtcs, resources->crtcs, sizeof(uint32_t) * b->num_crtcs);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002493
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002494 for (i = 0; i < resources->count_connectors; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002495 connector = drmModeGetConnector(b->drm.fd,
Benjamin Franzke117483d2011-08-30 11:38:26 +02002496 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002497 if (connector == NULL)
2498 continue;
2499
2500 if (connector->connection == DRM_MODE_CONNECTED &&
2501 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002502 connector->connector_id == option_connector)) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002503 if (create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002504 connector, x, y,
2505 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002506 drmModeFreeConnector(connector);
2507 continue;
2508 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002509
Giulio Camuffo954f1832014-10-11 18:27:30 +03002510 x += container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002511 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002512 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002513 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002514
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002515 drmModeFreeConnector(connector);
2516 }
2517
Giulio Camuffo954f1832014-10-11 18:27:30 +03002518 if (wl_list_empty(&b->compositor->output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002519 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002520 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002521 return -1;
2522 }
2523
2524 drmModeFreeResources(resources);
2525
2526 return 0;
2527}
2528
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002529static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002530update_outputs(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002531{
2532 drmModeConnector *connector;
2533 drmModeRes *resources;
2534 struct drm_output *output, *next;
2535 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002536 uint32_t connected = 0, disconnects = 0;
2537 int i;
2538
Giulio Camuffo954f1832014-10-11 18:27:30 +03002539 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002540 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002541 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002542 return;
2543 }
2544
2545 /* collect new connects */
2546 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002547 int connector_id = resources->connectors[i];
2548
Giulio Camuffo954f1832014-10-11 18:27:30 +03002549 connector = drmModeGetConnector(b->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002550 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002551 continue;
2552
David Herrmann7551cff2011-12-08 17:05:43 +01002553 if (connector->connection != DRM_MODE_CONNECTED) {
2554 drmModeFreeConnector(connector);
2555 continue;
2556 }
2557
Benjamin Franzke117483d2011-08-30 11:38:26 +02002558 connected |= (1 << connector_id);
2559
Giulio Camuffo954f1832014-10-11 18:27:30 +03002560 if (!(b->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002561 struct weston_output *last =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002562 container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002563 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002564
2565 /* XXX: not yet needed, we die with 0 outputs */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002566 if (!wl_list_empty(&b->compositor->output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002567 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002568 else
2569 x = 0;
2570 y = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002571 create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002572 connector, x, y,
2573 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002574 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002575
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002576 }
2577 drmModeFreeConnector(connector);
2578 }
2579 drmModeFreeResources(resources);
2580
Giulio Camuffo954f1832014-10-11 18:27:30 +03002581 disconnects = b->connector_allocator & ~connected;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002582 if (disconnects) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002583 wl_list_for_each_safe(output, next, &b->compositor->output_list,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002584 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002585 if (disconnects & (1 << output->connector_id)) {
2586 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002587 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002588 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002589 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002590 }
2591 }
2592 }
2593
Daniel Stonef556ebe2015-05-21 08:28:58 +01002594 /* FIXME: handle zero outputs, without terminating */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002595 if (b->connector_allocator == 0)
Giulio Camuffo459137b2014-10-11 23:56:24 +03002596 weston_compositor_exit(b->compositor);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002597}
2598
2599static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002600udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002601{
David Herrmannd7488c22012-03-11 20:05:21 +01002602 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002603 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002604
2605 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002606 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002607 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002608
David Herrmann6ac52db2012-03-11 20:05:22 +01002609 val = udev_device_get_property_value(device, "HOTPLUG");
2610 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002611 return 0;
2612
David Herrmann6ac52db2012-03-11 20:05:22 +01002613 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002614}
2615
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002616static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002617udev_drm_event(int fd, uint32_t mask, void *data)
2618{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002619 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002620 struct udev_device *event;
2621
Giulio Camuffo954f1832014-10-11 18:27:30 +03002622 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002623
Giulio Camuffo954f1832014-10-11 18:27:30 +03002624 if (udev_event_is_hotplug(b, event))
2625 update_outputs(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002626
2627 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002628
2629 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002630}
2631
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002632static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002633drm_restore(struct weston_compositor *ec)
2634{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002635 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002636}
2637
2638static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002639drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002640{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002641 struct drm_backend *b = (struct drm_backend *) ec->backend;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002642
Giulio Camuffo954f1832014-10-11 18:27:30 +03002643 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002644
Giulio Camuffo954f1832014-10-11 18:27:30 +03002645 wl_event_source_remove(b->udev_drm_source);
2646 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002647
Giulio Camuffo954f1832014-10-11 18:27:30 +03002648 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002649
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002650 weston_compositor_shutdown(ec);
2651
Giulio Camuffo954f1832014-10-11 18:27:30 +03002652 if (b->gbm)
2653 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002654
Giulio Camuffo954f1832014-10-11 18:27:30 +03002655 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002656
Giulio Camuffo954f1832014-10-11 18:27:30 +03002657 close(b->drm.fd);
Rob Bradford45c15b82013-07-26 16:29:35 +01002658
Giulio Camuffo954f1832014-10-11 18:27:30 +03002659 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002660}
2661
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002662static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002663drm_backend_set_modes(struct drm_backend *backend)
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002664{
2665 struct drm_output *output;
2666 struct drm_mode *drm_mode;
2667 int ret;
2668
Giulio Camuffo954f1832014-10-11 18:27:30 +03002669 wl_list_for_each(output, &backend->compositor->output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002670 if (!output->current) {
2671 /* If something that would cause the output to
2672 * switch mode happened while in another vt, we
2673 * might not have a current drm_fb. In that case,
2674 * schedule a repaint and let drm_output_repaint
2675 * handle setting the mode. */
2676 weston_output_schedule_repaint(&output->base);
2677 continue;
2678 }
2679
Hardeningff39efa2013-09-18 23:56:35 +02002680 drm_mode = (struct drm_mode *) output->base.current_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002681 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002682 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002683 &output->connector_id, 1,
2684 &drm_mode->mode_info);
2685 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002686 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002687 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002688 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002689 output->base.x, output->base.y);
2690 }
2691 }
2692}
2693
2694static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002695session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002696{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002697 struct weston_compositor *compositor = data;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002698 struct drm_backend *b = (struct drm_backend *)compositor->backend;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002699 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002700 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002701
Giulio Camuffo954f1832014-10-11 18:27:30 +03002702 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002703 weston_log("activating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002704 compositor->state = b->prev_state;
2705 drm_backend_set_modes(b);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002706 weston_compositor_damage_all(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002707 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002708 } else {
2709 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002710 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002711
Giulio Camuffo954f1832014-10-11 18:27:30 +03002712 b->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002713 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002714
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002715 /* If we have a repaint scheduled (either from a
2716 * pending pageflip or the idle handler), make sure we
2717 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002718 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002719 * further attemps at repainting. When we switch
2720 * back, we schedule a repaint, which will process
2721 * pending frame callbacks. */
2722
Giulio Camuffo954f1832014-10-11 18:27:30 +03002723 wl_list_for_each(output, &compositor->output_list, base.link) {
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002724 output->base.repaint_needed = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002725 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002726 }
2727
Giulio Camuffo954f1832014-10-11 18:27:30 +03002728 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002729 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002730
Giulio Camuffo954f1832014-10-11 18:27:30 +03002731 wl_list_for_each(sprite, &b->sprite_list, link)
2732 drmModeSetPlane(b->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002733 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002734 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002735 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002736 };
2737}
2738
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002739static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002740switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002741{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002742 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002743
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002744 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002745}
2746
David Herrmann0af066f2012-10-29 19:21:16 +01002747/*
2748 * Find primary GPU
2749 * Some systems may have multiple DRM devices attached to a single seat. This
2750 * function loops over all devices and tries to find a PCI device with the
2751 * boot_vga sysfs attribute set to 1.
2752 * If no such device is found, the first DRM device reported by udev is used.
2753 */
2754static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002755find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002756{
2757 struct udev_enumerate *e;
2758 struct udev_list_entry *entry;
2759 const char *path, *device_seat, *id;
2760 struct udev_device *device, *drm_device, *pci;
2761
Giulio Camuffo954f1832014-10-11 18:27:30 +03002762 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002763 udev_enumerate_add_match_subsystem(e, "drm");
2764 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2765
2766 udev_enumerate_scan_devices(e);
2767 drm_device = NULL;
2768 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2769 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002770 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002771 if (!device)
2772 continue;
2773 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2774 if (!device_seat)
2775 device_seat = default_seat;
2776 if (strcmp(device_seat, seat)) {
2777 udev_device_unref(device);
2778 continue;
2779 }
2780
2781 pci = udev_device_get_parent_with_subsystem_devtype(device,
2782 "pci", NULL);
2783 if (pci) {
2784 id = udev_device_get_sysattr_value(pci, "boot_vga");
2785 if (id && !strcmp(id, "1")) {
2786 if (drm_device)
2787 udev_device_unref(drm_device);
2788 drm_device = device;
2789 break;
2790 }
2791 }
2792
2793 if (!drm_device)
2794 drm_device = device;
2795 else
2796 udev_device_unref(device);
2797 }
2798
2799 udev_enumerate_unref(e);
2800 return drm_device;
2801}
2802
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002803static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002804planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002805{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002806 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002807
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002808 switch (key) {
2809 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002810 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002811 break;
2812 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002813 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002814 break;
2815 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002816 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002817 break;
2818 default:
2819 break;
2820 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002821}
2822
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002823#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002824static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002825recorder_destroy(struct drm_output *output)
2826{
2827 vaapi_recorder_destroy(output->recorder);
2828 output->recorder = NULL;
2829
2830 output->base.disable_planes--;
2831
2832 wl_list_remove(&output->recorder_frame_listener.link);
2833 weston_log("[libva recorder] done\n");
2834}
2835
2836static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002837recorder_frame_notify(struct wl_listener *listener, void *data)
2838{
2839 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002840 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002841 int fd, ret;
2842
2843 output = container_of(listener, struct drm_output,
2844 recorder_frame_listener);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002845 b = (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002846
2847 if (!output->recorder)
2848 return;
2849
Giulio Camuffo954f1832014-10-11 18:27:30 +03002850 ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002851 DRM_CLOEXEC, &fd);
2852 if (ret) {
2853 weston_log("[libva recorder] "
2854 "failed to create prime fd for front buffer\n");
2855 return;
2856 }
2857
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002858 ret = vaapi_recorder_frame(output->recorder, fd,
2859 output->current->stride);
2860 if (ret < 0) {
2861 weston_log("[libva recorder] aborted: %m\n");
2862 recorder_destroy(output);
2863 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002864}
2865
2866static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002867create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002868 const char *filename)
2869{
2870 int fd;
2871 drm_magic_t magic;
2872
Giulio Camuffo954f1832014-10-11 18:27:30 +03002873 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002874 if (fd < 0)
2875 return NULL;
2876
2877 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002878 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002879
2880 return vaapi_recorder_create(fd, width, height, filename);
2881}
2882
2883static void
2884recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2885 void *data)
2886{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002887 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002888 struct drm_output *output;
2889 int width, height;
2890
Giulio Camuffo954f1832014-10-11 18:27:30 +03002891 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002892 struct drm_output, base.link);
2893
2894 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002895 if (output->format != GBM_FORMAT_XRGB8888) {
2896 weston_log("failed to start vaapi recorder: "
2897 "output format not supported\n");
2898 return;
2899 }
2900
Hardeningff39efa2013-09-18 23:56:35 +02002901 width = output->base.current_mode->width;
2902 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002903
2904 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002905 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002906 if (!output->recorder) {
2907 weston_log("failed to create vaapi recorder\n");
2908 return;
2909 }
2910
2911 output->base.disable_planes++;
2912
2913 output->recorder_frame_listener.notify = recorder_frame_notify;
2914 wl_signal_add(&output->base.frame_signal,
2915 &output->recorder_frame_listener);
2916
2917 weston_output_schedule_repaint(&output->base);
2918
2919 weston_log("[libva recorder] initialized\n");
2920 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002921 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002922 }
2923}
2924#else
2925static void
2926recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2927 void *data)
2928{
2929 weston_log("Compiled without libva support\n");
2930}
2931#endif
2932
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002933static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002934switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002935{
2936 struct drm_output *output;
2937
Giulio Camuffo954f1832014-10-11 18:27:30 +03002938 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002939 return;
2940
2941 weston_log("Switching to GL renderer\n");
2942
Giulio Camuffo954f1832014-10-11 18:27:30 +03002943 b->gbm = create_gbm_device(b->drm.fd);
2944 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002945 weston_log("Failed to create gbm device. "
2946 "Aborting renderer switch\n");
2947 return;
2948 }
2949
Giulio Camuffo954f1832014-10-11 18:27:30 +03002950 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002951 pixman_renderer_output_destroy(&output->base);
2952
Giulio Camuffo954f1832014-10-11 18:27:30 +03002953 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002954
Giulio Camuffo954f1832014-10-11 18:27:30 +03002955 if (drm_backend_create_gl_renderer(b) < 0) {
2956 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002957 weston_log("Failed to create GL renderer. Quitting.\n");
2958 /* FIXME: we need a function to shutdown cleanly */
2959 assert(0);
2960 }
2961
Giulio Camuffo954f1832014-10-11 18:27:30 +03002962 wl_list_for_each(output, &b->compositor->output_list, base.link)
2963 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002964
Giulio Camuffo954f1832014-10-11 18:27:30 +03002965 b->use_pixman = 0;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002966}
2967
2968static void
2969renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2970 void *data)
2971{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002972 struct drm_backend *b = (struct drm_backend *)seat->compositor->backend;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002973
Giulio Camuffo954f1832014-10-11 18:27:30 +03002974 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002975}
2976
Giulio Camuffo954f1832014-10-11 18:27:30 +03002977static struct drm_backend *
2978drm_backend_create(struct weston_compositor *compositor,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002979 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002980 int *argc, char *argv[],
2981 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002982{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002983 struct drm_backend *b;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002984 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002985 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002986 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002987 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002988 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002989
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002990 weston_log("initializing drm backend\n");
2991
Giulio Camuffo954f1832014-10-11 18:27:30 +03002992 b = zalloc(sizeof *b);
2993 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002994 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002995
Pekka Paalanen68583832015-05-19 09:53:16 +03002996 /*
2997 * KMS support for hardware planes cannot properly synchronize
2998 * without nuclear page flip. Without nuclear/atomic, hw plane
2999 * and cursor plane updates would either tear or cause extra
3000 * waits for vblanks which means dropping the compositor framerate
3001 * to a fraction.
3002 *
3003 * These can be enabled again when nuclear/atomic support lands.
3004 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003005 b->sprites_are_broken = 1;
3006 b->cursors_are_broken = 1;
3007 b->compositor = compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003008
3009 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003010 if (get_gbm_format_from_section(section,
3011 GBM_FORMAT_XRGB8888,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003012 &b->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003013 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003014
Giulio Camuffo954f1832014-10-11 18:27:30 +03003015 b->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003016
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003017 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003018 compositor->launcher = weston_launcher_connect(compositor, param->tty,
3019 param->seat_id, true);
3020 if (compositor->launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003021 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04003022 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003023 goto err_compositor;
3024 }
3025
Giulio Camuffo954f1832014-10-11 18:27:30 +03003026 b->udev = udev_new();
3027 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003028 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003029 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003030 }
3031
Giulio Camuffo954f1832014-10-11 18:27:30 +03003032 b->session_listener.notify = session_notify;
3033 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003034
Giulio Camuffo954f1832014-10-11 18:27:30 +03003035 drm_device = find_primary_gpu(b, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003036 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003037 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003038 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003039 }
David Herrmann0af066f2012-10-29 19:21:16 +01003040 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003041
Giulio Camuffo954f1832014-10-11 18:27:30 +03003042 if (init_drm(b, drm_device) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003043 weston_log("failed to initialize kms\n");
3044 goto err_udev_dev;
3045 }
3046
Giulio Camuffo954f1832014-10-11 18:27:30 +03003047 if (b->use_pixman) {
3048 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003049 weston_log("failed to initialize pixman renderer\n");
3050 goto err_udev_dev;
3051 }
3052 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003053 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003054 weston_log("failed to initialize egl\n");
3055 goto err_udev_dev;
3056 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003057 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003058
Giulio Camuffo954f1832014-10-11 18:27:30 +03003059 b->base.destroy = drm_destroy;
3060 b->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003061
Giulio Camuffo954f1832014-10-11 18:27:30 +03003062 b->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02003063
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003064 for (key = KEY_F1; key < KEY_F9; key++)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003065 weston_compositor_add_key_binding(compositor, key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003066 MODIFIER_CTRL | MODIFIER_ALT,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003067 switch_vt_binding, compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003068
Giulio Camuffo954f1832014-10-11 18:27:30 +03003069 wl_list_init(&b->sprite_list);
3070 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003071
Giulio Camuffo954f1832014-10-11 18:27:30 +03003072 if (udev_input_init(&b->input,
3073 compositor, b->udev, param->seat_id) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003074 weston_log("failed to create input devices\n");
3075 goto err_sprite;
3076 }
3077
Giulio Camuffo954f1832014-10-11 18:27:30 +03003078 if (create_outputs(b, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003079 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003080 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003081 }
3082
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003083 /* A this point we have some idea of whether or not we have a working
3084 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003085 if (!b->cursors_are_broken)
3086 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003087
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02003088 path = NULL;
3089
Giulio Camuffo954f1832014-10-11 18:27:30 +03003090 loop = wl_display_get_event_loop(compositor->wl_display);
3091 b->drm_source =
3092 wl_event_loop_add_fd(loop, b->drm.fd,
3093 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003094
Giulio Camuffo954f1832014-10-11 18:27:30 +03003095 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3096 if (b->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003097 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003098 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003099 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003100 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003101 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003102 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003103 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003104 udev_monitor_get_fd(b->udev_monitor),
3105 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003106
Giulio Camuffo954f1832014-10-11 18:27:30 +03003107 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003108 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003109 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003110 }
3111
Daniel Stonea96b93c2012-06-22 14:04:37 +01003112 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003113
Giulio Camuffo954f1832014-10-11 18:27:30 +03003114 weston_compositor_add_debug_binding(compositor, KEY_O,
3115 planes_binding, b);
3116 weston_compositor_add_debug_binding(compositor, KEY_C,
3117 planes_binding, b);
3118 weston_compositor_add_debug_binding(compositor, KEY_V,
3119 planes_binding, b);
3120 weston_compositor_add_debug_binding(compositor, KEY_Q,
3121 recorder_binding, b);
3122 weston_compositor_add_debug_binding(compositor, KEY_W,
3123 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003124
Giulio Camuffo954f1832014-10-11 18:27:30 +03003125 compositor->backend = &b->base;
3126 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003127
3128err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003129 wl_event_source_remove(b->udev_drm_source);
3130 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003131err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003132 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003133err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003134 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003135err_sprite:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003136 compositor->renderer->destroy(compositor);
3137 gbm_device_destroy(b->gbm);
3138 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003139err_udev_dev:
3140 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003141err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003142 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003143err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003144 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003145err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003146 weston_compositor_shutdown(compositor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003147err_base:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003148 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003149 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003150}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003151
Giulio Camuffo954f1832014-10-11 18:27:30 +03003152WL_EXPORT int
3153backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003154 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003155{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003156 struct drm_backend *b;
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003157 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003158
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003159 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003160 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3161 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3162 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003163 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003164 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003165 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003166
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003167 param.seat_id = default_seat;
3168
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003169 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003170
Giulio Camuffo954f1832014-10-11 18:27:30 +03003171 b = drm_backend_create(compositor, &param, argc, argv, config);
3172 if (b == NULL)
3173 return -1;
3174 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003175}