blob: 26f00124def88e20091cff843cd9ecc6f2d43b1c [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"
Pekka Paalanene4d231e2014-06-12 15:12:48 +030059#include "linux-dmabuf.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040060
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030061#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
62#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
63#endif
64
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030065#ifndef DRM_CAP_CURSOR_WIDTH
66#define DRM_CAP_CURSOR_WIDTH 0x8
67#endif
68
69#ifndef DRM_CAP_CURSOR_HEIGHT
70#define DRM_CAP_CURSOR_HEIGHT 0x9
71#endif
72
73#ifndef GBM_BO_USE_CURSOR
74#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
75#endif
76
Kristian Høgsberg061c4252012-06-28 11:28:15 -040077static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060078
79enum output_config {
80 OUTPUT_CONFIG_INVALID = 0,
81 OUTPUT_CONFIG_OFF,
82 OUTPUT_CONFIG_PREFERRED,
83 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060084 OUTPUT_CONFIG_MODE,
85 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060086};
87
Giulio Camuffo954f1832014-10-11 18:27:30 +030088struct drm_backend {
89 struct weston_backend base;
90 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040091
92 struct udev *udev;
93 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040094
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010095 struct udev_monitor *udev_monitor;
96 struct wl_event_source *udev_drm_source;
97
Benjamin Franzke2af7f102011-03-02 11:14:59 +010098 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010099 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100100 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300101 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100102 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200103 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500104 uint32_t *crtcs;
105 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -0500106 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100107 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700108 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700109 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200110
Rob Clark4339add2012-08-09 14:18:28 -0500111 /* we need these parameters in order to not fail drmModeAddFB2()
112 * due to out of bounds dimensions, and then mistakenly set
113 * sprites_are_broken:
114 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200115 uint32_t min_width, max_width;
116 uint32_t min_height, max_height;
117 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500118
Jesse Barnes58ef3792012-02-23 09:45:49 -0500119 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500120 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200121 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500122
Rob Clarkab5b1e32012-08-09 13:24:45 -0500123 int cursors_are_broken;
124
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200125 int use_pixman;
126
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200127 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300128
Rob Bradfordd355b802013-05-31 18:09:55 +0100129 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300130
Daniel Stone70d337d2015-06-16 18:42:23 +0100131 int32_t cursor_width;
132 int32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400133};
134
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400135struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500136 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400137 drmModeModeInfo mode_info;
138};
139
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300140struct drm_output;
141
142struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300143 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200144 uint32_t fb_id, stride, handle, size;
145 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300146 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200147 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200148
149 /* Used by gbm fbs */
150 struct gbm_bo *bo;
151
152 /* Used by dumb fbs */
153 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300154};
155
Richard Hughes2b2092a2013-04-24 14:58:02 +0100156struct drm_edid {
157 char eisa_id[13];
158 char monitor_name[13];
159 char pnp_id[5];
160 char serial_number[13];
161};
162
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400163struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500164 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400165
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400166 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500167 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400168 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700169 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100170 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300171 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000172 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200173
Daniel Stone36609c72015-06-18 07:49:02 +0100174 enum dpms_enum dpms;
175
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300176 int vblank_pending;
177 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800178 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300179
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400180 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400181 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400182 struct weston_plane cursor_plane;
183 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500184 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400185 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300186 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200187 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200188
189 struct drm_fb *dumb[2];
190 pixman_image_t *image[2];
191 int current_image;
192 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300193
194 struct vaapi_recorder *recorder;
195 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400196};
197
Jesse Barnes58ef3792012-02-23 09:45:49 -0500198/*
199 * An output has a primary display plane plus zero or more sprites for
200 * blending display contents.
201 */
202struct drm_sprite {
203 struct wl_list link;
204
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400205 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500206
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200207 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300208 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300209 struct drm_backend *backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500210
Jesse Barnes58ef3792012-02-23 09:45:49 -0500211 uint32_t possible_crtcs;
212 uint32_t plane_id;
213 uint32_t count_formats;
214
215 int32_t src_x, src_y;
216 uint32_t src_w, src_h;
217 uint32_t dest_x, dest_y;
218 uint32_t dest_w, dest_h;
219
220 uint32_t formats[];
221};
222
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700223struct drm_parameters {
224 int connector;
225 int tty;
226 int use_pixman;
227 const char *seat_id;
228};
229
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300230static struct gl_renderer_interface *gl_renderer;
231
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500232static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400233
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400234static void
235drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400236
Mario Kleinerf507ec32015-06-21 21:25:14 +0200237static void
238drm_output_update_msc(struct drm_output *output, unsigned int seq);
239
Jesse Barnes58ef3792012-02-23 09:45:49 -0500240static int
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200241drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500242{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200243 struct weston_compositor *ec = output->base.compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300244 struct drm_backend *b =(struct drm_backend *)ec->backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500245 int crtc;
246
Giulio Camuffo954f1832014-10-11 18:27:30 +0300247 for (crtc = 0; crtc < b->num_crtcs; crtc++) {
248 if (b->crtcs[crtc] != output->crtc_id)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500249 continue;
250
251 if (supported & (1 << crtc))
252 return -1;
253 }
254
255 return 0;
256}
257
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300258static void
259drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
260{
261 struct drm_fb *fb = data;
262 struct gbm_device *gbm = gbm_bo_get_device(bo);
263
264 if (fb->fb_id)
265 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
266
Pekka Paalanende685b82012-12-04 15:58:12 +0200267 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300268
269 free(data);
270}
271
272static struct drm_fb *
Giulio Camuffo954f1832014-10-11 18:27:30 +0300273drm_fb_create_dumb(struct drm_backend *b, unsigned width, unsigned height)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200274{
275 struct drm_fb *fb;
276 int ret;
277
278 struct drm_mode_create_dumb create_arg;
279 struct drm_mode_destroy_dumb destroy_arg;
280 struct drm_mode_map_dumb map_arg;
281
Peter Huttererf3d62272013-08-08 11:57:05 +1000282 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200283 if (!fb)
284 return NULL;
285
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700286 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200287 create_arg.bpp = 32;
288 create_arg.width = width;
289 create_arg.height = height;
290
Giulio Camuffo954f1832014-10-11 18:27:30 +0300291 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200292 if (ret)
293 goto err_fb;
294
295 fb->handle = create_arg.handle;
296 fb->stride = create_arg.pitch;
297 fb->size = create_arg.size;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300298 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200299
Giulio Camuffo954f1832014-10-11 18:27:30 +0300300 ret = drmModeAddFB(b->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200301 fb->stride, fb->handle, &fb->fb_id);
302 if (ret)
303 goto err_bo;
304
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700305 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200306 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400307 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200308 if (ret)
309 goto err_add_fb;
310
311 fb->map = mmap(0, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300312 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200313 if (fb->map == MAP_FAILED)
314 goto err_add_fb;
315
316 return fb;
317
318err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300319 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200320err_bo:
321 memset(&destroy_arg, 0, sizeof(destroy_arg));
322 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300323 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200324err_fb:
325 free(fb);
326 return NULL;
327}
328
329static void
330drm_fb_destroy_dumb(struct drm_fb *fb)
331{
332 struct drm_mode_destroy_dumb destroy_arg;
333
334 if (!fb->map)
335 return;
336
337 if (fb->fb_id)
338 drmModeRmFB(fb->fd, fb->fb_id);
339
340 weston_buffer_reference(&fb->buffer_ref, NULL);
341
342 munmap(fb->map, fb->size);
343
344 memset(&destroy_arg, 0, sizeof(destroy_arg));
345 destroy_arg.handle = fb->handle;
346 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
347
348 free(fb);
349}
350
351static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500352drm_fb_get_from_bo(struct gbm_bo *bo,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300353 struct drm_backend *backend, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354{
355 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200356 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200357 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300358 int ret;
359
360 if (fb)
361 return fb;
362
Bryce Harringtonde16d892014-11-20 22:21:57 -0800363 fb = zalloc(sizeof *fb);
364 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200365 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366
367 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368
369 width = gbm_bo_get_width(bo);
370 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200371 fb->stride = gbm_bo_get_stride(bo);
372 fb->handle = gbm_bo_get_handle(bo).u32;
373 fb->size = fb->stride * height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300374 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300375
Giulio Camuffo954f1832014-10-11 18:27:30 +0300376 if (backend->min_width > width || width > backend->max_width ||
377 backend->min_height > height ||
378 height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 weston_log("bo geometry out of bounds\n");
380 goto err_free;
381 }
382
383 ret = -1;
384
Giulio Camuffo954f1832014-10-11 18:27:30 +0300385 if (format && !backend->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200386 handles[0] = fb->handle;
387 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200388 offsets[0] = 0;
389
Giulio Camuffo954f1832014-10-11 18:27:30 +0300390 ret = drmModeAddFB2(backend->drm.fd, width, height,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200391 format, handles, pitches, offsets,
392 &fb->fb_id, 0);
393 if (ret) {
394 weston_log("addfb2 failed: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300395 backend->no_addfb2 = 1;
396 backend->sprites_are_broken = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397 }
398 }
399
400 if (ret)
Giulio Camuffo954f1832014-10-11 18:27:30 +0300401 ret = drmModeAddFB(backend->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200402 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200403
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200405 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200406 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300407 }
408
409 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
410
411 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200412
413err_free:
414 free(fb);
415 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300416}
417
418static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500419drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200420{
Pekka Paalanende685b82012-12-04 15:58:12 +0200421 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200422
423 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200424
Pekka Paalanende685b82012-12-04 15:58:12 +0200425 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200426}
427
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200428static void
429drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
430{
431 if (!fb)
432 return;
433
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200434 if (fb->map &&
435 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200436 drm_fb_destroy_dumb(fb);
437 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200438 if (fb->is_client_buffer)
439 gbm_bo_destroy(fb->bo);
440 else
441 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600442 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200443 }
444}
445
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500446static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200447drm_output_check_scanout_format(struct drm_output *output,
448 struct weston_surface *es, struct gbm_bo *bo)
449{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200450 uint32_t format;
451 pixman_region32_t r;
452
453 format = gbm_bo_get_format(bo);
454
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700455 if (format == GBM_FORMAT_ARGB8888) {
456 /* We can scanout an ARGB buffer if the surface's
457 * opaque region covers the whole output, but we have
458 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800459 pixman_region32_init_rect(&r, 0, 0,
460 output->base.width,
461 output->base.height);
462 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200463
464 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500465 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200466
467 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500468 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700469
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000470 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700471 return format;
472
473 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200474}
475
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400476static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200477drm_output_prepare_scanout_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500478 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500479{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300480 struct drm_backend *b =
481 (struct drm_backend *)output->base.compositor->backend;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500482 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200483 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300484 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500485 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500486
Jason Ekstranda7af7042013-10-12 22:38:11 -0500487 if (ev->geometry.x != output->base.x ||
488 ev->geometry.y != output->base.y ||
Giulio Camuffo954f1832014-10-11 18:27:30 +0300489 buffer == NULL || b->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200490 buffer->width != output->base.current_mode->width ||
491 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200492 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500493 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400494 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500495
Pekka Paalanen5580f222015-02-17 16:33:18 +0200496 if (ev->geometry.scissor_enabled)
497 return NULL;
498
Giulio Camuffo954f1832014-10-11 18:27:30 +0300499 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700500 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500501
Rob Bradford9b101872012-09-14 23:25:41 +0100502 /* Unable to use the buffer for scanout */
503 if (!bo)
504 return NULL;
505
Jason Ekstranda7af7042013-10-12 22:38:11 -0500506 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500507 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300508 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400509 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300510 }
511
Giulio Camuffo954f1832014-10-11 18:27:30 +0300512 output->next = drm_fb_get_from_bo(bo, b, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300513 if (!output->next) {
514 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400515 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300516 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500517
Pekka Paalanende685b82012-12-04 15:58:12 +0200518 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500519
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400520 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500521}
522
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500523static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200524drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400525{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300526 struct drm_backend *b =
527 (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300528 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400529
Giulio Camuffo954f1832014-10-11 18:27:30 +0300530 output->base.compositor->renderer->repaint_output(&output->base,
531 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400532
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300533 bo = gbm_surface_lock_front_buffer(output->surface);
534 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200535 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400536 return;
537 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300538
Giulio Camuffo954f1832014-10-11 18:27:30 +0300539 output->next = drm_fb_get_from_bo(bo, b, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300540 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200541 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300542 gbm_surface_release_buffer(output->surface, bo);
543 return;
544 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400545}
546
547static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200548drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
549{
550 struct weston_compositor *ec = output->base.compositor;
551 pixman_region32_t total_damage, previous_damage;
552
553 pixman_region32_init(&total_damage);
554 pixman_region32_init(&previous_damage);
555
556 pixman_region32_copy(&previous_damage, damage);
557
558 pixman_region32_union(&total_damage, damage, &output->previous_damage);
559 pixman_region32_copy(&output->previous_damage, &previous_damage);
560
561 output->current_image ^= 1;
562
563 output->next = output->dumb[output->current_image];
564 pixman_renderer_output_set_buffer(&output->base,
565 output->image[output->current_image]);
566
567 ec->renderer->repaint_output(&output->base, &total_damage);
568
569 pixman_region32_fini(&total_damage);
570 pixman_region32_fini(&previous_damage);
571}
572
573static void
574drm_output_render(struct drm_output *output, pixman_region32_t *damage)
575{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300576 struct weston_compositor *c = output->base.compositor;
577 struct drm_backend *b = (struct drm_backend *)c->backend;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200578
Giulio Camuffo954f1832014-10-11 18:27:30 +0300579 if (b->use_pixman)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200580 drm_output_render_pixman(output, damage);
581 else
582 drm_output_render_gl(output, damage);
583
Giulio Camuffo954f1832014-10-11 18:27:30 +0300584 pixman_region32_subtract(&c->primary_plane.damage,
585 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200586}
587
588static void
Richard Hughese7299962013-05-01 21:52:12 +0100589drm_output_set_gamma(struct weston_output *output_base,
590 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
591{
592 int rc;
593 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300594 struct drm_backend *backend =
595 (struct drm_backend *) output->base.compositor->backend;
Richard Hughese7299962013-05-01 21:52:12 +0100596
597 /* check */
598 if (output_base->gamma_size != size)
599 return;
600 if (!output->original_crtc)
601 return;
602
Giulio Camuffo954f1832014-10-11 18:27:30 +0300603 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +0100604 output->crtc_id,
605 size, r, g, b);
606 if (rc)
607 weston_log("set gamma failed: %m\n");
608}
609
Bryce Harringtonada4f072015-06-30 13:25:46 -0700610/* Determine the type of vblank synchronization to use for the output.
611 *
612 * The pipe parameter indicates which CRTC is in use. Knowing this, we
613 * can determine which vblank sequence type to use for it. Traditional
614 * cards had only two CRTCs, with CRTC 0 using no special flags, and
615 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
616 * parameter indicates this.
617 *
618 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
619 * 0-31. If this is non-zero it indicates we're dealing with a
620 * multi-gpu situation and we need to calculate the vblank sync
621 * using DRM_BLANK_HIGH_CRTC_MASK.
622 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +0300623static unsigned int
624drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200625{
626 if (output->pipe > 1)
627 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
628 DRM_VBLANK_HIGH_CRTC_MASK;
629 else if (output->pipe > 0)
630 return DRM_VBLANK_SECONDARY;
631 else
632 return 0;
633}
634
David Herrmann1edf44c2013-10-22 17:11:26 +0200635static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500636drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400637 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100638{
639 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300640 struct drm_backend *backend =
641 (struct drm_backend *)output->base.compositor->backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500642 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400643 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500644 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100645
Xiong Zhangabd5d472013-10-11 14:43:07 +0800646 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200647 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800648
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300649 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400650 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300651 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200652 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100653
Hardeningff39efa2013-09-18 23:56:35 +0200654 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200655 if (!output->current ||
656 output->current->stride != output->next->stride) {
Giulio Camuffo954f1832014-10-11 18:27:30 +0300657 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300658 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400659 &output->connector_id, 1,
660 &mode->mode_info);
661 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200662 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200663 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400664 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300665 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200666 }
667
Giulio Camuffo954f1832014-10-11 18:27:30 +0300668 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300669 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500670 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200671 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200672 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500673 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100674
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300675 output->page_flip_pending = 1;
676
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400677 drm_output_set_cursor(output);
678
Jesse Barnes58ef3792012-02-23 09:45:49 -0500679 /*
680 * Now, update all the sprite surfaces
681 */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300682 wl_list_for_each(s, &backend->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200683 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500684 drmVBlank vbl = {
685 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
686 .request.sequence = 1,
687 };
688
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200689 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200690 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500691 continue;
692
Giulio Camuffo954f1832014-10-11 18:27:30 +0300693 if (s->next && !backend->sprites_hidden)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200694 fb_id = s->next->fb_id;
695
Giulio Camuffo954f1832014-10-11 18:27:30 +0300696 ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200697 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500698 s->dest_x, s->dest_y,
699 s->dest_w, s->dest_h,
700 s->src_x, s->src_y,
701 s->src_w, s->src_h);
702 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200703 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500704 ret, strerror(errno));
705
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200706 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -0500707
Jesse Barnes58ef3792012-02-23 09:45:49 -0500708 /*
709 * Queue a vblank signal so we know when the surface
710 * becomes active on the display or has been replaced.
711 */
712 vbl.request.signal = (unsigned long)s;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300713 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500714 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200715 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500716 ret, strerror(errno));
717 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300718
719 s->output = output;
720 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500721 }
722
David Herrmann1edf44c2013-10-22 17:11:26 +0200723 return 0;
724
725err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800726 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200727 if (output->next) {
728 drm_output_release_fb(output, output->next);
729 output->next = NULL;
730 }
731
732 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400733}
734
735static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200736drm_output_start_repaint_loop(struct weston_output *output_base)
737{
738 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300739 struct drm_backend *backend = (struct drm_backend *)
740 output_base->compositor->backend;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200741 uint32_t fb_id;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200742 struct timespec ts, tnow;
743 struct timespec vbl2now;
744 int64_t refresh_nsec;
745 int ret;
746 drmVBlank vbl = {
747 .request.type = DRM_VBLANK_RELATIVE,
748 .request.sequence = 0,
749 .request.signal = 0,
750 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300751
Xiong Zhangabd5d472013-10-11 14:43:07 +0800752 if (output->destroy_pending)
753 return;
754
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300755 if (!output->current) {
756 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200757 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300758 }
759
Mario Kleinerf507ec32015-06-21 21:25:14 +0200760 /* Try to get current msc and timestamp via instant query */
761 vbl.request.type |= drm_waitvblank_pipe(output);
762 ret = drmWaitVBlank(backend->drm.fd, &vbl);
763
764 /* Error ret or zero timestamp means failure to get valid timestamp */
765 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
766 ts.tv_sec = vbl.reply.tval_sec;
767 ts.tv_nsec = vbl.reply.tval_usec * 1000;
768
769 /* Valid timestamp for most recent vblank - not stale?
770 * Stale ts could happen on Linux 3.17+, so make sure it
771 * is not older than 1 refresh duration since now.
772 */
773 weston_compositor_read_presentation_clock(backend->compositor,
774 &tnow);
775 timespec_sub(&vbl2now, &tnow, &ts);
776 refresh_nsec =
777 millihz_to_nsec(output->base.current_mode->refresh);
778 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
779 drm_output_update_msc(output, vbl.reply.sequence);
780 weston_output_finish_frame(output_base, &ts,
781 PRESENTATION_FEEDBACK_INVALID);
782 return;
783 }
784 }
785
786 /* Immediate query didn't provide valid timestamp.
787 * Use pageflip fallback.
788 */
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300789 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200790
Giulio Camuffo954f1832014-10-11 18:27:30 +0300791 if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
Jonas Ådahle5a12252013-04-05 23:07:11 +0200792 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
793 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200794 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200795 }
David Herrmann3c688c52013-10-22 17:11:25 +0200796
797 return;
798
799finish_frame:
800 /* if we cannot page-flip, immediately finish frame */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300801 weston_compositor_read_presentation_clock(output_base->compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200802 weston_output_finish_frame(output_base, &ts,
803 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200804}
805
806static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400807drm_output_update_msc(struct drm_output *output, unsigned int seq)
808{
809 uint64_t msc_hi = output->base.msc >> 32;
810
811 if (seq < (output->base.msc & 0xffffffff))
812 msc_hi++;
813
814 output->base.msc = (msc_hi << 32) + seq;
815}
816
817static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
819 void *data)
820{
821 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300822 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400823 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200824 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
825 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300826
Pekka Paalanen641307c2014-09-23 22:08:47 -0400827 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300828 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500829
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200830 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200831 s->current = s->next;
832 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300833
834 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400835 ts.tv_sec = sec;
836 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200837 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300838 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839}
840
841static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800842drm_output_destroy(struct weston_output *output_base);
843
844static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400845page_flip_handler(int fd, unsigned int frame,
846 unsigned int sec, unsigned int usec, void *data)
847{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200848 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400849 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200850 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
851 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
852 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400853
Pekka Paalanen641307c2014-09-23 22:08:47 -0400854 drm_output_update_msc(output, frame);
855
Jonas Ådahle5a12252013-04-05 23:07:11 +0200856 /* We don't set page_flip_pending on start_repaint_loop, in that case
857 * we just want to page flip to the current buffer to get an accurate
858 * timestamp */
859 if (output->page_flip_pending) {
860 drm_output_release_fb(output, output->current);
861 output->current = output->next;
862 output->next = NULL;
863 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300864
Jonas Ådahle5a12252013-04-05 23:07:11 +0200865 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400866
Xiong Zhangabd5d472013-10-11 14:43:07 +0800867 if (output->destroy_pending)
868 drm_output_destroy(&output->base);
869 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400870 ts.tv_sec = sec;
871 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200872 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300873
874 /* We can't call this from frame_notify, because the output's
875 * repaint needed flag is cleared just after that */
876 if (output->recorder)
877 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300878 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200879}
880
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500881static uint32_t
882drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500883 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500884{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500885 uint32_t i, format;
886
887 format = gbm_bo_get_format(bo);
888
889 if (format == GBM_FORMAT_ARGB8888) {
890 pixman_region32_t r;
891
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500892 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600893 ev->surface->width,
894 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500895 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500896
897 if (!pixman_region32_not_empty(&r))
898 format = GBM_FORMAT_XRGB8888;
899
900 pixman_region32_fini(&r);
901 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500902
903 for (i = 0; i < s->count_formats; i++)
904 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500905 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500906
907 return 0;
908}
909
910static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500911drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500912{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500913 return !ev->transform.enabled ||
914 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500915}
916
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400917static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200918drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500919 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500920{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200921 struct weston_compositor *ec = output->base.compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300922 struct drm_backend *b = (struct drm_backend *)ec->backend;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200923 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300924 struct wl_resource *buffer_resource;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925 struct drm_sprite *s;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300926 struct linux_dmabuf_buffer *dmabuf;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500927 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500928 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500929 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200930 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400932 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500933
Giulio Camuffo954f1832014-10-11 18:27:30 +0300934 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200935 return NULL;
936
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200937 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200938 return NULL;
939
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200940 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200941 return NULL;
942
Giulio Camuffo954f1832014-10-11 18:27:30 +0300943 if (b->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400944 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500945
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200946 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400947 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300948
Jason Ekstranda7af7042013-10-12 22:38:11 -0500949 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400950 return NULL;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300951 buffer_resource = ev->surface->buffer_ref.buffer->resource;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500952
Jason Ekstranda7af7042013-10-12 22:38:11 -0500953 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200954 return NULL;
955
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300956 if (wl_shm_buffer_get(buffer_resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500957 return NULL;
958
Jason Ekstranda7af7042013-10-12 22:38:11 -0500959 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400960 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500961
Giulio Camuffo954f1832014-10-11 18:27:30 +0300962 wl_list_for_each(s, &b->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200963 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500964 continue;
965
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200966 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500967 found = 1;
968 break;
969 }
970 }
971
972 /* No sprites available */
973 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400974 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500975
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300976 if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) {
Bryce Harringtona3582072015-08-14 12:23:13 -0700977#ifdef HAVE_GBM_FD_IMPORT
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300978 /* XXX: TODO:
979 *
980 * Use AddFB2 directly, do not go via GBM.
981 * Add support for multiplanar formats.
982 * Both require refactoring in the DRM-backend to
983 * support a mix of gbm_bos and drmfbs.
984 */
985 struct gbm_import_fd_data gbm_dmabuf = {
986 .fd = dmabuf->dmabuf_fd[0],
987 .width = dmabuf->width,
988 .height = dmabuf->height,
989 .stride = dmabuf->stride[0],
990 .format = dmabuf->format
991 };
992
993 if (dmabuf->n_planes != 1 || dmabuf->offset[0] != 0)
994 return NULL;
995
996 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
997 GBM_BO_USE_SCANOUT);
Bryce Harringtona3582072015-08-14 12:23:13 -0700998#else
999 return NULL;
1000#endif
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03001001 } else {
1002 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
1003 buffer_resource, GBM_BO_USE_SCANOUT);
1004 }
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -04001005 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001006 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -04001007
Jason Ekstranda7af7042013-10-12 22:38:11 -05001008 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001009 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001010 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001011 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001012 }
1013
Giulio Camuffo954f1832014-10-11 18:27:30 +03001014 s->next = drm_fb_get_from_bo(bo, b, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001015 if (!s->next) {
1016 gbm_bo_destroy(bo);
1017 return NULL;
1018 }
1019
Jason Ekstranda7af7042013-10-12 22:38:11 -05001020 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001021
Jason Ekstranda7af7042013-10-12 22:38:11 -05001022 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001023 s->plane.x = box->x1;
1024 s->plane.y = box->y1;
1025
Jesse Barnes58ef3792012-02-23 09:45:49 -05001026 /*
1027 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -05001028 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -05001029 * for us already).
1030 */
1031 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001032 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001033 &output->base.region);
1034 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001035 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001036 tbox = weston_transformed_rect(output->base.width,
1037 output->base.height,
1038 output->base.transform,
1039 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001040 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001041 s->dest_x = tbox.x1;
1042 s->dest_y = tbox.y1;
1043 s->dest_w = tbox.x2 - tbox.x1;
1044 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001045 pixman_region32_fini(&dest_rect);
1046
1047 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001048 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001049 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001050 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001051
Jason Ekstranda7af7042013-10-12 22:38:11 -05001052 weston_view_from_global_fixed(ev,
1053 wl_fixed_from_int(box->x1),
1054 wl_fixed_from_int(box->y1),
1055 &sx1, &sy1);
1056 weston_view_from_global_fixed(ev,
1057 wl_fixed_from_int(box->x2),
1058 wl_fixed_from_int(box->y2),
1059 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001060
1061 if (sx1 < 0)
1062 sx1 = 0;
1063 if (sy1 < 0)
1064 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001065 if (sx2 > wl_fixed_from_int(ev->surface->width))
1066 sx2 = wl_fixed_from_int(ev->surface->width);
1067 if (sy2 > wl_fixed_from_int(ev->surface->height))
1068 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001069
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001070 tbox.x1 = sx1;
1071 tbox.y1 = sy1;
1072 tbox.x2 = sx2;
1073 tbox.y2 = sy2;
1074
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001075 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
1076 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001077 viewport->buffer.transform,
1078 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01001079 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001080
1081 s->src_x = tbox.x1 << 8;
1082 s->src_y = tbox.y1 << 8;
1083 s->src_w = (tbox.x2 - tbox.x1) << 8;
1084 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001085 pixman_region32_fini(&src_rect);
1086
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001087 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001088}
1089
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001090static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001091drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001092 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001093{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001094 struct drm_backend *b =
1095 (struct drm_backend *)output->base.compositor->backend;
Neil Robertsf37f82c2014-05-01 18:00:41 +01001096 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001097
Giulio Camuffo954f1832014-10-11 18:27:30 +03001098 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001099 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +02001100 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1101 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001102 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001103 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001104 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001105 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001106 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001107 return NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001108 if (b->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001109 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001110 if (ev->geometry.scissor_enabled)
1111 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001112 if (ev->surface->buffer_ref.buffer == NULL ||
1113 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Daniel Stone70d337d2015-06-16 18:42:23 +01001114 ev->surface->width > b->cursor_width ||
1115 ev->surface->height > b->cursor_height)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001116 return NULL;
1117
Jason Ekstranda7af7042013-10-12 22:38:11 -05001118 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001119
1120 return &output->cursor_plane;
1121}
1122
Pekka Paalanend0ead482014-06-16 12:05:40 +03001123/**
1124 * Update the image for the current cursor surface
1125 *
1126 * @param b DRM backend structure
1127 * @param bo GBM buffer object to write into
1128 * @param ev View to use for cursor image
1129 */
1130static void
1131cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
1132 struct weston_view *ev)
1133{
1134 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
1135 uint32_t buf[b->cursor_width * b->cursor_height];
1136 int32_t stride;
1137 uint8_t *s;
1138 int i;
1139
1140 assert(buffer && buffer->shm_buffer);
1141 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
1142 assert(ev->surface->width <= b->cursor_width);
1143 assert(ev->surface->height <= b->cursor_height);
1144
1145 memset(buf, 0, sizeof buf);
1146 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1147 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1148
1149 wl_shm_buffer_begin_access(buffer->shm_buffer);
1150 for (i = 0; i < ev->surface->height; i++)
1151 memcpy(buf + i * b->cursor_width,
1152 s + i * stride,
1153 ev->surface->width * 4);
1154 wl_shm_buffer_end_access(buffer->shm_buffer);
1155
1156 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
1157 weston_log("failed update cursor: %m\n");
1158}
1159
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001160static void
1161drm_output_set_cursor(struct drm_output *output)
1162{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001163 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001164 struct weston_buffer *buffer;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001165 struct drm_backend *b =
1166 (struct drm_backend *) output->base.compositor->backend;
Pekka Paalanend0ead482014-06-16 12:05:40 +03001167 EGLint handle;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001168 struct gbm_bo *bo;
Pekka Paalanend0ead482014-06-16 12:05:40 +03001169 int x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001170
Jason Ekstranda7af7042013-10-12 22:38:11 -05001171 output->cursor_view = NULL;
1172 if (ev == NULL) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001173 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001174 return;
1175 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001176
Neil Robertse5051712013-11-13 15:44:06 +00001177 buffer = ev->surface->buffer_ref.buffer;
1178
1179 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001180 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001181 pixman_region32_fini(&output->cursor_plane.damage);
1182 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001183 output->current_cursor ^= 1;
1184 bo = output->cursor_bo[output->current_cursor];
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001185
Pekka Paalanend0ead482014-06-16 12:05:40 +03001186 cursor_bo_update(b, bo, ev);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001187 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001188 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
1189 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001190 weston_log("failed to set cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001191 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001192 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001193 }
1194
Jason Ekstranda7af7042013-10-12 22:38:11 -05001195 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1196 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001197 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001198 if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001199 weston_log("failed to move cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001200 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001201 }
1202
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001203 output->cursor_plane.x = x;
1204 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001205 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001206}
1207
Jesse Barnes58ef3792012-02-23 09:45:49 -05001208static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001209drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001210{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001211 struct drm_backend *b =
1212 (struct drm_backend *)output_base->compositor->backend;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001213 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001214 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001215 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001216 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001217
1218 /*
1219 * Find a surface for each sprite in the output using some heuristics:
1220 * 1) size
1221 * 2) frequency of update
1222 * 3) opacity (though some hw might support alpha blending)
1223 * 4) clipping (this can be fixed with color keys)
1224 *
1225 * The idea is to save on blitting since this should save power.
1226 * If we can get a large video surface on the sprite for example,
1227 * the main display surface may not need to update at all, and
1228 * the client buffer can be used directly for the sprite surface
1229 * as we do for flipping full screen surfaces.
1230 */
1231 pixman_region32_init(&overlap);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001232 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001233
Giulio Camuffo954f1832014-10-11 18:27:30 +03001234 wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001235 struct weston_surface *es = ev->surface;
1236
1237 /* Test whether this buffer can ever go into a plane:
1238 * non-shm, or small enough to be a cursor.
1239 *
1240 * Also, keep a reference when using the pixman renderer.
1241 * That makes it possible to do a seamless switch to the GL
1242 * renderer and since the pixman renderer keeps a reference
1243 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001244 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001245 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001246 (es->buffer_ref.buffer &&
1247 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001248 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001249 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001250 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001251 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001252
Jesse Barnes58ef3792012-02-23 09:45:49 -05001253 pixman_region32_init(&surface_overlap);
1254 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001255 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001256
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001257 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001258 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001259 next_plane = primary;
1260 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001261 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001262 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001263 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001264 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001265 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001266 if (next_plane == NULL)
1267 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001268
Jason Ekstranda7af7042013-10-12 22:38:11 -05001269 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001270
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001271 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001272 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001273 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001274
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001275 if (next_plane == primary ||
1276 next_plane == &output->cursor_plane) {
1277 /* cursor plane involves a copy */
1278 ev->psf_flags = 0;
1279 } else {
1280 /* All other planes are a direct scanout of a
1281 * single client buffer.
1282 */
1283 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1284 }
1285
Jesse Barnes58ef3792012-02-23 09:45:49 -05001286 pixman_region32_fini(&surface_overlap);
1287 }
1288 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001289}
1290
Matt Roper361d2ad2011-08-29 13:52:23 -07001291static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001292drm_output_fini_pixman(struct drm_output *output);
1293
1294static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001295drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001296{
1297 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001298 struct drm_backend *b =
1299 (struct drm_backend *)output->base.compositor->backend;
Matt Roper361d2ad2011-08-29 13:52:23 -07001300 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001301
Xiong Zhangabd5d472013-10-11 14:43:07 +08001302 if (output->page_flip_pending) {
1303 output->destroy_pending = 1;
1304 weston_log("destroy output while page flip pending\n");
1305 return;
1306 }
1307
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001308 if (output->backlight)
1309 backlight_destroy(output->backlight);
1310
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001311 drmModeFreeProperty(output->dpms_prop);
1312
Matt Roper361d2ad2011-08-29 13:52:23 -07001313 /* Turn off hardware cursor */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001314 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001315
1316 /* Restore original CRTC state */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001317 drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001318 origcrtc->x, origcrtc->y,
1319 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001320 drmModeFreeCrtc(origcrtc);
1321
Giulio Camuffo954f1832014-10-11 18:27:30 +03001322 b->crtc_allocator &= ~(1 << output->crtc_id);
1323 b->connector_allocator &= ~(1 << output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001324
Giulio Camuffo954f1832014-10-11 18:27:30 +03001325 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001326 drm_output_fini_pixman(output);
1327 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001328 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001329 gbm_surface_destroy(output->surface);
1330 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001331
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001332 weston_plane_release(&output->fb_plane);
1333 weston_plane_release(&output->cursor_plane);
1334
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001335 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001336
Matt Roper361d2ad2011-08-29 13:52:23 -07001337 free(output);
1338}
1339
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001340/**
1341 * Find the closest-matching mode for a given target
1342 *
1343 * Given a target mode, find the most suitable mode amongst the output's
1344 * current mode list to use, preferring the current mode if possible, to
1345 * avoid an expensive mode switch.
1346 *
1347 * @param output DRM output
1348 * @param target_mode Mode to attempt to match
1349 * @returns Pointer to a mode from the output's mode list
1350 */
Alex Wub7b8bda2012-04-17 17:20:48 +08001351static struct drm_mode *
1352choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1353{
1354 struct drm_mode *tmp_mode = NULL, *mode;
1355
Hardeningff39efa2013-09-18 23:56:35 +02001356 if (output->base.current_mode->width == target_mode->width &&
1357 output->base.current_mode->height == target_mode->height &&
1358 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001359 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001360 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001361
1362 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1363 if (mode->mode_info.hdisplay == target_mode->width &&
1364 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001365 if (mode->base.refresh == target_mode->refresh ||
1366 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001367 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001368 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001369 tmp_mode = mode;
1370 }
1371 }
1372
1373 return tmp_mode;
1374}
1375
1376static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001377drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001378static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001379drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001380
1381static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001382drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1383{
1384 struct drm_output *output;
1385 struct drm_mode *drm_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001386 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08001387
1388 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001389 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001390 return -1;
1391 }
1392
1393 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001394 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001395 return -1;
1396 }
1397
Giulio Camuffo954f1832014-10-11 18:27:30 +03001398 b = (struct drm_backend *)output_base->compositor->backend;
Alex Wub7b8bda2012-04-17 17:20:48 +08001399 output = (struct drm_output *)output_base;
1400 drm_mode = choose_mode (output, mode);
1401
1402 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001403 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001404 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001405 }
1406
Hardeningff39efa2013-09-18 23:56:35 +02001407 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001408 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001409
Hardeningff39efa2013-09-18 23:56:35 +02001410 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001411
Hardeningff39efa2013-09-18 23:56:35 +02001412 output->base.current_mode = &drm_mode->base;
1413 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001414 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1415
Alex Wub7b8bda2012-04-17 17:20:48 +08001416 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001417 drm_output_release_fb(output, output->current);
1418 drm_output_release_fb(output, output->next);
1419 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001420
Giulio Camuffo954f1832014-10-11 18:27:30 +03001421 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001422 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001423 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001424 weston_log("failed to init output pixman state with "
1425 "new mode\n");
1426 return -1;
1427 }
1428 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001429 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001430 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001431
Giulio Camuffo954f1832014-10-11 18:27:30 +03001432 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001433 weston_log("failed to init output egl state with "
1434 "new mode");
1435 return -1;
1436 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001437 }
1438
Alex Wub7b8bda2012-04-17 17:20:48 +08001439 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001440}
1441
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001442static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001443on_drm_input(int fd, uint32_t mask, void *data)
1444{
1445 drmEventContext evctx;
1446
1447 memset(&evctx, 0, sizeof evctx);
1448 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1449 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001450 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001451 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001452
1453 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001454}
1455
1456static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001457init_drm(struct drm_backend *b, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001458{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001459 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001460 uint64_t cap;
1461 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001462 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001463
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001464 sysnum = udev_device_get_sysnum(device);
1465 if (sysnum)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001466 b->drm.id = atoi(sysnum);
1467 if (!sysnum || b->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001468 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001469 return -1;
1470 }
1471
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001472 filename = udev_device_get_devnode(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001473 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001474 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001475 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001476 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001477 udev_device_get_devnode(device));
1478 return -1;
1479 }
1480
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001481 weston_log("using %s\n", filename);
1482
Giulio Camuffo954f1832014-10-11 18:27:30 +03001483 b->drm.fd = fd;
1484 b->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001485
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001486 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1487 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001488 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001489 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001490 clk_id = CLOCK_REALTIME;
1491
Giulio Camuffo954f1832014-10-11 18:27:30 +03001492 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001493 weston_log("Error: failed to set presentation clock %d.\n",
1494 clk_id);
1495 return -1;
1496 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001497
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001498 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1499 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001500 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001501 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001502 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001503
1504 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1505 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001506 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001507 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001508 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001509
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001510 return 0;
1511}
1512
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001513static struct gbm_device *
1514create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001515{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001516 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001517
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001518 gl_renderer = weston_load_module("gl-renderer.so",
1519 "gl_renderer_interface");
1520 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001521 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001522
1523 /* GBM will load a dri driver, but even though they need symbols from
1524 * libglapi, in some version of Mesa they are not linked to it. Since
1525 * only the gl-renderer module links to it, the call above won't make
1526 * these symbols globally available, and loading the DRI driver fails.
1527 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1528 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1529
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001530 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001531
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001532 return gbm;
1533}
1534
Bryce Harringtonc056a982015-05-19 15:25:18 -07001535/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001536 * we may be able to susbstitute an ARGB format for an XRGB one.
1537 *
1538 * This returns 0 if substitution isn't possible, but 0 might be a
1539 * legitimate format for other EGL platforms, so the caller is
1540 * responsible for checking for 0 before calling gl_renderer->create().
1541 *
1542 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1543 * but it's entirely possible we'll see this again on other implementations.
1544 */
1545static int
1546fallback_format_for(uint32_t format)
1547{
1548 switch (format) {
1549 case GBM_FORMAT_XRGB8888:
1550 return GBM_FORMAT_ARGB8888;
1551 case GBM_FORMAT_XRGB2101010:
1552 return GBM_FORMAT_ARGB2101010;
1553 default:
1554 return 0;
1555 }
1556}
1557
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001558static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001559drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001560{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001561 EGLint format[2] = {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001562 b->format,
1563 fallback_format_for(b->format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05001564 };
1565 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001566
Derek Foremanc4cfe852015-05-15 12:12:40 -05001567 if (format[1])
1568 n_formats = 2;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001569 if (gl_renderer->create(b->compositor,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001570 EGL_PLATFORM_GBM_KHR,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001571 (void *)b->gbm,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001572 gl_renderer->opaque_attribs,
1573 format,
1574 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001575 return -1;
1576 }
1577
1578 return 0;
1579}
1580
1581static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001582init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001583{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001584 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001585
Giulio Camuffo954f1832014-10-11 18:27:30 +03001586 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001587 return -1;
1588
Giulio Camuffo954f1832014-10-11 18:27:30 +03001589 if (drm_backend_create_gl_renderer(b) < 0) {
1590 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001591 return -1;
1592 }
1593
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001594 return 0;
1595}
1596
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001597static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001598init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001599{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001600 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001601}
1602
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001603/**
1604 * Add a mode to output's mode list
1605 *
1606 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
1607 * output's mode list.
1608 *
1609 * @param output DRM output to add mode to
1610 * @param info DRM mode structure to add
1611 * @returns Newly-allocated Weston/DRM mode structure
1612 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001613static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001614drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001615{
1616 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001617 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001618
1619 mode = malloc(sizeof *mode);
1620 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001621 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001622
1623 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001624 mode->base.width = info->hdisplay;
1625 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001626
1627 /* Calculate higher precision (mHz) refresh rate */
1628 refresh = (info->clock * 1000000LL / info->htotal +
1629 info->vtotal / 2) / info->vtotal;
1630
1631 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1632 refresh *= 2;
1633 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1634 refresh /= 2;
1635 if (info->vscan > 1)
1636 refresh /= info->vscan;
1637
1638 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001639 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001640
1641 if (info->type & DRM_MODE_TYPE_PREFERRED)
1642 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1643
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001644 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1645
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001646 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001647}
1648
1649static int
1650drm_subpixel_to_wayland(int drm_value)
1651{
1652 switch (drm_value) {
1653 default:
1654 case DRM_MODE_SUBPIXEL_UNKNOWN:
1655 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1656 case DRM_MODE_SUBPIXEL_NONE:
1657 return WL_OUTPUT_SUBPIXEL_NONE;
1658 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1659 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1660 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1661 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1662 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1663 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1664 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1665 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1666 }
1667}
1668
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001669/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001670static uint32_t
1671drm_get_backlight(struct drm_output *output)
1672{
1673 long brightness, max_brightness, norm;
1674
1675 brightness = backlight_get_brightness(output->backlight);
1676 max_brightness = backlight_get_max_brightness(output->backlight);
1677
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001678 /* convert it on a scale of 0 to 255 */
1679 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001680
1681 return (uint32_t) norm;
1682}
1683
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001684/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001685static void
1686drm_set_backlight(struct weston_output *output_base, uint32_t value)
1687{
1688 struct drm_output *output = (struct drm_output *) output_base;
1689 long max_brightness, new_brightness;
1690
1691 if (!output->backlight)
1692 return;
1693
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001694 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001695 return;
1696
1697 max_brightness = backlight_get_max_brightness(output->backlight);
1698
1699 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001700 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001701
1702 backlight_set_brightness(output->backlight, new_brightness);
1703}
1704
1705static drmModePropertyPtr
1706drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1707{
1708 drmModePropertyPtr props;
1709 int i;
1710
1711 for (i = 0; i < connector->count_props; i++) {
1712 props = drmModeGetProperty(fd, connector->props[i]);
1713 if (!props)
1714 continue;
1715
1716 if (!strcmp(props->name, name))
1717 return props;
1718
1719 drmModeFreeProperty(props);
1720 }
1721
1722 return NULL;
1723}
1724
1725static void
1726drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1727{
1728 struct drm_output *output = (struct drm_output *) output_base;
1729 struct weston_compositor *ec = output_base->compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001730 struct drm_backend *b = (struct drm_backend *)ec->backend;
Daniel Stone36609c72015-06-18 07:49:02 +01001731 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001732
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001733 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001734 return;
1735
Daniel Stone36609c72015-06-18 07:49:02 +01001736 ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
1737 output->dpms_prop->prop_id, level);
1738 if (ret) {
1739 weston_log("DRM: DPMS: failed property set for %s\n",
1740 output->base.name);
1741 return;
1742 }
1743
1744 output->dpms = level;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001745}
1746
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001747static const char * const connector_type_names[] = {
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001748 "None",
1749 "VGA",
1750 "DVI",
1751 "DVI",
1752 "DVI",
1753 "Composite",
1754 "TV",
1755 "LVDS",
1756 "CTV",
1757 "DIN",
1758 "DP",
1759 "HDMI",
1760 "HDMI",
1761 "TV",
1762 "eDP",
1763};
1764
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001765static char *
1766make_connector_name(const drmModeConnector *con)
1767{
1768 char name[32];
1769 const char *type_name;
1770
1771 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1772 type_name = connector_type_names[con->connector_type];
1773 else
1774 type_name = "UNKNOWN";
1775 snprintf(name, sizeof name, "%s%d", type_name, con->connector_type_id);
1776
1777 return strdup(name);
1778}
1779
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001780static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001781find_crtc_for_connector(struct drm_backend *b,
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001782 drmModeRes *resources, drmModeConnector *connector)
1783{
1784 drmModeEncoder *encoder;
1785 uint32_t possible_crtcs;
1786 int i, j;
1787
1788 for (j = 0; j < connector->count_encoders; j++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001789 encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001790 if (encoder == NULL) {
1791 weston_log("Failed to get encoder.\n");
1792 return -1;
1793 }
1794 possible_crtcs = encoder->possible_crtcs;
1795 drmModeFreeEncoder(encoder);
1796
1797 for (i = 0; i < resources->count_crtcs; i++) {
1798 if (possible_crtcs & (1 << i) &&
Giulio Camuffo954f1832014-10-11 18:27:30 +03001799 !(b->crtc_allocator & (1 << resources->crtcs[i])))
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001800 return i;
1801 }
1802 }
1803
1804 return -1;
1805}
1806
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001807/* Init output state that depends on gl or gbm */
1808static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001809drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001810{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001811 EGLint format[2] = {
1812 output->format,
1813 fallback_format_for(output->format),
1814 };
1815 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001816
Giulio Camuffo954f1832014-10-11 18:27:30 +03001817 output->surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001818 output->base.current_mode->width,
1819 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001820 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001821 GBM_BO_USE_SCANOUT |
1822 GBM_BO_USE_RENDERING);
1823 if (!output->surface) {
1824 weston_log("failed to create gbm surface\n");
1825 return -1;
1826 }
1827
Derek Foremanc4cfe852015-05-15 12:12:40 -05001828 if (format[1])
1829 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001830 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001831 (EGLNativeDisplayType)output->surface,
1832 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001833 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001834 format,
1835 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001836 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001837 gbm_surface_destroy(output->surface);
1838 return -1;
1839 }
1840
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001841 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001842
1843 for (i = 0; i < 2; i++) {
1844 if (output->cursor_bo[i])
1845 continue;
1846
1847 output->cursor_bo[i] =
Giulio Camuffo954f1832014-10-11 18:27:30 +03001848 gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001849 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001850 }
1851
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001852 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1853 weston_log("cursor buffers unavailable, using gl cursors\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001854 b->cursors_are_broken = 1;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001855 }
1856
1857 return 0;
1858}
1859
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001860static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001861drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001862{
Hardeningff39efa2013-09-18 23:56:35 +02001863 int w = output->base.current_mode->width;
1864 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001865 unsigned int i;
1866
1867 /* FIXME error checking */
1868
1869 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001870 output->dumb[i] = drm_fb_create_dumb(b, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001871 if (!output->dumb[i])
1872 goto err;
1873
1874 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001875 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001876 output->dumb[i]->map,
1877 output->dumb[i]->stride);
1878 if (!output->image[i])
1879 goto err;
1880 }
1881
1882 if (pixman_renderer_output_create(&output->base) < 0)
1883 goto err;
1884
1885 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001886 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001887
1888 return 0;
1889
1890err:
1891 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1892 if (output->dumb[i])
1893 drm_fb_destroy_dumb(output->dumb[i]);
1894 if (output->image[i])
1895 pixman_image_unref(output->image[i]);
1896
1897 output->dumb[i] = NULL;
1898 output->image[i] = NULL;
1899 }
1900
1901 return -1;
1902}
1903
1904static void
1905drm_output_fini_pixman(struct drm_output *output)
1906{
1907 unsigned int i;
1908
1909 pixman_renderer_output_destroy(&output->base);
1910 pixman_region32_fini(&output->previous_damage);
1911
1912 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1913 drm_fb_destroy_dumb(output->dumb[i]);
1914 pixman_image_unref(output->image[i]);
1915 output->dumb[i] = NULL;
1916 output->image[i] = NULL;
1917 }
1918}
1919
Richard Hughes2b2092a2013-04-24 14:58:02 +01001920static void
1921edid_parse_string(const uint8_t *data, char text[])
1922{
1923 int i;
1924 int replaced = 0;
1925
1926 /* this is always 12 bytes, but we can't guarantee it's null
1927 * terminated or not junk. */
1928 strncpy(text, (const char *) data, 12);
1929
1930 /* remove insane chars */
1931 for (i = 0; text[i] != '\0'; i++) {
1932 if (text[i] == '\n' ||
1933 text[i] == '\r') {
1934 text[i] = '\0';
1935 break;
1936 }
1937 }
1938
1939 /* ensure string is printable */
1940 for (i = 0; text[i] != '\0'; i++) {
1941 if (!isprint(text[i])) {
1942 text[i] = '-';
1943 replaced++;
1944 }
1945 }
1946
1947 /* if the string is random junk, ignore the string */
1948 if (replaced > 4)
1949 text[0] = '\0';
1950}
1951
1952#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1953#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1954#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1955#define EDID_OFFSET_DATA_BLOCKS 0x36
1956#define EDID_OFFSET_LAST_BLOCK 0x6c
1957#define EDID_OFFSET_PNPID 0x08
1958#define EDID_OFFSET_SERIAL 0x0c
1959
1960static int
1961edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1962{
1963 int i;
1964 uint32_t serial_number;
1965
1966 /* check header */
1967 if (length < 128)
1968 return -1;
1969 if (data[0] != 0x00 || data[1] != 0xff)
1970 return -1;
1971
1972 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1973 * /--08--\/--09--\
1974 * 7654321076543210
1975 * |\---/\---/\---/
1976 * R C1 C2 C3 */
1977 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1978 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1979 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1980 edid->pnp_id[3] = '\0';
1981
1982 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1983 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1984 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1985 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1986 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1987 if (serial_number > 0)
1988 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1989
1990 /* parse EDID data */
1991 for (i = EDID_OFFSET_DATA_BLOCKS;
1992 i <= EDID_OFFSET_LAST_BLOCK;
1993 i += 18) {
1994 /* ignore pixel clock data */
1995 if (data[i] != 0)
1996 continue;
1997 if (data[i+2] != 0)
1998 continue;
1999
2000 /* any useful blocks? */
2001 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
2002 edid_parse_string(&data[i+5],
2003 edid->monitor_name);
2004 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
2005 edid_parse_string(&data[i+5],
2006 edid->serial_number);
2007 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
2008 edid_parse_string(&data[i+5],
2009 edid->eisa_id);
2010 }
2011 }
2012 return 0;
2013}
2014
2015static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002016find_and_parse_output_edid(struct drm_backend *b,
Richard Hughes2b2092a2013-04-24 14:58:02 +01002017 struct drm_output *output,
2018 drmModeConnector *connector)
2019{
2020 drmModePropertyBlobPtr edid_blob = NULL;
2021 drmModePropertyPtr property;
2022 int i;
2023 int rc;
2024
2025 for (i = 0; i < connector->count_props && !edid_blob; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002026 property = drmModeGetProperty(b->drm.fd, connector->props[i]);
Richard Hughes2b2092a2013-04-24 14:58:02 +01002027 if (!property)
2028 continue;
2029 if ((property->flags & DRM_MODE_PROP_BLOB) &&
2030 !strcmp(property->name, "EDID")) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002031 edid_blob = drmModeGetPropertyBlob(b->drm.fd,
Richard Hughes2b2092a2013-04-24 14:58:02 +01002032 connector->prop_values[i]);
2033 }
2034 drmModeFreeProperty(property);
2035 }
2036 if (!edid_blob)
2037 return;
2038
2039 rc = edid_parse(&output->edid,
2040 edid_blob->data,
2041 edid_blob->length);
2042 if (!rc) {
2043 weston_log("EDID data '%s', '%s', '%s'\n",
2044 output->edid.pnp_id,
2045 output->edid.monitor_name,
2046 output->edid.serial_number);
2047 if (output->edid.pnp_id[0] != '\0')
2048 output->base.make = output->edid.pnp_id;
2049 if (output->edid.monitor_name[0] != '\0')
2050 output->base.model = output->edid.monitor_name;
2051 if (output->edid.serial_number[0] != '\0')
2052 output->base.serial_number = output->edid.serial_number;
2053 }
2054 drmModeFreePropertyBlob(edid_blob);
2055}
2056
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002057
2058
2059static int
2060parse_modeline(const char *s, drmModeModeInfo *mode)
2061{
2062 char hsync[16];
2063 char vsync[16];
2064 float fclock;
2065
2066 mode->type = DRM_MODE_TYPE_USERDEF;
2067 mode->hskew = 0;
2068 mode->vscan = 0;
2069 mode->vrefresh = 0;
2070 mode->flags = 0;
2071
Rob Bradford307e09e2013-07-26 16:29:40 +01002072 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002073 &fclock,
2074 &mode->hdisplay,
2075 &mode->hsync_start,
2076 &mode->hsync_end,
2077 &mode->htotal,
2078 &mode->vdisplay,
2079 &mode->vsync_start,
2080 &mode->vsync_end,
2081 &mode->vtotal, hsync, vsync) != 11)
2082 return -1;
2083
2084 mode->clock = fclock * 1000;
2085 if (strcmp(hsync, "+hsync") == 0)
2086 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2087 else if (strcmp(hsync, "-hsync") == 0)
2088 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2089 else
2090 return -1;
2091
2092 if (strcmp(vsync, "+vsync") == 0)
2093 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2094 else if (strcmp(vsync, "-vsync") == 0)
2095 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2096 else
2097 return -1;
2098
2099 return 0;
2100}
2101
Rob Bradford66bd9f52013-06-25 18:56:42 +01002102static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002103setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01002104 struct weston_output *output,
2105 const char *s)
2106{
2107 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05002108 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01002109 struct udev_seat *seat;
2110
Giulio Camuffo954f1832014-10-11 18:27:30 +03002111 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05002112 if (!seat)
2113 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01002114
Derek Foreman0720ea32015-07-15 13:00:35 -05002115 seat->base.output = output;
2116
Derek Foreman1281a362015-07-31 16:55:32 -05002117 pointer = weston_seat_get_pointer(&seat->base);
2118 if (pointer)
2119 weston_pointer_clamp(pointer,
2120 &pointer->x,
2121 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002122 }
2123}
2124
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002125static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002126get_gbm_format_from_section(struct weston_config_section *section,
2127 uint32_t default_value,
2128 uint32_t *format)
2129{
2130 char *s;
2131 int ret = 0;
2132
2133 weston_config_section_get_string(section,
2134 "gbm-format", &s, NULL);
2135
2136 if (s == NULL)
2137 *format = default_value;
2138 else if (strcmp(s, "xrgb8888") == 0)
2139 *format = GBM_FORMAT_XRGB8888;
2140 else if (strcmp(s, "rgb565") == 0)
2141 *format = GBM_FORMAT_RGB565;
2142 else if (strcmp(s, "xrgb2101010") == 0)
2143 *format = GBM_FORMAT_XRGB2101010;
2144 else {
2145 weston_log("fatal: unrecognized pixel format: %s\n", s);
2146 ret = -1;
2147 }
2148
2149 free(s);
2150
2151 return ret;
2152}
2153
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002154/**
2155 * Choose suitable mode for an output
2156 *
2157 * Find the most suitable mode to use for initial setup (or reconfiguration on
2158 * hotplug etc) for a DRM output.
2159 *
2160 * @param output DRM output to choose mode for
2161 * @param kind Strategy and preference to use when choosing mode
2162 * @param width Desired width for this output
2163 * @param height Desired height for this output
2164 * @param current_mode Mode currently being displayed on this output
2165 * @param modeline Manually-entered mode (may be NULL)
2166 * @returns A mode from the output's mode list, or NULL if none available
2167 */
2168static struct drm_mode *
2169drm_output_choose_initial_mode(struct drm_output *output,
2170 enum output_config kind,
2171 int width, int height,
2172 const drmModeModeInfo *current_mode,
2173 const drmModeModeInfo *modeline)
2174{
2175 struct drm_mode *preferred = NULL;
2176 struct drm_mode *current = NULL;
2177 struct drm_mode *configured = NULL;
2178 struct drm_mode *best = NULL;
2179 struct drm_mode *drm_mode;
2180
2181 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
2182 if (kind == OUTPUT_CONFIG_MODE &&
2183 width == drm_mode->base.width &&
2184 height == drm_mode->base.height)
2185 configured = drm_mode;
2186
2187 if (memcmp(&current_mode, &drm_mode->mode_info,
2188 sizeof *current_mode) == 0)
2189 current = drm_mode;
2190
2191 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
2192 preferred = drm_mode;
2193
2194 best = drm_mode;
2195 }
2196
2197 if (kind == OUTPUT_CONFIG_MODELINE) {
2198 configured = drm_output_add_mode(output, modeline);
2199 if (!configured)
2200 return NULL;
2201 }
2202
2203 if (current == NULL && current_mode->clock != 0) {
2204 current = drm_output_add_mode(output, current_mode);
2205 if (!current)
2206 return NULL;
2207 }
2208
2209 if (kind == OUTPUT_CONFIG_CURRENT)
2210 configured = current;
2211
2212 if (option_current_mode && current)
2213 return current;
2214
2215 if (configured)
2216 return configured;
2217
2218 if (preferred)
2219 return preferred;
2220
2221 if (current)
2222 return current;
2223
2224 if (best)
2225 return best;
2226
2227 weston_log("no available modes for %s\n", output->base.name);
2228 return NULL;
2229}
2230
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002231static int
2232connector_get_current_mode(drmModeConnector *connector, int drm_fd,
2233 drmModeModeInfo *mode)
2234{
2235 drmModeEncoder *encoder;
2236 drmModeCrtc *crtc;
2237
2238 /* Get the current mode on the crtc that's currently driving
2239 * this connector. */
2240 encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
2241 memset(mode, 0, sizeof *mode);
2242 if (encoder != NULL) {
2243 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
2244 drmModeFreeEncoder(encoder);
2245 if (crtc == NULL)
2246 return -1;
2247 if (crtc->mode_valid)
2248 *mode = crtc->mode;
2249 drmModeFreeCrtc(crtc);
2250 }
2251
2252 return 0;
2253}
2254
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002255/**
2256 * Create and configure a Weston output structure
2257 *
2258 * Given a DRM connector, create a matching drm_output structure and add it
2259 * to Weston's output list.
2260 *
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002261 * @param b Weston backend structure structure
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002262 * @param resources DRM resources for this device
2263 * @param connector DRM connector to use for this new output
2264 * @param x Horizontal offset to use into global co-ordinate space
2265 * @param y Vertical offset to use into global co-ordinate space
2266 * @param drm_device udev device pointer
2267 * @returns 0 on success, or -1 on failure
2268 */
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002269static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002270create_output_for_connector(struct drm_backend *b,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002271 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002272 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002273 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002274{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002275 struct drm_output *output;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002276 struct drm_mode *drm_mode, *next, *current;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002277 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002278 struct weston_config_section *section;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002279 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002280 int i, width, height, scale;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002281 char *s;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002282 enum output_config config;
2283 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002284
Giulio Camuffo954f1832014-10-11 18:27:30 +03002285 i = find_crtc_for_connector(b, resources, connector);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002286 if (i < 0) {
2287 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002288 return -1;
2289 }
2290
Peter Huttererf3d62272013-08-08 11:57:05 +10002291 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002292 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002293 return -1;
2294
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002295 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002296 output->base.name = make_connector_name(connector);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002297 output->base.make = "unknown";
2298 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002299 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002300 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002301
Giulio Camuffo954f1832014-10-11 18:27:30 +03002302 section = weston_config_get_section(b->compositor->config, "output", "name",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002303 output->base.name);
2304 weston_config_section_get_string(section, "mode", &s, "preferred");
2305 if (strcmp(s, "off") == 0)
2306 config = OUTPUT_CONFIG_OFF;
2307 else if (strcmp(s, "preferred") == 0)
2308 config = OUTPUT_CONFIG_PREFERRED;
2309 else if (strcmp(s, "current") == 0)
2310 config = OUTPUT_CONFIG_CURRENT;
2311 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2312 config = OUTPUT_CONFIG_MODE;
2313 else if (parse_modeline(s, &modeline) == 0)
2314 config = OUTPUT_CONFIG_MODELINE;
2315 else {
2316 weston_log("Invalid mode \"%s\" for output %s\n",
2317 s, output->base.name);
2318 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002319 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002320 free(s);
2321
2322 weston_config_section_get_int(section, "scale", &scale, 1);
2323 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002324 if (weston_parse_transform(s, &transform) < 0)
2325 weston_log("Invalid transform \"%s\" for output %s\n",
2326 s, output->base.name);
2327
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002328 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002329
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002330 if (get_gbm_format_from_section(section,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002331 b->format,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002332 &output->format) == -1)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002333 output->format = b->format;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002334
Rob Bradford66bd9f52013-06-25 18:56:42 +01002335 weston_config_section_get_string(section, "seat", &s, "");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002336 setup_output_seat_constraint(b, &output->base, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002337 free(s);
2338
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002339 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002340 output->pipe = i;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002341 b->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002342 output->connector_id = connector->connector_id;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002343 b->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002344
Giulio Camuffo954f1832014-10-11 18:27:30 +03002345 output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
2346 output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002347
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002348 if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
2349 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002350
David Herrmann0f0d54e2011-12-08 17:05:45 +01002351 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002352 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002353 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002354 goto err_free;
2355 }
2356
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002357 if (config == OUTPUT_CONFIG_OFF) {
2358 weston_log("Disabling output %s\n", output->base.name);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002359 drmModeSetCrtc(b->drm.fd, output->crtc_id,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002360 0, 0, 0, 0, 0, NULL);
2361 goto err_free;
2362 }
2363
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002364 current = drm_output_choose_initial_mode(output, config,
2365 width, height,
2366 &crtc_mode, &modeline);
2367 if (!current)
Wang Quanxianacb805a2012-07-30 18:09:46 -04002368 goto err_free;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002369 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02002370 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002371
Giulio Camuffo954f1832014-10-11 18:27:30 +03002372 weston_output_init(&output->base, b->compositor, x, y,
John Kåre Alsaker94659272012-11-13 19:10:18 +01002373 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002374 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002375
Giulio Camuffo954f1832014-10-11 18:27:30 +03002376 if (b->use_pixman) {
2377 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002378 weston_log("Failed to init output pixman state\n");
2379 goto err_output;
2380 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03002381 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002382 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002383 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002384 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002385
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002386 output->backlight = backlight_init(drm_device,
2387 connector->connector_type);
2388 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002389 weston_log("Initialized backlight, device %s\n",
2390 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002391 output->base.set_backlight = drm_set_backlight;
2392 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002393 } else {
2394 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002395 }
2396
Giulio Camuffo954f1832014-10-11 18:27:30 +03002397 weston_compositor_add_output(b->compositor, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002398
Giulio Camuffo954f1832014-10-11 18:27:30 +03002399 find_and_parse_output_edid(b, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002400 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2401 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002402
Jonas Ådahle5a12252013-04-05 23:07:11 +02002403 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002404 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002405 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002406 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002407 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002408 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002409
Richard Hughese7299962013-05-01 21:52:12 +01002410 output->base.gamma_size = output->original_crtc->gamma_size;
2411 output->base.set_gamma = drm_output_set_gamma;
2412
Giulio Camuffo954f1832014-10-11 18:27:30 +03002413 weston_plane_init(&output->cursor_plane, b->compositor, 0, 0);
2414 weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002415
Giulio Camuffo954f1832014-10-11 18:27:30 +03002416 weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
2417 weston_compositor_stack_plane(b->compositor, &output->fb_plane,
2418 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002419
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002420 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002421 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002422 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002423 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002424 m->width, m->height, m->refresh / 1000.0,
2425 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2426 ", preferred" : "",
2427 m->flags & WL_OUTPUT_MODE_CURRENT ?
2428 ", current" : "",
2429 connector->count_modes == 0 ?
2430 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002431
Mario Kleiner80817042015-06-21 21:25:11 +02002432 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2433 output->base.native_mode = output->base.current_mode;
2434 output->base.native_scale = output->base.current_scale;
2435
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002436 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002437
John Kåre Alsaker94659272012-11-13 19:10:18 +01002438err_output:
2439 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002440err_free:
2441 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2442 base.link) {
2443 wl_list_remove(&drm_mode->base.link);
2444 free(drm_mode);
2445 }
2446
2447 drmModeFreeCrtc(output->original_crtc);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002448 b->crtc_allocator &= ~(1 << output->crtc_id);
2449 b->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002450 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002451
David Herrmann0f0d54e2011-12-08 17:05:45 +01002452 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002453}
2454
Jesse Barnes58ef3792012-02-23 09:45:49 -05002455static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002456create_sprites(struct drm_backend *b)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002457{
2458 struct drm_sprite *sprite;
2459 drmModePlaneRes *plane_res;
2460 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002461 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002462
Giulio Camuffo954f1832014-10-11 18:27:30 +03002463 plane_res = drmModeGetPlaneResources(b->drm.fd);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002464 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002465 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002466 strerror(errno));
2467 return;
2468 }
2469
2470 for (i = 0; i < plane_res->count_planes; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002471 plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002472 if (!plane)
2473 continue;
2474
Peter Huttererf3d62272013-08-08 11:57:05 +10002475 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002476 plane->count_formats));
2477 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002478 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002479 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002480 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002481 continue;
2482 }
2483
Jesse Barnes58ef3792012-02-23 09:45:49 -05002484 sprite->possible_crtcs = plane->possible_crtcs;
2485 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002486 sprite->current = NULL;
2487 sprite->next = NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002488 sprite->backend = b;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002489 sprite->count_formats = plane->count_formats;
2490 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002491 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002492 drmModeFreePlane(plane);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002493 weston_plane_init(&sprite->plane, b->compositor, 0, 0);
2494 weston_compositor_stack_plane(b->compositor, &sprite->plane,
2495 &b->compositor->primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002496
Giulio Camuffo954f1832014-10-11 18:27:30 +03002497 wl_list_insert(&b->sprite_list, &sprite->link);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002498 }
2499
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002500 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002501}
2502
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002503static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002504destroy_sprites(struct drm_backend *backend)
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002505{
2506 struct drm_sprite *sprite, *next;
2507 struct drm_output *output;
2508
Giulio Camuffo954f1832014-10-11 18:27:30 +03002509 output = container_of(backend->compositor->output_list.next,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002510 struct drm_output, base.link);
2511
Giulio Camuffo954f1832014-10-11 18:27:30 +03002512 wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
2513 drmModeSetPlane(backend->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002514 sprite->plane_id,
2515 output->crtc_id, 0, 0,
2516 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002517 drm_output_release_fb(output, sprite->current);
2518 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002519 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002520 free(sprite);
2521 }
2522}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002523
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002524static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002525create_outputs(struct drm_backend *b, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002526 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002527{
2528 drmModeConnector *connector;
2529 drmModeRes *resources;
2530 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002531 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002532
Giulio Camuffo954f1832014-10-11 18:27:30 +03002533 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002534 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002535 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002536 return -1;
2537 }
2538
Giulio Camuffo954f1832014-10-11 18:27:30 +03002539 b->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
2540 if (!b->crtcs) {
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002541 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002542 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002543 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002544
Giulio Camuffo954f1832014-10-11 18:27:30 +03002545 b->min_width = resources->min_width;
2546 b->max_width = resources->max_width;
2547 b->min_height = resources->min_height;
2548 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002549
Giulio Camuffo954f1832014-10-11 18:27:30 +03002550 b->num_crtcs = resources->count_crtcs;
2551 memcpy(b->crtcs, resources->crtcs, sizeof(uint32_t) * b->num_crtcs);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002552
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002553 for (i = 0; i < resources->count_connectors; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002554 connector = drmModeGetConnector(b->drm.fd,
Benjamin Franzke117483d2011-08-30 11:38:26 +02002555 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002556 if (connector == NULL)
2557 continue;
2558
2559 if (connector->connection == DRM_MODE_CONNECTED &&
2560 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002561 connector->connector_id == option_connector)) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002562 if (create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002563 connector, x, y,
2564 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002565 drmModeFreeConnector(connector);
2566 continue;
2567 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002568
Giulio Camuffo954f1832014-10-11 18:27:30 +03002569 x += container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002570 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002571 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002572 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002573
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002574 drmModeFreeConnector(connector);
2575 }
2576
Giulio Camuffo954f1832014-10-11 18:27:30 +03002577 if (wl_list_empty(&b->compositor->output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002578 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002579 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002580 return -1;
2581 }
2582
2583 drmModeFreeResources(resources);
2584
2585 return 0;
2586}
2587
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002588static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002589update_outputs(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002590{
2591 drmModeConnector *connector;
2592 drmModeRes *resources;
2593 struct drm_output *output, *next;
2594 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002595 uint32_t connected = 0, disconnects = 0;
2596 int i;
2597
Giulio Camuffo954f1832014-10-11 18:27:30 +03002598 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002599 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002600 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002601 return;
2602 }
2603
2604 /* collect new connects */
2605 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002606 int connector_id = resources->connectors[i];
2607
Giulio Camuffo954f1832014-10-11 18:27:30 +03002608 connector = drmModeGetConnector(b->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002609 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002610 continue;
2611
David Herrmann7551cff2011-12-08 17:05:43 +01002612 if (connector->connection != DRM_MODE_CONNECTED) {
2613 drmModeFreeConnector(connector);
2614 continue;
2615 }
2616
Benjamin Franzke117483d2011-08-30 11:38:26 +02002617 connected |= (1 << connector_id);
2618
Giulio Camuffo954f1832014-10-11 18:27:30 +03002619 if (!(b->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002620 struct weston_output *last =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002621 container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002622 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002623
2624 /* XXX: not yet needed, we die with 0 outputs */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002625 if (!wl_list_empty(&b->compositor->output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002626 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002627 else
2628 x = 0;
2629 y = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002630 create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002631 connector, x, y,
2632 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002633 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002634
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002635 }
2636 drmModeFreeConnector(connector);
2637 }
2638 drmModeFreeResources(resources);
2639
Giulio Camuffo954f1832014-10-11 18:27:30 +03002640 disconnects = b->connector_allocator & ~connected;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002641 if (disconnects) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002642 wl_list_for_each_safe(output, next, &b->compositor->output_list,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002643 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002644 if (disconnects & (1 << output->connector_id)) {
2645 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002646 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002647 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002648 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002649 }
2650 }
2651 }
2652
Daniel Stonef556ebe2015-05-21 08:28:58 +01002653 /* FIXME: handle zero outputs, without terminating */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002654 if (b->connector_allocator == 0)
Giulio Camuffo459137b2014-10-11 23:56:24 +03002655 weston_compositor_exit(b->compositor);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002656}
2657
2658static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002659udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002660{
David Herrmannd7488c22012-03-11 20:05:21 +01002661 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002662 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002663
2664 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002665 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002666 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002667
David Herrmann6ac52db2012-03-11 20:05:22 +01002668 val = udev_device_get_property_value(device, "HOTPLUG");
2669 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002670 return 0;
2671
David Herrmann6ac52db2012-03-11 20:05:22 +01002672 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002673}
2674
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002675static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002676udev_drm_event(int fd, uint32_t mask, void *data)
2677{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002678 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002679 struct udev_device *event;
2680
Giulio Camuffo954f1832014-10-11 18:27:30 +03002681 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002682
Giulio Camuffo954f1832014-10-11 18:27:30 +03002683 if (udev_event_is_hotplug(b, event))
2684 update_outputs(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002685
2686 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002687
2688 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002689}
2690
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002691static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002692drm_restore(struct weston_compositor *ec)
2693{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002694 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002695}
2696
2697static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002698drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002699{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002700 struct drm_backend *b = (struct drm_backend *) ec->backend;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002701
Giulio Camuffo954f1832014-10-11 18:27:30 +03002702 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002703
Giulio Camuffo954f1832014-10-11 18:27:30 +03002704 wl_event_source_remove(b->udev_drm_source);
2705 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002706
Giulio Camuffo954f1832014-10-11 18:27:30 +03002707 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002708
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002709 weston_compositor_shutdown(ec);
2710
Giulio Camuffo954f1832014-10-11 18:27:30 +03002711 if (b->gbm)
2712 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002713
Giulio Camuffo954f1832014-10-11 18:27:30 +03002714 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002715
Giulio Camuffo954f1832014-10-11 18:27:30 +03002716 close(b->drm.fd);
Rob Bradford45c15b82013-07-26 16:29:35 +01002717
Giulio Camuffo954f1832014-10-11 18:27:30 +03002718 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002719}
2720
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002721static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002722drm_backend_set_modes(struct drm_backend *backend)
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002723{
2724 struct drm_output *output;
2725 struct drm_mode *drm_mode;
2726 int ret;
2727
Giulio Camuffo954f1832014-10-11 18:27:30 +03002728 wl_list_for_each(output, &backend->compositor->output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002729 if (!output->current) {
2730 /* If something that would cause the output to
2731 * switch mode happened while in another vt, we
2732 * might not have a current drm_fb. In that case,
2733 * schedule a repaint and let drm_output_repaint
2734 * handle setting the mode. */
2735 weston_output_schedule_repaint(&output->base);
2736 continue;
2737 }
2738
Hardeningff39efa2013-09-18 23:56:35 +02002739 drm_mode = (struct drm_mode *) output->base.current_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002740 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002741 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002742 &output->connector_id, 1,
2743 &drm_mode->mode_info);
2744 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002745 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002746 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002747 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002748 output->base.x, output->base.y);
2749 }
2750 }
2751}
2752
2753static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002754session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002755{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002756 struct weston_compositor *compositor = data;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002757 struct drm_backend *b = (struct drm_backend *)compositor->backend;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002758 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002759 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002760
Giulio Camuffo954f1832014-10-11 18:27:30 +03002761 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002762 weston_log("activating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002763 compositor->state = b->prev_state;
2764 drm_backend_set_modes(b);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002765 weston_compositor_damage_all(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002766 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002767 } else {
2768 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002769 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002770
Giulio Camuffo954f1832014-10-11 18:27:30 +03002771 b->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002772 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002773
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002774 /* If we have a repaint scheduled (either from a
2775 * pending pageflip or the idle handler), make sure we
2776 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002777 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002778 * further attemps at repainting. When we switch
2779 * back, we schedule a repaint, which will process
2780 * pending frame callbacks. */
2781
Giulio Camuffo954f1832014-10-11 18:27:30 +03002782 wl_list_for_each(output, &compositor->output_list, base.link) {
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002783 output->base.repaint_needed = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002784 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002785 }
2786
Giulio Camuffo954f1832014-10-11 18:27:30 +03002787 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002788 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002789
Giulio Camuffo954f1832014-10-11 18:27:30 +03002790 wl_list_for_each(sprite, &b->sprite_list, link)
2791 drmModeSetPlane(b->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002792 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002793 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002794 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002795 };
2796}
2797
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002798static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002799switch_vt_binding(struct weston_keyboard *keyboard, uint32_t time,
2800 uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002801{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002802 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002803
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002804 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002805}
2806
David Herrmann0af066f2012-10-29 19:21:16 +01002807/*
2808 * Find primary GPU
2809 * Some systems may have multiple DRM devices attached to a single seat. This
2810 * function loops over all devices and tries to find a PCI device with the
2811 * boot_vga sysfs attribute set to 1.
2812 * If no such device is found, the first DRM device reported by udev is used.
2813 */
2814static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002815find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002816{
2817 struct udev_enumerate *e;
2818 struct udev_list_entry *entry;
2819 const char *path, *device_seat, *id;
2820 struct udev_device *device, *drm_device, *pci;
2821
Giulio Camuffo954f1832014-10-11 18:27:30 +03002822 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002823 udev_enumerate_add_match_subsystem(e, "drm");
2824 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2825
2826 udev_enumerate_scan_devices(e);
2827 drm_device = NULL;
2828 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2829 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002830 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002831 if (!device)
2832 continue;
2833 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2834 if (!device_seat)
2835 device_seat = default_seat;
2836 if (strcmp(device_seat, seat)) {
2837 udev_device_unref(device);
2838 continue;
2839 }
2840
2841 pci = udev_device_get_parent_with_subsystem_devtype(device,
2842 "pci", NULL);
2843 if (pci) {
2844 id = udev_device_get_sysattr_value(pci, "boot_vga");
2845 if (id && !strcmp(id, "1")) {
2846 if (drm_device)
2847 udev_device_unref(drm_device);
2848 drm_device = device;
2849 break;
2850 }
2851 }
2852
2853 if (!drm_device)
2854 drm_device = device;
2855 else
2856 udev_device_unref(device);
2857 }
2858
2859 udev_enumerate_unref(e);
2860 return drm_device;
2861}
2862
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002863static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002864planes_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
2865 void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002866{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002867 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002868
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002869 switch (key) {
2870 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002871 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002872 break;
2873 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002874 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002875 break;
2876 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002877 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002878 break;
2879 default:
2880 break;
2881 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002882}
2883
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002884#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002885static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002886recorder_destroy(struct drm_output *output)
2887{
2888 vaapi_recorder_destroy(output->recorder);
2889 output->recorder = NULL;
2890
2891 output->base.disable_planes--;
2892
2893 wl_list_remove(&output->recorder_frame_listener.link);
2894 weston_log("[libva recorder] done\n");
2895}
2896
2897static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002898recorder_frame_notify(struct wl_listener *listener, void *data)
2899{
2900 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002901 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002902 int fd, ret;
2903
2904 output = container_of(listener, struct drm_output,
2905 recorder_frame_listener);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002906 b = (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002907
2908 if (!output->recorder)
2909 return;
2910
Giulio Camuffo954f1832014-10-11 18:27:30 +03002911 ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002912 DRM_CLOEXEC, &fd);
2913 if (ret) {
2914 weston_log("[libva recorder] "
2915 "failed to create prime fd for front buffer\n");
2916 return;
2917 }
2918
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002919 ret = vaapi_recorder_frame(output->recorder, fd,
2920 output->current->stride);
2921 if (ret < 0) {
2922 weston_log("[libva recorder] aborted: %m\n");
2923 recorder_destroy(output);
2924 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002925}
2926
2927static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002928create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002929 const char *filename)
2930{
2931 int fd;
2932 drm_magic_t magic;
2933
Giulio Camuffo954f1832014-10-11 18:27:30 +03002934 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002935 if (fd < 0)
2936 return NULL;
2937
2938 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002939 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002940
2941 return vaapi_recorder_create(fd, width, height, filename);
2942}
2943
2944static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002945recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002946 void *data)
2947{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002948 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002949 struct drm_output *output;
2950 int width, height;
2951
Giulio Camuffo954f1832014-10-11 18:27:30 +03002952 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002953 struct drm_output, base.link);
2954
2955 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002956 if (output->format != GBM_FORMAT_XRGB8888) {
2957 weston_log("failed to start vaapi recorder: "
2958 "output format not supported\n");
2959 return;
2960 }
2961
Hardeningff39efa2013-09-18 23:56:35 +02002962 width = output->base.current_mode->width;
2963 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002964
2965 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002966 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002967 if (!output->recorder) {
2968 weston_log("failed to create vaapi recorder\n");
2969 return;
2970 }
2971
2972 output->base.disable_planes++;
2973
2974 output->recorder_frame_listener.notify = recorder_frame_notify;
2975 wl_signal_add(&output->base.frame_signal,
2976 &output->recorder_frame_listener);
2977
2978 weston_output_schedule_repaint(&output->base);
2979
2980 weston_log("[libva recorder] initialized\n");
2981 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002982 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002983 }
2984}
2985#else
2986static void
Bryce Harrington4a8a3a12015-07-16 19:12:26 -07002987recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002988 void *data)
2989{
2990 weston_log("Compiled without libva support\n");
2991}
2992#endif
2993
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002994static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002995switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002996{
2997 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002998 bool dmabuf_support_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002999
Giulio Camuffo954f1832014-10-11 18:27:30 +03003000 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003001 return;
3002
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003003 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
3004
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003005 weston_log("Switching to GL renderer\n");
3006
Giulio Camuffo954f1832014-10-11 18:27:30 +03003007 b->gbm = create_gbm_device(b->drm.fd);
3008 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003009 weston_log("Failed to create gbm device. "
3010 "Aborting renderer switch\n");
3011 return;
3012 }
3013
Giulio Camuffo954f1832014-10-11 18:27:30 +03003014 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003015 pixman_renderer_output_destroy(&output->base);
3016
Giulio Camuffo954f1832014-10-11 18:27:30 +03003017 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003018
Giulio Camuffo954f1832014-10-11 18:27:30 +03003019 if (drm_backend_create_gl_renderer(b) < 0) {
3020 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003021 weston_log("Failed to create GL renderer. Quitting.\n");
3022 /* FIXME: we need a function to shutdown cleanly */
3023 assert(0);
3024 }
3025
Giulio Camuffo954f1832014-10-11 18:27:30 +03003026 wl_list_for_each(output, &b->compositor->output_list, base.link)
3027 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003028
Giulio Camuffo954f1832014-10-11 18:27:30 +03003029 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003030
3031 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
3032 if (linux_dmabuf_setup(b->compositor) < 0)
3033 weston_log("Error: initializing dmabuf "
3034 "support failed.\n");
3035 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003036}
3037
3038static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05003039renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
3040 uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003041{
Derek Foreman8ae2db52015-07-15 13:00:36 -05003042 struct drm_backend *b =
3043 (struct drm_backend *) keyboard->seat->compositor;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003044
Giulio Camuffo954f1832014-10-11 18:27:30 +03003045 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003046}
3047
Giulio Camuffo954f1832014-10-11 18:27:30 +03003048static struct drm_backend *
3049drm_backend_create(struct weston_compositor *compositor,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003050 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003051 int *argc, char *argv[],
3052 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003053{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003054 struct drm_backend *b;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003055 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01003056 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003057 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01003058 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003059 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003060
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04003061 weston_log("initializing drm backend\n");
3062
Giulio Camuffo954f1832014-10-11 18:27:30 +03003063 b = zalloc(sizeof *b);
3064 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003065 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01003066
Pekka Paalanen68583832015-05-19 09:53:16 +03003067 /*
3068 * KMS support for hardware planes cannot properly synchronize
3069 * without nuclear page flip. Without nuclear/atomic, hw plane
3070 * and cursor plane updates would either tear or cause extra
3071 * waits for vblanks which means dropping the compositor framerate
3072 * to a fraction.
3073 *
3074 * These can be enabled again when nuclear/atomic support lands.
3075 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003076 b->sprites_are_broken = 1;
3077 b->cursors_are_broken = 1;
3078 b->compositor = compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003079
3080 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003081 if (get_gbm_format_from_section(section,
3082 GBM_FORMAT_XRGB8888,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003083 &b->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003084 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003085
Giulio Camuffo954f1832014-10-11 18:27:30 +03003086 b->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003087
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003088 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003089 compositor->launcher = weston_launcher_connect(compositor, param->tty,
3090 param->seat_id, true);
3091 if (compositor->launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003092 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04003093 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003094 goto err_compositor;
3095 }
3096
Giulio Camuffo954f1832014-10-11 18:27:30 +03003097 b->udev = udev_new();
3098 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003099 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003100 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003101 }
3102
Giulio Camuffo954f1832014-10-11 18:27:30 +03003103 b->session_listener.notify = session_notify;
3104 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003105
Giulio Camuffo954f1832014-10-11 18:27:30 +03003106 drm_device = find_primary_gpu(b, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003107 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003108 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003109 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003110 }
David Herrmann0af066f2012-10-29 19:21:16 +01003111 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003112
Giulio Camuffo954f1832014-10-11 18:27:30 +03003113 if (init_drm(b, drm_device) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003114 weston_log("failed to initialize kms\n");
3115 goto err_udev_dev;
3116 }
3117
Giulio Camuffo954f1832014-10-11 18:27:30 +03003118 if (b->use_pixman) {
3119 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003120 weston_log("failed to initialize pixman renderer\n");
3121 goto err_udev_dev;
3122 }
3123 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003124 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003125 weston_log("failed to initialize egl\n");
3126 goto err_udev_dev;
3127 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003128 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003129
Giulio Camuffo954f1832014-10-11 18:27:30 +03003130 b->base.destroy = drm_destroy;
3131 b->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003132
Giulio Camuffo954f1832014-10-11 18:27:30 +03003133 b->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02003134
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003135 for (key = KEY_F1; key < KEY_F9; key++)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003136 weston_compositor_add_key_binding(compositor, key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003137 MODIFIER_CTRL | MODIFIER_ALT,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003138 switch_vt_binding, compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003139
Giulio Camuffo954f1832014-10-11 18:27:30 +03003140 wl_list_init(&b->sprite_list);
3141 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003142
Giulio Camuffo954f1832014-10-11 18:27:30 +03003143 if (udev_input_init(&b->input,
3144 compositor, b->udev, param->seat_id) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003145 weston_log("failed to create input devices\n");
3146 goto err_sprite;
3147 }
3148
Giulio Camuffo954f1832014-10-11 18:27:30 +03003149 if (create_outputs(b, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003150 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003151 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003152 }
3153
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003154 /* A this point we have some idea of whether or not we have a working
3155 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003156 if (!b->cursors_are_broken)
3157 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003158
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02003159 path = NULL;
3160
Giulio Camuffo954f1832014-10-11 18:27:30 +03003161 loop = wl_display_get_event_loop(compositor->wl_display);
3162 b->drm_source =
3163 wl_event_loop_add_fd(loop, b->drm.fd,
3164 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003165
Giulio Camuffo954f1832014-10-11 18:27:30 +03003166 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3167 if (b->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003168 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003169 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003170 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003171 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003172 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003173 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003174 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003175 udev_monitor_get_fd(b->udev_monitor),
3176 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003177
Giulio Camuffo954f1832014-10-11 18:27:30 +03003178 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003179 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003180 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003181 }
3182
Daniel Stonea96b93c2012-06-22 14:04:37 +01003183 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003184
Giulio Camuffo954f1832014-10-11 18:27:30 +03003185 weston_compositor_add_debug_binding(compositor, KEY_O,
3186 planes_binding, b);
3187 weston_compositor_add_debug_binding(compositor, KEY_C,
3188 planes_binding, b);
3189 weston_compositor_add_debug_binding(compositor, KEY_V,
3190 planes_binding, b);
3191 weston_compositor_add_debug_binding(compositor, KEY_Q,
3192 recorder_binding, b);
3193 weston_compositor_add_debug_binding(compositor, KEY_W,
3194 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003195
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003196 if (compositor->renderer->import_dmabuf) {
3197 if (linux_dmabuf_setup(compositor) < 0)
3198 weston_log("Error: initializing dmabuf "
3199 "support failed.\n");
3200 }
3201
Giulio Camuffo954f1832014-10-11 18:27:30 +03003202 compositor->backend = &b->base;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003203
Giulio Camuffo954f1832014-10-11 18:27:30 +03003204 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003205
3206err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003207 wl_event_source_remove(b->udev_drm_source);
3208 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003209err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003210 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003211err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003212 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003213err_sprite:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003214 gbm_device_destroy(b->gbm);
3215 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003216err_udev_dev:
3217 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003218err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003219 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003220err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003221 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003222err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003223 weston_compositor_shutdown(compositor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003224err_base:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003225 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003226 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003227}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003228
Giulio Camuffo954f1832014-10-11 18:27:30 +03003229WL_EXPORT int
3230backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003231 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003232{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003233 struct drm_backend *b;
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003234 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003235
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003236 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003237 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3238 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3239 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003240 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003241 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003242 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003243
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003244 param.seat_id = default_seat;
3245
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003246 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003247
Giulio Camuffo954f1832014-10-11 18:27:30 +03003248 b = drm_backend_create(compositor, &param, argc, argv, config);
3249 if (b == NULL)
3250 return -1;
3251 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003252}