blob: 33421329e7dfeed541fb3b4b7a08c6349824d71b [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;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500924 struct drm_sprite *s;
925 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500926 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500927 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200928 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500929 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400930 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931
Giulio Camuffo954f1832014-10-11 18:27:30 +0300932 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200933 return NULL;
934
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200935 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200936 return NULL;
937
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200938 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200939 return NULL;
940
Giulio Camuffo954f1832014-10-11 18:27:30 +0300941 if (b->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400942 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500943
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200944 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400945 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300946
Jason Ekstranda7af7042013-10-12 22:38:11 -0500947 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400948 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500949
Jason Ekstranda7af7042013-10-12 22:38:11 -0500950 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200951 return NULL;
952
Jason Ekstranda7af7042013-10-12 22:38:11 -0500953 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500954 return NULL;
955
Jason Ekstranda7af7042013-10-12 22:38:11 -0500956 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400957 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500958
Giulio Camuffo954f1832014-10-11 18:27:30 +0300959 wl_list_for_each(s, &b->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200960 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500961 continue;
962
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200963 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500964 found = 1;
965 break;
966 }
967 }
968
969 /* No sprites available */
970 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400971 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500972
Giulio Camuffo954f1832014-10-11 18:27:30 +0300973 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500974 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700975 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400976 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400977 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400978
Jason Ekstranda7af7042013-10-12 22:38:11 -0500979 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500980 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200981 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400982 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500983 }
984
Giulio Camuffo954f1832014-10-11 18:27:30 +0300985 s->next = drm_fb_get_from_bo(bo, b, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200986 if (!s->next) {
987 gbm_bo_destroy(bo);
988 return NULL;
989 }
990
Jason Ekstranda7af7042013-10-12 22:38:11 -0500991 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500992
Jason Ekstranda7af7042013-10-12 22:38:11 -0500993 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400994 s->plane.x = box->x1;
995 s->plane.y = box->y1;
996
Jesse Barnes58ef3792012-02-23 09:45:49 -0500997 /*
998 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500999 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -05001000 * for us already).
1001 */
1002 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001003 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001004 &output->base.region);
1005 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001006 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001007 tbox = weston_transformed_rect(output->base.width,
1008 output->base.height,
1009 output->base.transform,
1010 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001011 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001012 s->dest_x = tbox.x1;
1013 s->dest_y = tbox.y1;
1014 s->dest_w = tbox.x2 - tbox.x1;
1015 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001016 pixman_region32_fini(&dest_rect);
1017
1018 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001019 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001020 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001021 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001022
Jason Ekstranda7af7042013-10-12 22:38:11 -05001023 weston_view_from_global_fixed(ev,
1024 wl_fixed_from_int(box->x1),
1025 wl_fixed_from_int(box->y1),
1026 &sx1, &sy1);
1027 weston_view_from_global_fixed(ev,
1028 wl_fixed_from_int(box->x2),
1029 wl_fixed_from_int(box->y2),
1030 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001031
1032 if (sx1 < 0)
1033 sx1 = 0;
1034 if (sy1 < 0)
1035 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001036 if (sx2 > wl_fixed_from_int(ev->surface->width))
1037 sx2 = wl_fixed_from_int(ev->surface->width);
1038 if (sy2 > wl_fixed_from_int(ev->surface->height))
1039 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001040
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001041 tbox.x1 = sx1;
1042 tbox.y1 = sy1;
1043 tbox.x2 = sx2;
1044 tbox.y2 = sy2;
1045
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001046 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
1047 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001048 viewport->buffer.transform,
1049 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01001050 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001051
1052 s->src_x = tbox.x1 << 8;
1053 s->src_y = tbox.y1 << 8;
1054 s->src_w = (tbox.x2 - tbox.x1) << 8;
1055 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001056 pixman_region32_fini(&src_rect);
1057
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001058 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001059}
1060
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001061static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001062drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001063 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001064{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001065 struct drm_backend *b =
1066 (struct drm_backend *)output->base.compositor->backend;
Neil Robertsf37f82c2014-05-01 18:00:41 +01001067 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001068
Giulio Camuffo954f1832014-10-11 18:27:30 +03001069 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001070 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +02001071 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1072 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001073 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001074 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001075 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001076 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001077 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001078 return NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001079 if (b->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001080 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001081 if (ev->geometry.scissor_enabled)
1082 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001083 if (ev->surface->buffer_ref.buffer == NULL ||
1084 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Daniel Stone70d337d2015-06-16 18:42:23 +01001085 ev->surface->width > b->cursor_width ||
1086 ev->surface->height > b->cursor_height)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001087 return NULL;
1088
Jason Ekstranda7af7042013-10-12 22:38:11 -05001089 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001090
1091 return &output->cursor_plane;
1092}
1093
Pekka Paalanend0ead482014-06-16 12:05:40 +03001094/**
1095 * Update the image for the current cursor surface
1096 *
1097 * @param b DRM backend structure
1098 * @param bo GBM buffer object to write into
1099 * @param ev View to use for cursor image
1100 */
1101static void
1102cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
1103 struct weston_view *ev)
1104{
1105 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
1106 uint32_t buf[b->cursor_width * b->cursor_height];
1107 int32_t stride;
1108 uint8_t *s;
1109 int i;
1110
1111 assert(buffer && buffer->shm_buffer);
1112 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
1113 assert(ev->surface->width <= b->cursor_width);
1114 assert(ev->surface->height <= b->cursor_height);
1115
1116 memset(buf, 0, sizeof buf);
1117 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1118 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1119
1120 wl_shm_buffer_begin_access(buffer->shm_buffer);
1121 for (i = 0; i < ev->surface->height; i++)
1122 memcpy(buf + i * b->cursor_width,
1123 s + i * stride,
1124 ev->surface->width * 4);
1125 wl_shm_buffer_end_access(buffer->shm_buffer);
1126
1127 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
1128 weston_log("failed update cursor: %m\n");
1129}
1130
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001131static void
1132drm_output_set_cursor(struct drm_output *output)
1133{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001134 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001135 struct weston_buffer *buffer;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001136 struct drm_backend *b =
1137 (struct drm_backend *) output->base.compositor->backend;
Pekka Paalanend0ead482014-06-16 12:05:40 +03001138 EGLint handle;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001139 struct gbm_bo *bo;
Pekka Paalanend0ead482014-06-16 12:05:40 +03001140 int x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001141
Jason Ekstranda7af7042013-10-12 22:38:11 -05001142 output->cursor_view = NULL;
1143 if (ev == NULL) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001144 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001145 return;
1146 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001147
Neil Robertse5051712013-11-13 15:44:06 +00001148 buffer = ev->surface->buffer_ref.buffer;
1149
1150 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001151 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001152 pixman_region32_fini(&output->cursor_plane.damage);
1153 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001154 output->current_cursor ^= 1;
1155 bo = output->cursor_bo[output->current_cursor];
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001156
Pekka Paalanend0ead482014-06-16 12:05:40 +03001157 cursor_bo_update(b, bo, ev);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001158 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001159 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
1160 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001161 weston_log("failed to set cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001162 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001163 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001164 }
1165
Jason Ekstranda7af7042013-10-12 22:38:11 -05001166 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1167 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001168 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001169 if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001170 weston_log("failed to move cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001171 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001172 }
1173
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001174 output->cursor_plane.x = x;
1175 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001176 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001177}
1178
Jesse Barnes58ef3792012-02-23 09:45:49 -05001179static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001180drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001181{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001182 struct drm_backend *b =
1183 (struct drm_backend *)output_base->compositor->backend;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001184 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001185 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001186 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001187 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001188
1189 /*
1190 * Find a surface for each sprite in the output using some heuristics:
1191 * 1) size
1192 * 2) frequency of update
1193 * 3) opacity (though some hw might support alpha blending)
1194 * 4) clipping (this can be fixed with color keys)
1195 *
1196 * The idea is to save on blitting since this should save power.
1197 * If we can get a large video surface on the sprite for example,
1198 * the main display surface may not need to update at all, and
1199 * the client buffer can be used directly for the sprite surface
1200 * as we do for flipping full screen surfaces.
1201 */
1202 pixman_region32_init(&overlap);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001203 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001204
Giulio Camuffo954f1832014-10-11 18:27:30 +03001205 wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001206 struct weston_surface *es = ev->surface;
1207
1208 /* Test whether this buffer can ever go into a plane:
1209 * non-shm, or small enough to be a cursor.
1210 *
1211 * Also, keep a reference when using the pixman renderer.
1212 * That makes it possible to do a seamless switch to the GL
1213 * renderer and since the pixman renderer keeps a reference
1214 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001215 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001216 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001217 (es->buffer_ref.buffer &&
1218 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001219 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001220 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001221 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001222 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001223
Jesse Barnes58ef3792012-02-23 09:45:49 -05001224 pixman_region32_init(&surface_overlap);
1225 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001226 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001227
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001228 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001229 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001230 next_plane = primary;
1231 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001232 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001233 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001234 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001235 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001236 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001237 if (next_plane == NULL)
1238 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001239
Jason Ekstranda7af7042013-10-12 22:38:11 -05001240 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001241
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001242 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001243 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001244 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001245
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001246 if (next_plane == primary ||
1247 next_plane == &output->cursor_plane) {
1248 /* cursor plane involves a copy */
1249 ev->psf_flags = 0;
1250 } else {
1251 /* All other planes are a direct scanout of a
1252 * single client buffer.
1253 */
1254 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1255 }
1256
Jesse Barnes58ef3792012-02-23 09:45:49 -05001257 pixman_region32_fini(&surface_overlap);
1258 }
1259 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001260}
1261
Matt Roper361d2ad2011-08-29 13:52:23 -07001262static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001263drm_output_fini_pixman(struct drm_output *output);
1264
1265static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001266drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001267{
1268 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001269 struct drm_backend *b =
1270 (struct drm_backend *)output->base.compositor->backend;
Matt Roper361d2ad2011-08-29 13:52:23 -07001271 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001272
Xiong Zhangabd5d472013-10-11 14:43:07 +08001273 if (output->page_flip_pending) {
1274 output->destroy_pending = 1;
1275 weston_log("destroy output while page flip pending\n");
1276 return;
1277 }
1278
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001279 if (output->backlight)
1280 backlight_destroy(output->backlight);
1281
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001282 drmModeFreeProperty(output->dpms_prop);
1283
Matt Roper361d2ad2011-08-29 13:52:23 -07001284 /* Turn off hardware cursor */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001285 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001286
1287 /* Restore original CRTC state */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001288 drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001289 origcrtc->x, origcrtc->y,
1290 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001291 drmModeFreeCrtc(origcrtc);
1292
Giulio Camuffo954f1832014-10-11 18:27:30 +03001293 b->crtc_allocator &= ~(1 << output->crtc_id);
1294 b->connector_allocator &= ~(1 << output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001295
Giulio Camuffo954f1832014-10-11 18:27:30 +03001296 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001297 drm_output_fini_pixman(output);
1298 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001299 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001300 gbm_surface_destroy(output->surface);
1301 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001302
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001303 weston_plane_release(&output->fb_plane);
1304 weston_plane_release(&output->cursor_plane);
1305
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001306 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001307
Matt Roper361d2ad2011-08-29 13:52:23 -07001308 free(output);
1309}
1310
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001311/**
1312 * Find the closest-matching mode for a given target
1313 *
1314 * Given a target mode, find the most suitable mode amongst the output's
1315 * current mode list to use, preferring the current mode if possible, to
1316 * avoid an expensive mode switch.
1317 *
1318 * @param output DRM output
1319 * @param target_mode Mode to attempt to match
1320 * @returns Pointer to a mode from the output's mode list
1321 */
Alex Wub7b8bda2012-04-17 17:20:48 +08001322static struct drm_mode *
1323choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1324{
1325 struct drm_mode *tmp_mode = NULL, *mode;
1326
Hardeningff39efa2013-09-18 23:56:35 +02001327 if (output->base.current_mode->width == target_mode->width &&
1328 output->base.current_mode->height == target_mode->height &&
1329 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001330 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001331 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001332
1333 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1334 if (mode->mode_info.hdisplay == target_mode->width &&
1335 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001336 if (mode->base.refresh == target_mode->refresh ||
1337 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001338 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001339 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001340 tmp_mode = mode;
1341 }
1342 }
1343
1344 return tmp_mode;
1345}
1346
1347static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001348drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001349static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001350drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001351
1352static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001353drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1354{
1355 struct drm_output *output;
1356 struct drm_mode *drm_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001357 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08001358
1359 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001360 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001361 return -1;
1362 }
1363
1364 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001365 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001366 return -1;
1367 }
1368
Giulio Camuffo954f1832014-10-11 18:27:30 +03001369 b = (struct drm_backend *)output_base->compositor->backend;
Alex Wub7b8bda2012-04-17 17:20:48 +08001370 output = (struct drm_output *)output_base;
1371 drm_mode = choose_mode (output, mode);
1372
1373 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001374 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001375 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001376 }
1377
Hardeningff39efa2013-09-18 23:56:35 +02001378 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001379 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001380
Hardeningff39efa2013-09-18 23:56:35 +02001381 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001382
Hardeningff39efa2013-09-18 23:56:35 +02001383 output->base.current_mode = &drm_mode->base;
1384 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001385 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1386
Alex Wub7b8bda2012-04-17 17:20:48 +08001387 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001388 drm_output_release_fb(output, output->current);
1389 drm_output_release_fb(output, output->next);
1390 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001391
Giulio Camuffo954f1832014-10-11 18:27:30 +03001392 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001393 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001394 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001395 weston_log("failed to init output pixman state with "
1396 "new mode\n");
1397 return -1;
1398 }
1399 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001400 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001401 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001402
Giulio Camuffo954f1832014-10-11 18:27:30 +03001403 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001404 weston_log("failed to init output egl state with "
1405 "new mode");
1406 return -1;
1407 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001408 }
1409
Alex Wub7b8bda2012-04-17 17:20:48 +08001410 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001411}
1412
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001413static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001414on_drm_input(int fd, uint32_t mask, void *data)
1415{
1416 drmEventContext evctx;
1417
1418 memset(&evctx, 0, sizeof evctx);
1419 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1420 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001421 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001422 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001423
1424 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001425}
1426
1427static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001428init_drm(struct drm_backend *b, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001429{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001430 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001431 uint64_t cap;
1432 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001433 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001434
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001435 sysnum = udev_device_get_sysnum(device);
1436 if (sysnum)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001437 b->drm.id = atoi(sysnum);
1438 if (!sysnum || b->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001439 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001440 return -1;
1441 }
1442
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001443 filename = udev_device_get_devnode(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001444 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001445 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001446 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001447 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001448 udev_device_get_devnode(device));
1449 return -1;
1450 }
1451
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001452 weston_log("using %s\n", filename);
1453
Giulio Camuffo954f1832014-10-11 18:27:30 +03001454 b->drm.fd = fd;
1455 b->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001456
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001457 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1458 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001459 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001460 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001461 clk_id = CLOCK_REALTIME;
1462
Giulio Camuffo954f1832014-10-11 18:27:30 +03001463 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001464 weston_log("Error: failed to set presentation clock %d.\n",
1465 clk_id);
1466 return -1;
1467 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001468
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001469 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1470 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001471 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001472 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001473 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001474
1475 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1476 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001477 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001478 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001479 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001480
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001481 return 0;
1482}
1483
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001484static struct gbm_device *
1485create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001486{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001487 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001488
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001489 gl_renderer = weston_load_module("gl-renderer.so",
1490 "gl_renderer_interface");
1491 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001492 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001493
1494 /* GBM will load a dri driver, but even though they need symbols from
1495 * libglapi, in some version of Mesa they are not linked to it. Since
1496 * only the gl-renderer module links to it, the call above won't make
1497 * these symbols globally available, and loading the DRI driver fails.
1498 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1499 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1500
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001501 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001502
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001503 return gbm;
1504}
1505
Bryce Harringtonc056a982015-05-19 15:25:18 -07001506/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001507 * we may be able to susbstitute an ARGB format for an XRGB one.
1508 *
1509 * This returns 0 if substitution isn't possible, but 0 might be a
1510 * legitimate format for other EGL platforms, so the caller is
1511 * responsible for checking for 0 before calling gl_renderer->create().
1512 *
1513 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1514 * but it's entirely possible we'll see this again on other implementations.
1515 */
1516static int
1517fallback_format_for(uint32_t format)
1518{
1519 switch (format) {
1520 case GBM_FORMAT_XRGB8888:
1521 return GBM_FORMAT_ARGB8888;
1522 case GBM_FORMAT_XRGB2101010:
1523 return GBM_FORMAT_ARGB2101010;
1524 default:
1525 return 0;
1526 }
1527}
1528
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001529static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001530drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001531{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001532 EGLint format[2] = {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001533 b->format,
1534 fallback_format_for(b->format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05001535 };
1536 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001537
Derek Foremanc4cfe852015-05-15 12:12:40 -05001538 if (format[1])
1539 n_formats = 2;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001540 if (gl_renderer->create(b->compositor,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001541 EGL_PLATFORM_GBM_KHR,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001542 (void *)b->gbm,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001543 gl_renderer->opaque_attribs,
1544 format,
1545 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001546 return -1;
1547 }
1548
1549 return 0;
1550}
1551
1552static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001553init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001554{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001555 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001556
Giulio Camuffo954f1832014-10-11 18:27:30 +03001557 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001558 return -1;
1559
Giulio Camuffo954f1832014-10-11 18:27:30 +03001560 if (drm_backend_create_gl_renderer(b) < 0) {
1561 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001562 return -1;
1563 }
1564
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001565 return 0;
1566}
1567
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001568static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001569init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001570{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001571 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001572}
1573
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001574/**
1575 * Add a mode to output's mode list
1576 *
1577 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
1578 * output's mode list.
1579 *
1580 * @param output DRM output to add mode to
1581 * @param info DRM mode structure to add
1582 * @returns Newly-allocated Weston/DRM mode structure
1583 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001584static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001585drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001586{
1587 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001588 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001589
1590 mode = malloc(sizeof *mode);
1591 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001592 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001593
1594 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001595 mode->base.width = info->hdisplay;
1596 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001597
1598 /* Calculate higher precision (mHz) refresh rate */
1599 refresh = (info->clock * 1000000LL / info->htotal +
1600 info->vtotal / 2) / info->vtotal;
1601
1602 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1603 refresh *= 2;
1604 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1605 refresh /= 2;
1606 if (info->vscan > 1)
1607 refresh /= info->vscan;
1608
1609 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001610 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001611
1612 if (info->type & DRM_MODE_TYPE_PREFERRED)
1613 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1614
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001615 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1616
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001617 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001618}
1619
1620static int
1621drm_subpixel_to_wayland(int drm_value)
1622{
1623 switch (drm_value) {
1624 default:
1625 case DRM_MODE_SUBPIXEL_UNKNOWN:
1626 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1627 case DRM_MODE_SUBPIXEL_NONE:
1628 return WL_OUTPUT_SUBPIXEL_NONE;
1629 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1630 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1631 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1632 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1633 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1634 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1635 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1636 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1637 }
1638}
1639
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001640/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001641static uint32_t
1642drm_get_backlight(struct drm_output *output)
1643{
1644 long brightness, max_brightness, norm;
1645
1646 brightness = backlight_get_brightness(output->backlight);
1647 max_brightness = backlight_get_max_brightness(output->backlight);
1648
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001649 /* convert it on a scale of 0 to 255 */
1650 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001651
1652 return (uint32_t) norm;
1653}
1654
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001655/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001656static void
1657drm_set_backlight(struct weston_output *output_base, uint32_t value)
1658{
1659 struct drm_output *output = (struct drm_output *) output_base;
1660 long max_brightness, new_brightness;
1661
1662 if (!output->backlight)
1663 return;
1664
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001665 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001666 return;
1667
1668 max_brightness = backlight_get_max_brightness(output->backlight);
1669
1670 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001671 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001672
1673 backlight_set_brightness(output->backlight, new_brightness);
1674}
1675
1676static drmModePropertyPtr
1677drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1678{
1679 drmModePropertyPtr props;
1680 int i;
1681
1682 for (i = 0; i < connector->count_props; i++) {
1683 props = drmModeGetProperty(fd, connector->props[i]);
1684 if (!props)
1685 continue;
1686
1687 if (!strcmp(props->name, name))
1688 return props;
1689
1690 drmModeFreeProperty(props);
1691 }
1692
1693 return NULL;
1694}
1695
1696static void
1697drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1698{
1699 struct drm_output *output = (struct drm_output *) output_base;
1700 struct weston_compositor *ec = output_base->compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001701 struct drm_backend *b = (struct drm_backend *)ec->backend;
Daniel Stone36609c72015-06-18 07:49:02 +01001702 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001703
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001704 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001705 return;
1706
Daniel Stone36609c72015-06-18 07:49:02 +01001707 ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
1708 output->dpms_prop->prop_id, level);
1709 if (ret) {
1710 weston_log("DRM: DPMS: failed property set for %s\n",
1711 output->base.name);
1712 return;
1713 }
1714
1715 output->dpms = level;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001716}
1717
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001718static const char * const connector_type_names[] = {
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001719 "None",
1720 "VGA",
1721 "DVI",
1722 "DVI",
1723 "DVI",
1724 "Composite",
1725 "TV",
1726 "LVDS",
1727 "CTV",
1728 "DIN",
1729 "DP",
1730 "HDMI",
1731 "HDMI",
1732 "TV",
1733 "eDP",
1734};
1735
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001736static char *
1737make_connector_name(const drmModeConnector *con)
1738{
1739 char name[32];
1740 const char *type_name;
1741
1742 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1743 type_name = connector_type_names[con->connector_type];
1744 else
1745 type_name = "UNKNOWN";
1746 snprintf(name, sizeof name, "%s%d", type_name, con->connector_type_id);
1747
1748 return strdup(name);
1749}
1750
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001751static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001752find_crtc_for_connector(struct drm_backend *b,
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001753 drmModeRes *resources, drmModeConnector *connector)
1754{
1755 drmModeEncoder *encoder;
1756 uint32_t possible_crtcs;
1757 int i, j;
1758
1759 for (j = 0; j < connector->count_encoders; j++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001760 encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001761 if (encoder == NULL) {
1762 weston_log("Failed to get encoder.\n");
1763 return -1;
1764 }
1765 possible_crtcs = encoder->possible_crtcs;
1766 drmModeFreeEncoder(encoder);
1767
1768 for (i = 0; i < resources->count_crtcs; i++) {
1769 if (possible_crtcs & (1 << i) &&
Giulio Camuffo954f1832014-10-11 18:27:30 +03001770 !(b->crtc_allocator & (1 << resources->crtcs[i])))
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001771 return i;
1772 }
1773 }
1774
1775 return -1;
1776}
1777
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001778/* Init output state that depends on gl or gbm */
1779static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001780drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001781{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001782 EGLint format[2] = {
1783 output->format,
1784 fallback_format_for(output->format),
1785 };
1786 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001787
Giulio Camuffo954f1832014-10-11 18:27:30 +03001788 output->surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001789 output->base.current_mode->width,
1790 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001791 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001792 GBM_BO_USE_SCANOUT |
1793 GBM_BO_USE_RENDERING);
1794 if (!output->surface) {
1795 weston_log("failed to create gbm surface\n");
1796 return -1;
1797 }
1798
Derek Foremanc4cfe852015-05-15 12:12:40 -05001799 if (format[1])
1800 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001801 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001802 (EGLNativeDisplayType)output->surface,
1803 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001804 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001805 format,
1806 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001807 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001808 gbm_surface_destroy(output->surface);
1809 return -1;
1810 }
1811
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001812 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001813
1814 for (i = 0; i < 2; i++) {
1815 if (output->cursor_bo[i])
1816 continue;
1817
1818 output->cursor_bo[i] =
Giulio Camuffo954f1832014-10-11 18:27:30 +03001819 gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001820 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001821 }
1822
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001823 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1824 weston_log("cursor buffers unavailable, using gl cursors\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001825 b->cursors_are_broken = 1;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001826 }
1827
1828 return 0;
1829}
1830
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001831static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001832drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001833{
Hardeningff39efa2013-09-18 23:56:35 +02001834 int w = output->base.current_mode->width;
1835 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001836 unsigned int i;
1837
1838 /* FIXME error checking */
1839
1840 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001841 output->dumb[i] = drm_fb_create_dumb(b, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001842 if (!output->dumb[i])
1843 goto err;
1844
1845 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001846 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001847 output->dumb[i]->map,
1848 output->dumb[i]->stride);
1849 if (!output->image[i])
1850 goto err;
1851 }
1852
1853 if (pixman_renderer_output_create(&output->base) < 0)
1854 goto err;
1855
1856 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001857 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001858
1859 return 0;
1860
1861err:
1862 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1863 if (output->dumb[i])
1864 drm_fb_destroy_dumb(output->dumb[i]);
1865 if (output->image[i])
1866 pixman_image_unref(output->image[i]);
1867
1868 output->dumb[i] = NULL;
1869 output->image[i] = NULL;
1870 }
1871
1872 return -1;
1873}
1874
1875static void
1876drm_output_fini_pixman(struct drm_output *output)
1877{
1878 unsigned int i;
1879
1880 pixman_renderer_output_destroy(&output->base);
1881 pixman_region32_fini(&output->previous_damage);
1882
1883 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1884 drm_fb_destroy_dumb(output->dumb[i]);
1885 pixman_image_unref(output->image[i]);
1886 output->dumb[i] = NULL;
1887 output->image[i] = NULL;
1888 }
1889}
1890
Richard Hughes2b2092a2013-04-24 14:58:02 +01001891static void
1892edid_parse_string(const uint8_t *data, char text[])
1893{
1894 int i;
1895 int replaced = 0;
1896
1897 /* this is always 12 bytes, but we can't guarantee it's null
1898 * terminated or not junk. */
1899 strncpy(text, (const char *) data, 12);
1900
1901 /* remove insane chars */
1902 for (i = 0; text[i] != '\0'; i++) {
1903 if (text[i] == '\n' ||
1904 text[i] == '\r') {
1905 text[i] = '\0';
1906 break;
1907 }
1908 }
1909
1910 /* ensure string is printable */
1911 for (i = 0; text[i] != '\0'; i++) {
1912 if (!isprint(text[i])) {
1913 text[i] = '-';
1914 replaced++;
1915 }
1916 }
1917
1918 /* if the string is random junk, ignore the string */
1919 if (replaced > 4)
1920 text[0] = '\0';
1921}
1922
1923#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1924#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1925#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1926#define EDID_OFFSET_DATA_BLOCKS 0x36
1927#define EDID_OFFSET_LAST_BLOCK 0x6c
1928#define EDID_OFFSET_PNPID 0x08
1929#define EDID_OFFSET_SERIAL 0x0c
1930
1931static int
1932edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1933{
1934 int i;
1935 uint32_t serial_number;
1936
1937 /* check header */
1938 if (length < 128)
1939 return -1;
1940 if (data[0] != 0x00 || data[1] != 0xff)
1941 return -1;
1942
1943 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1944 * /--08--\/--09--\
1945 * 7654321076543210
1946 * |\---/\---/\---/
1947 * R C1 C2 C3 */
1948 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1949 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1950 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1951 edid->pnp_id[3] = '\0';
1952
1953 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1954 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1955 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1956 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1957 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1958 if (serial_number > 0)
1959 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1960
1961 /* parse EDID data */
1962 for (i = EDID_OFFSET_DATA_BLOCKS;
1963 i <= EDID_OFFSET_LAST_BLOCK;
1964 i += 18) {
1965 /* ignore pixel clock data */
1966 if (data[i] != 0)
1967 continue;
1968 if (data[i+2] != 0)
1969 continue;
1970
1971 /* any useful blocks? */
1972 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1973 edid_parse_string(&data[i+5],
1974 edid->monitor_name);
1975 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1976 edid_parse_string(&data[i+5],
1977 edid->serial_number);
1978 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1979 edid_parse_string(&data[i+5],
1980 edid->eisa_id);
1981 }
1982 }
1983 return 0;
1984}
1985
1986static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001987find_and_parse_output_edid(struct drm_backend *b,
Richard Hughes2b2092a2013-04-24 14:58:02 +01001988 struct drm_output *output,
1989 drmModeConnector *connector)
1990{
1991 drmModePropertyBlobPtr edid_blob = NULL;
1992 drmModePropertyPtr property;
1993 int i;
1994 int rc;
1995
1996 for (i = 0; i < connector->count_props && !edid_blob; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001997 property = drmModeGetProperty(b->drm.fd, connector->props[i]);
Richard Hughes2b2092a2013-04-24 14:58:02 +01001998 if (!property)
1999 continue;
2000 if ((property->flags & DRM_MODE_PROP_BLOB) &&
2001 !strcmp(property->name, "EDID")) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002002 edid_blob = drmModeGetPropertyBlob(b->drm.fd,
Richard Hughes2b2092a2013-04-24 14:58:02 +01002003 connector->prop_values[i]);
2004 }
2005 drmModeFreeProperty(property);
2006 }
2007 if (!edid_blob)
2008 return;
2009
2010 rc = edid_parse(&output->edid,
2011 edid_blob->data,
2012 edid_blob->length);
2013 if (!rc) {
2014 weston_log("EDID data '%s', '%s', '%s'\n",
2015 output->edid.pnp_id,
2016 output->edid.monitor_name,
2017 output->edid.serial_number);
2018 if (output->edid.pnp_id[0] != '\0')
2019 output->base.make = output->edid.pnp_id;
2020 if (output->edid.monitor_name[0] != '\0')
2021 output->base.model = output->edid.monitor_name;
2022 if (output->edid.serial_number[0] != '\0')
2023 output->base.serial_number = output->edid.serial_number;
2024 }
2025 drmModeFreePropertyBlob(edid_blob);
2026}
2027
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002028
2029
2030static int
2031parse_modeline(const char *s, drmModeModeInfo *mode)
2032{
2033 char hsync[16];
2034 char vsync[16];
2035 float fclock;
2036
2037 mode->type = DRM_MODE_TYPE_USERDEF;
2038 mode->hskew = 0;
2039 mode->vscan = 0;
2040 mode->vrefresh = 0;
2041 mode->flags = 0;
2042
Rob Bradford307e09e2013-07-26 16:29:40 +01002043 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002044 &fclock,
2045 &mode->hdisplay,
2046 &mode->hsync_start,
2047 &mode->hsync_end,
2048 &mode->htotal,
2049 &mode->vdisplay,
2050 &mode->vsync_start,
2051 &mode->vsync_end,
2052 &mode->vtotal, hsync, vsync) != 11)
2053 return -1;
2054
2055 mode->clock = fclock * 1000;
2056 if (strcmp(hsync, "+hsync") == 0)
2057 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2058 else if (strcmp(hsync, "-hsync") == 0)
2059 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2060 else
2061 return -1;
2062
2063 if (strcmp(vsync, "+vsync") == 0)
2064 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2065 else if (strcmp(vsync, "-vsync") == 0)
2066 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2067 else
2068 return -1;
2069
2070 return 0;
2071}
2072
Rob Bradford66bd9f52013-06-25 18:56:42 +01002073static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002074setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01002075 struct weston_output *output,
2076 const char *s)
2077{
2078 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05002079 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01002080 struct udev_seat *seat;
2081
Giulio Camuffo954f1832014-10-11 18:27:30 +03002082 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05002083 if (!seat)
2084 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01002085
Derek Foreman0720ea32015-07-15 13:00:35 -05002086 seat->base.output = output;
2087
Derek Foreman1281a362015-07-31 16:55:32 -05002088 pointer = weston_seat_get_pointer(&seat->base);
2089 if (pointer)
2090 weston_pointer_clamp(pointer,
2091 &pointer->x,
2092 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002093 }
2094}
2095
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002096static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002097get_gbm_format_from_section(struct weston_config_section *section,
2098 uint32_t default_value,
2099 uint32_t *format)
2100{
2101 char *s;
2102 int ret = 0;
2103
2104 weston_config_section_get_string(section,
2105 "gbm-format", &s, NULL);
2106
2107 if (s == NULL)
2108 *format = default_value;
2109 else if (strcmp(s, "xrgb8888") == 0)
2110 *format = GBM_FORMAT_XRGB8888;
2111 else if (strcmp(s, "rgb565") == 0)
2112 *format = GBM_FORMAT_RGB565;
2113 else if (strcmp(s, "xrgb2101010") == 0)
2114 *format = GBM_FORMAT_XRGB2101010;
2115 else {
2116 weston_log("fatal: unrecognized pixel format: %s\n", s);
2117 ret = -1;
2118 }
2119
2120 free(s);
2121
2122 return ret;
2123}
2124
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002125/**
2126 * Choose suitable mode for an output
2127 *
2128 * Find the most suitable mode to use for initial setup (or reconfiguration on
2129 * hotplug etc) for a DRM output.
2130 *
2131 * @param output DRM output to choose mode for
2132 * @param kind Strategy and preference to use when choosing mode
2133 * @param width Desired width for this output
2134 * @param height Desired height for this output
2135 * @param current_mode Mode currently being displayed on this output
2136 * @param modeline Manually-entered mode (may be NULL)
2137 * @returns A mode from the output's mode list, or NULL if none available
2138 */
2139static struct drm_mode *
2140drm_output_choose_initial_mode(struct drm_output *output,
2141 enum output_config kind,
2142 int width, int height,
2143 const drmModeModeInfo *current_mode,
2144 const drmModeModeInfo *modeline)
2145{
2146 struct drm_mode *preferred = NULL;
2147 struct drm_mode *current = NULL;
2148 struct drm_mode *configured = NULL;
2149 struct drm_mode *best = NULL;
2150 struct drm_mode *drm_mode;
2151
2152 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
2153 if (kind == OUTPUT_CONFIG_MODE &&
2154 width == drm_mode->base.width &&
2155 height == drm_mode->base.height)
2156 configured = drm_mode;
2157
2158 if (memcmp(&current_mode, &drm_mode->mode_info,
2159 sizeof *current_mode) == 0)
2160 current = drm_mode;
2161
2162 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
2163 preferred = drm_mode;
2164
2165 best = drm_mode;
2166 }
2167
2168 if (kind == OUTPUT_CONFIG_MODELINE) {
2169 configured = drm_output_add_mode(output, modeline);
2170 if (!configured)
2171 return NULL;
2172 }
2173
2174 if (current == NULL && current_mode->clock != 0) {
2175 current = drm_output_add_mode(output, current_mode);
2176 if (!current)
2177 return NULL;
2178 }
2179
2180 if (kind == OUTPUT_CONFIG_CURRENT)
2181 configured = current;
2182
2183 if (option_current_mode && current)
2184 return current;
2185
2186 if (configured)
2187 return configured;
2188
2189 if (preferred)
2190 return preferred;
2191
2192 if (current)
2193 return current;
2194
2195 if (best)
2196 return best;
2197
2198 weston_log("no available modes for %s\n", output->base.name);
2199 return NULL;
2200}
2201
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002202static int
2203connector_get_current_mode(drmModeConnector *connector, int drm_fd,
2204 drmModeModeInfo *mode)
2205{
2206 drmModeEncoder *encoder;
2207 drmModeCrtc *crtc;
2208
2209 /* Get the current mode on the crtc that's currently driving
2210 * this connector. */
2211 encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
2212 memset(mode, 0, sizeof *mode);
2213 if (encoder != NULL) {
2214 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
2215 drmModeFreeEncoder(encoder);
2216 if (crtc == NULL)
2217 return -1;
2218 if (crtc->mode_valid)
2219 *mode = crtc->mode;
2220 drmModeFreeCrtc(crtc);
2221 }
2222
2223 return 0;
2224}
2225
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002226/**
2227 * Create and configure a Weston output structure
2228 *
2229 * Given a DRM connector, create a matching drm_output structure and add it
2230 * to Weston's output list.
2231 *
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002232 * @param b Weston backend structure structure
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002233 * @param resources DRM resources for this device
2234 * @param connector DRM connector to use for this new output
2235 * @param x Horizontal offset to use into global co-ordinate space
2236 * @param y Vertical offset to use into global co-ordinate space
2237 * @param drm_device udev device pointer
2238 * @returns 0 on success, or -1 on failure
2239 */
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002240static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002241create_output_for_connector(struct drm_backend *b,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002242 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002243 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002244 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002245{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002246 struct drm_output *output;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002247 struct drm_mode *drm_mode, *next, *current;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002248 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002249 struct weston_config_section *section;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002250 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002251 int i, width, height, scale;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002252 char *s;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002253 enum output_config config;
2254 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002255
Giulio Camuffo954f1832014-10-11 18:27:30 +03002256 i = find_crtc_for_connector(b, resources, connector);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002257 if (i < 0) {
2258 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002259 return -1;
2260 }
2261
Peter Huttererf3d62272013-08-08 11:57:05 +10002262 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002263 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002264 return -1;
2265
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002266 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002267 output->base.name = make_connector_name(connector);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002268 output->base.make = "unknown";
2269 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002270 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002271 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002272
Giulio Camuffo954f1832014-10-11 18:27:30 +03002273 section = weston_config_get_section(b->compositor->config, "output", "name",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002274 output->base.name);
2275 weston_config_section_get_string(section, "mode", &s, "preferred");
2276 if (strcmp(s, "off") == 0)
2277 config = OUTPUT_CONFIG_OFF;
2278 else if (strcmp(s, "preferred") == 0)
2279 config = OUTPUT_CONFIG_PREFERRED;
2280 else if (strcmp(s, "current") == 0)
2281 config = OUTPUT_CONFIG_CURRENT;
2282 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2283 config = OUTPUT_CONFIG_MODE;
2284 else if (parse_modeline(s, &modeline) == 0)
2285 config = OUTPUT_CONFIG_MODELINE;
2286 else {
2287 weston_log("Invalid mode \"%s\" for output %s\n",
2288 s, output->base.name);
2289 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002290 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002291 free(s);
2292
2293 weston_config_section_get_int(section, "scale", &scale, 1);
2294 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002295 if (weston_parse_transform(s, &transform) < 0)
2296 weston_log("Invalid transform \"%s\" for output %s\n",
2297 s, output->base.name);
2298
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002299 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002300
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002301 if (get_gbm_format_from_section(section,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002302 b->format,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002303 &output->format) == -1)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002304 output->format = b->format;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002305
Rob Bradford66bd9f52013-06-25 18:56:42 +01002306 weston_config_section_get_string(section, "seat", &s, "");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002307 setup_output_seat_constraint(b, &output->base, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002308 free(s);
2309
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002310 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002311 output->pipe = i;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002312 b->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002313 output->connector_id = connector->connector_id;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002314 b->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002315
Giulio Camuffo954f1832014-10-11 18:27:30 +03002316 output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
2317 output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002318
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002319 if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
2320 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002321
David Herrmann0f0d54e2011-12-08 17:05:45 +01002322 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002323 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002324 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002325 goto err_free;
2326 }
2327
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002328 if (config == OUTPUT_CONFIG_OFF) {
2329 weston_log("Disabling output %s\n", output->base.name);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002330 drmModeSetCrtc(b->drm.fd, output->crtc_id,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002331 0, 0, 0, 0, 0, NULL);
2332 goto err_free;
2333 }
2334
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002335 current = drm_output_choose_initial_mode(output, config,
2336 width, height,
2337 &crtc_mode, &modeline);
2338 if (!current)
Wang Quanxianacb805a2012-07-30 18:09:46 -04002339 goto err_free;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002340 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02002341 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002342
Giulio Camuffo954f1832014-10-11 18:27:30 +03002343 weston_output_init(&output->base, b->compositor, x, y,
John Kåre Alsaker94659272012-11-13 19:10:18 +01002344 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002345 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002346
Giulio Camuffo954f1832014-10-11 18:27:30 +03002347 if (b->use_pixman) {
2348 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002349 weston_log("Failed to init output pixman state\n");
2350 goto err_output;
2351 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03002352 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002353 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002354 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002355 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002356
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002357 output->backlight = backlight_init(drm_device,
2358 connector->connector_type);
2359 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002360 weston_log("Initialized backlight, device %s\n",
2361 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002362 output->base.set_backlight = drm_set_backlight;
2363 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002364 } else {
2365 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002366 }
2367
Giulio Camuffo954f1832014-10-11 18:27:30 +03002368 weston_compositor_add_output(b->compositor, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002369
Giulio Camuffo954f1832014-10-11 18:27:30 +03002370 find_and_parse_output_edid(b, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002371 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2372 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002373
Jonas Ådahle5a12252013-04-05 23:07:11 +02002374 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002375 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002376 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002377 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002378 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002379 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002380
Richard Hughese7299962013-05-01 21:52:12 +01002381 output->base.gamma_size = output->original_crtc->gamma_size;
2382 output->base.set_gamma = drm_output_set_gamma;
2383
Giulio Camuffo954f1832014-10-11 18:27:30 +03002384 weston_plane_init(&output->cursor_plane, b->compositor, 0, 0);
2385 weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002386
Giulio Camuffo954f1832014-10-11 18:27:30 +03002387 weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
2388 weston_compositor_stack_plane(b->compositor, &output->fb_plane,
2389 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002390
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002391 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002392 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002393 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002394 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002395 m->width, m->height, m->refresh / 1000.0,
2396 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2397 ", preferred" : "",
2398 m->flags & WL_OUTPUT_MODE_CURRENT ?
2399 ", current" : "",
2400 connector->count_modes == 0 ?
2401 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002402
Mario Kleiner80817042015-06-21 21:25:11 +02002403 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2404 output->base.native_mode = output->base.current_mode;
2405 output->base.native_scale = output->base.current_scale;
2406
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002407 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002408
John Kåre Alsaker94659272012-11-13 19:10:18 +01002409err_output:
2410 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002411err_free:
2412 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2413 base.link) {
2414 wl_list_remove(&drm_mode->base.link);
2415 free(drm_mode);
2416 }
2417
2418 drmModeFreeCrtc(output->original_crtc);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002419 b->crtc_allocator &= ~(1 << output->crtc_id);
2420 b->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002421 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002422
David Herrmann0f0d54e2011-12-08 17:05:45 +01002423 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002424}
2425
Jesse Barnes58ef3792012-02-23 09:45:49 -05002426static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002427create_sprites(struct drm_backend *b)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002428{
2429 struct drm_sprite *sprite;
2430 drmModePlaneRes *plane_res;
2431 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002432 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002433
Giulio Camuffo954f1832014-10-11 18:27:30 +03002434 plane_res = drmModeGetPlaneResources(b->drm.fd);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002435 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002436 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002437 strerror(errno));
2438 return;
2439 }
2440
2441 for (i = 0; i < plane_res->count_planes; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002442 plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002443 if (!plane)
2444 continue;
2445
Peter Huttererf3d62272013-08-08 11:57:05 +10002446 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002447 plane->count_formats));
2448 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002449 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002450 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002451 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002452 continue;
2453 }
2454
Jesse Barnes58ef3792012-02-23 09:45:49 -05002455 sprite->possible_crtcs = plane->possible_crtcs;
2456 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002457 sprite->current = NULL;
2458 sprite->next = NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002459 sprite->backend = b;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002460 sprite->count_formats = plane->count_formats;
2461 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002462 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002463 drmModeFreePlane(plane);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002464 weston_plane_init(&sprite->plane, b->compositor, 0, 0);
2465 weston_compositor_stack_plane(b->compositor, &sprite->plane,
2466 &b->compositor->primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002467
Giulio Camuffo954f1832014-10-11 18:27:30 +03002468 wl_list_insert(&b->sprite_list, &sprite->link);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002469 }
2470
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002471 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002472}
2473
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002474static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002475destroy_sprites(struct drm_backend *backend)
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002476{
2477 struct drm_sprite *sprite, *next;
2478 struct drm_output *output;
2479
Giulio Camuffo954f1832014-10-11 18:27:30 +03002480 output = container_of(backend->compositor->output_list.next,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002481 struct drm_output, base.link);
2482
Giulio Camuffo954f1832014-10-11 18:27:30 +03002483 wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
2484 drmModeSetPlane(backend->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002485 sprite->plane_id,
2486 output->crtc_id, 0, 0,
2487 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002488 drm_output_release_fb(output, sprite->current);
2489 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002490 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002491 free(sprite);
2492 }
2493}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002494
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002495static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002496create_outputs(struct drm_backend *b, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002497 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002498{
2499 drmModeConnector *connector;
2500 drmModeRes *resources;
2501 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002502 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002503
Giulio Camuffo954f1832014-10-11 18:27:30 +03002504 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002505 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002506 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002507 return -1;
2508 }
2509
Giulio Camuffo954f1832014-10-11 18:27:30 +03002510 b->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
2511 if (!b->crtcs) {
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002512 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002513 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002514 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002515
Giulio Camuffo954f1832014-10-11 18:27:30 +03002516 b->min_width = resources->min_width;
2517 b->max_width = resources->max_width;
2518 b->min_height = resources->min_height;
2519 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002520
Giulio Camuffo954f1832014-10-11 18:27:30 +03002521 b->num_crtcs = resources->count_crtcs;
2522 memcpy(b->crtcs, resources->crtcs, sizeof(uint32_t) * b->num_crtcs);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002523
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002524 for (i = 0; i < resources->count_connectors; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002525 connector = drmModeGetConnector(b->drm.fd,
Benjamin Franzke117483d2011-08-30 11:38:26 +02002526 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002527 if (connector == NULL)
2528 continue;
2529
2530 if (connector->connection == DRM_MODE_CONNECTED &&
2531 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002532 connector->connector_id == option_connector)) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002533 if (create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002534 connector, x, y,
2535 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002536 drmModeFreeConnector(connector);
2537 continue;
2538 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002539
Giulio Camuffo954f1832014-10-11 18:27:30 +03002540 x += container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002541 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002542 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002543 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002544
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002545 drmModeFreeConnector(connector);
2546 }
2547
Giulio Camuffo954f1832014-10-11 18:27:30 +03002548 if (wl_list_empty(&b->compositor->output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002549 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002550 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002551 return -1;
2552 }
2553
2554 drmModeFreeResources(resources);
2555
2556 return 0;
2557}
2558
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002559static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002560update_outputs(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002561{
2562 drmModeConnector *connector;
2563 drmModeRes *resources;
2564 struct drm_output *output, *next;
2565 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002566 uint32_t connected = 0, disconnects = 0;
2567 int i;
2568
Giulio Camuffo954f1832014-10-11 18:27:30 +03002569 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002570 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002571 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002572 return;
2573 }
2574
2575 /* collect new connects */
2576 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002577 int connector_id = resources->connectors[i];
2578
Giulio Camuffo954f1832014-10-11 18:27:30 +03002579 connector = drmModeGetConnector(b->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002580 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002581 continue;
2582
David Herrmann7551cff2011-12-08 17:05:43 +01002583 if (connector->connection != DRM_MODE_CONNECTED) {
2584 drmModeFreeConnector(connector);
2585 continue;
2586 }
2587
Benjamin Franzke117483d2011-08-30 11:38:26 +02002588 connected |= (1 << connector_id);
2589
Giulio Camuffo954f1832014-10-11 18:27:30 +03002590 if (!(b->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002591 struct weston_output *last =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002592 container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002593 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002594
2595 /* XXX: not yet needed, we die with 0 outputs */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002596 if (!wl_list_empty(&b->compositor->output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002597 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002598 else
2599 x = 0;
2600 y = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002601 create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002602 connector, x, y,
2603 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002604 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002605
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002606 }
2607 drmModeFreeConnector(connector);
2608 }
2609 drmModeFreeResources(resources);
2610
Giulio Camuffo954f1832014-10-11 18:27:30 +03002611 disconnects = b->connector_allocator & ~connected;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002612 if (disconnects) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002613 wl_list_for_each_safe(output, next, &b->compositor->output_list,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002614 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002615 if (disconnects & (1 << output->connector_id)) {
2616 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002617 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002618 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002619 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002620 }
2621 }
2622 }
2623
Daniel Stonef556ebe2015-05-21 08:28:58 +01002624 /* FIXME: handle zero outputs, without terminating */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002625 if (b->connector_allocator == 0)
Giulio Camuffo459137b2014-10-11 23:56:24 +03002626 weston_compositor_exit(b->compositor);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002627}
2628
2629static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002630udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002631{
David Herrmannd7488c22012-03-11 20:05:21 +01002632 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002633 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002634
2635 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002636 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002637 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002638
David Herrmann6ac52db2012-03-11 20:05:22 +01002639 val = udev_device_get_property_value(device, "HOTPLUG");
2640 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002641 return 0;
2642
David Herrmann6ac52db2012-03-11 20:05:22 +01002643 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002644}
2645
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002646static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002647udev_drm_event(int fd, uint32_t mask, void *data)
2648{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002649 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002650 struct udev_device *event;
2651
Giulio Camuffo954f1832014-10-11 18:27:30 +03002652 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002653
Giulio Camuffo954f1832014-10-11 18:27:30 +03002654 if (udev_event_is_hotplug(b, event))
2655 update_outputs(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002656
2657 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002658
2659 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002660}
2661
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002662static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002663drm_restore(struct weston_compositor *ec)
2664{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002665 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002666}
2667
2668static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002669drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002670{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002671 struct drm_backend *b = (struct drm_backend *) ec->backend;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002672
Giulio Camuffo954f1832014-10-11 18:27:30 +03002673 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002674
Giulio Camuffo954f1832014-10-11 18:27:30 +03002675 wl_event_source_remove(b->udev_drm_source);
2676 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002677
Giulio Camuffo954f1832014-10-11 18:27:30 +03002678 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002679
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002680 weston_compositor_shutdown(ec);
2681
Giulio Camuffo954f1832014-10-11 18:27:30 +03002682 if (b->gbm)
2683 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002684
Giulio Camuffo954f1832014-10-11 18:27:30 +03002685 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002686
Giulio Camuffo954f1832014-10-11 18:27:30 +03002687 close(b->drm.fd);
Rob Bradford45c15b82013-07-26 16:29:35 +01002688
Giulio Camuffo954f1832014-10-11 18:27:30 +03002689 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002690}
2691
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002692static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002693drm_backend_set_modes(struct drm_backend *backend)
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002694{
2695 struct drm_output *output;
2696 struct drm_mode *drm_mode;
2697 int ret;
2698
Giulio Camuffo954f1832014-10-11 18:27:30 +03002699 wl_list_for_each(output, &backend->compositor->output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002700 if (!output->current) {
2701 /* If something that would cause the output to
2702 * switch mode happened while in another vt, we
2703 * might not have a current drm_fb. In that case,
2704 * schedule a repaint and let drm_output_repaint
2705 * handle setting the mode. */
2706 weston_output_schedule_repaint(&output->base);
2707 continue;
2708 }
2709
Hardeningff39efa2013-09-18 23:56:35 +02002710 drm_mode = (struct drm_mode *) output->base.current_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002711 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002712 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002713 &output->connector_id, 1,
2714 &drm_mode->mode_info);
2715 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002716 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002717 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002718 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002719 output->base.x, output->base.y);
2720 }
2721 }
2722}
2723
2724static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002725session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002726{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002727 struct weston_compositor *compositor = data;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002728 struct drm_backend *b = (struct drm_backend *)compositor->backend;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002729 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002730 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002731
Giulio Camuffo954f1832014-10-11 18:27:30 +03002732 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002733 weston_log("activating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002734 compositor->state = b->prev_state;
2735 drm_backend_set_modes(b);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002736 weston_compositor_damage_all(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002737 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002738 } else {
2739 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002740 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002741
Giulio Camuffo954f1832014-10-11 18:27:30 +03002742 b->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002743 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002744
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002745 /* If we have a repaint scheduled (either from a
2746 * pending pageflip or the idle handler), make sure we
2747 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002748 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002749 * further attemps at repainting. When we switch
2750 * back, we schedule a repaint, which will process
2751 * pending frame callbacks. */
2752
Giulio Camuffo954f1832014-10-11 18:27:30 +03002753 wl_list_for_each(output, &compositor->output_list, base.link) {
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002754 output->base.repaint_needed = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002755 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002756 }
2757
Giulio Camuffo954f1832014-10-11 18:27:30 +03002758 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002759 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002760
Giulio Camuffo954f1832014-10-11 18:27:30 +03002761 wl_list_for_each(sprite, &b->sprite_list, link)
2762 drmModeSetPlane(b->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002763 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002764 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002765 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002766 };
2767}
2768
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002769static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002770switch_vt_binding(struct weston_keyboard *keyboard, uint32_t time,
2771 uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002772{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002773 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002774
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002775 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002776}
2777
David Herrmann0af066f2012-10-29 19:21:16 +01002778/*
2779 * Find primary GPU
2780 * Some systems may have multiple DRM devices attached to a single seat. This
2781 * function loops over all devices and tries to find a PCI device with the
2782 * boot_vga sysfs attribute set to 1.
2783 * If no such device is found, the first DRM device reported by udev is used.
2784 */
2785static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002786find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002787{
2788 struct udev_enumerate *e;
2789 struct udev_list_entry *entry;
2790 const char *path, *device_seat, *id;
2791 struct udev_device *device, *drm_device, *pci;
2792
Giulio Camuffo954f1832014-10-11 18:27:30 +03002793 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002794 udev_enumerate_add_match_subsystem(e, "drm");
2795 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2796
2797 udev_enumerate_scan_devices(e);
2798 drm_device = NULL;
2799 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2800 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002801 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002802 if (!device)
2803 continue;
2804 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2805 if (!device_seat)
2806 device_seat = default_seat;
2807 if (strcmp(device_seat, seat)) {
2808 udev_device_unref(device);
2809 continue;
2810 }
2811
2812 pci = udev_device_get_parent_with_subsystem_devtype(device,
2813 "pci", NULL);
2814 if (pci) {
2815 id = udev_device_get_sysattr_value(pci, "boot_vga");
2816 if (id && !strcmp(id, "1")) {
2817 if (drm_device)
2818 udev_device_unref(drm_device);
2819 drm_device = device;
2820 break;
2821 }
2822 }
2823
2824 if (!drm_device)
2825 drm_device = device;
2826 else
2827 udev_device_unref(device);
2828 }
2829
2830 udev_enumerate_unref(e);
2831 return drm_device;
2832}
2833
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002834static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002835planes_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
2836 void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002837{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002838 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002839
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002840 switch (key) {
2841 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002842 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002843 break;
2844 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002845 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002846 break;
2847 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002848 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002849 break;
2850 default:
2851 break;
2852 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002853}
2854
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002855#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002856static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002857recorder_destroy(struct drm_output *output)
2858{
2859 vaapi_recorder_destroy(output->recorder);
2860 output->recorder = NULL;
2861
2862 output->base.disable_planes--;
2863
2864 wl_list_remove(&output->recorder_frame_listener.link);
2865 weston_log("[libva recorder] done\n");
2866}
2867
2868static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002869recorder_frame_notify(struct wl_listener *listener, void *data)
2870{
2871 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002872 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002873 int fd, ret;
2874
2875 output = container_of(listener, struct drm_output,
2876 recorder_frame_listener);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002877 b = (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002878
2879 if (!output->recorder)
2880 return;
2881
Giulio Camuffo954f1832014-10-11 18:27:30 +03002882 ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002883 DRM_CLOEXEC, &fd);
2884 if (ret) {
2885 weston_log("[libva recorder] "
2886 "failed to create prime fd for front buffer\n");
2887 return;
2888 }
2889
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002890 ret = vaapi_recorder_frame(output->recorder, fd,
2891 output->current->stride);
2892 if (ret < 0) {
2893 weston_log("[libva recorder] aborted: %m\n");
2894 recorder_destroy(output);
2895 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002896}
2897
2898static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002899create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002900 const char *filename)
2901{
2902 int fd;
2903 drm_magic_t magic;
2904
Giulio Camuffo954f1832014-10-11 18:27:30 +03002905 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002906 if (fd < 0)
2907 return NULL;
2908
2909 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002910 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002911
2912 return vaapi_recorder_create(fd, width, height, filename);
2913}
2914
2915static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002916recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002917 void *data)
2918{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002919 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002920 struct drm_output *output;
2921 int width, height;
2922
Giulio Camuffo954f1832014-10-11 18:27:30 +03002923 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002924 struct drm_output, base.link);
2925
2926 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002927 if (output->format != GBM_FORMAT_XRGB8888) {
2928 weston_log("failed to start vaapi recorder: "
2929 "output format not supported\n");
2930 return;
2931 }
2932
Hardeningff39efa2013-09-18 23:56:35 +02002933 width = output->base.current_mode->width;
2934 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002935
2936 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002937 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002938 if (!output->recorder) {
2939 weston_log("failed to create vaapi recorder\n");
2940 return;
2941 }
2942
2943 output->base.disable_planes++;
2944
2945 output->recorder_frame_listener.notify = recorder_frame_notify;
2946 wl_signal_add(&output->base.frame_signal,
2947 &output->recorder_frame_listener);
2948
2949 weston_output_schedule_repaint(&output->base);
2950
2951 weston_log("[libva recorder] initialized\n");
2952 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002953 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002954 }
2955}
2956#else
2957static void
Bryce Harrington4a8a3a12015-07-16 19:12:26 -07002958recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002959 void *data)
2960{
2961 weston_log("Compiled without libva support\n");
2962}
2963#endif
2964
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002965static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002966switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002967{
2968 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002969 bool dmabuf_support_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002970
Giulio Camuffo954f1832014-10-11 18:27:30 +03002971 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002972 return;
2973
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002974 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
2975
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002976 weston_log("Switching to GL renderer\n");
2977
Giulio Camuffo954f1832014-10-11 18:27:30 +03002978 b->gbm = create_gbm_device(b->drm.fd);
2979 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002980 weston_log("Failed to create gbm device. "
2981 "Aborting renderer switch\n");
2982 return;
2983 }
2984
Giulio Camuffo954f1832014-10-11 18:27:30 +03002985 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002986 pixman_renderer_output_destroy(&output->base);
2987
Giulio Camuffo954f1832014-10-11 18:27:30 +03002988 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002989
Giulio Camuffo954f1832014-10-11 18:27:30 +03002990 if (drm_backend_create_gl_renderer(b) < 0) {
2991 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002992 weston_log("Failed to create GL renderer. Quitting.\n");
2993 /* FIXME: we need a function to shutdown cleanly */
2994 assert(0);
2995 }
2996
Giulio Camuffo954f1832014-10-11 18:27:30 +03002997 wl_list_for_each(output, &b->compositor->output_list, base.link)
2998 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002999
Giulio Camuffo954f1832014-10-11 18:27:30 +03003000 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003001
3002 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
3003 if (linux_dmabuf_setup(b->compositor) < 0)
3004 weston_log("Error: initializing dmabuf "
3005 "support failed.\n");
3006 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003007}
3008
3009static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05003010renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
3011 uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003012{
Derek Foreman8ae2db52015-07-15 13:00:36 -05003013 struct drm_backend *b =
3014 (struct drm_backend *) keyboard->seat->compositor;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003015
Giulio Camuffo954f1832014-10-11 18:27:30 +03003016 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003017}
3018
Giulio Camuffo954f1832014-10-11 18:27:30 +03003019static struct drm_backend *
3020drm_backend_create(struct weston_compositor *compositor,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003021 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003022 int *argc, char *argv[],
3023 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003024{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003025 struct drm_backend *b;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003026 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01003027 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003028 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01003029 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003030 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003031
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04003032 weston_log("initializing drm backend\n");
3033
Giulio Camuffo954f1832014-10-11 18:27:30 +03003034 b = zalloc(sizeof *b);
3035 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003036 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01003037
Pekka Paalanen68583832015-05-19 09:53:16 +03003038 /*
3039 * KMS support for hardware planes cannot properly synchronize
3040 * without nuclear page flip. Without nuclear/atomic, hw plane
3041 * and cursor plane updates would either tear or cause extra
3042 * waits for vblanks which means dropping the compositor framerate
3043 * to a fraction.
3044 *
3045 * These can be enabled again when nuclear/atomic support lands.
3046 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003047 b->sprites_are_broken = 1;
3048 b->cursors_are_broken = 1;
3049 b->compositor = compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003050
3051 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003052 if (get_gbm_format_from_section(section,
3053 GBM_FORMAT_XRGB8888,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003054 &b->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003055 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003056
Giulio Camuffo954f1832014-10-11 18:27:30 +03003057 b->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003058
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003059 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003060 compositor->launcher = weston_launcher_connect(compositor, param->tty,
3061 param->seat_id, true);
3062 if (compositor->launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003063 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04003064 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003065 goto err_compositor;
3066 }
3067
Giulio Camuffo954f1832014-10-11 18:27:30 +03003068 b->udev = udev_new();
3069 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003070 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003071 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003072 }
3073
Giulio Camuffo954f1832014-10-11 18:27:30 +03003074 b->session_listener.notify = session_notify;
3075 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003076
Giulio Camuffo954f1832014-10-11 18:27:30 +03003077 drm_device = find_primary_gpu(b, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003078 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003079 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003080 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003081 }
David Herrmann0af066f2012-10-29 19:21:16 +01003082 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003083
Giulio Camuffo954f1832014-10-11 18:27:30 +03003084 if (init_drm(b, drm_device) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003085 weston_log("failed to initialize kms\n");
3086 goto err_udev_dev;
3087 }
3088
Giulio Camuffo954f1832014-10-11 18:27:30 +03003089 if (b->use_pixman) {
3090 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003091 weston_log("failed to initialize pixman renderer\n");
3092 goto err_udev_dev;
3093 }
3094 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003095 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003096 weston_log("failed to initialize egl\n");
3097 goto err_udev_dev;
3098 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003099 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003100
Giulio Camuffo954f1832014-10-11 18:27:30 +03003101 b->base.destroy = drm_destroy;
3102 b->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003103
Giulio Camuffo954f1832014-10-11 18:27:30 +03003104 b->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02003105
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003106 for (key = KEY_F1; key < KEY_F9; key++)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003107 weston_compositor_add_key_binding(compositor, key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003108 MODIFIER_CTRL | MODIFIER_ALT,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003109 switch_vt_binding, compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003110
Giulio Camuffo954f1832014-10-11 18:27:30 +03003111 wl_list_init(&b->sprite_list);
3112 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003113
Giulio Camuffo954f1832014-10-11 18:27:30 +03003114 if (udev_input_init(&b->input,
3115 compositor, b->udev, param->seat_id) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003116 weston_log("failed to create input devices\n");
3117 goto err_sprite;
3118 }
3119
Giulio Camuffo954f1832014-10-11 18:27:30 +03003120 if (create_outputs(b, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003121 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003122 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003123 }
3124
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003125 /* A this point we have some idea of whether or not we have a working
3126 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003127 if (!b->cursors_are_broken)
3128 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003129
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02003130 path = NULL;
3131
Giulio Camuffo954f1832014-10-11 18:27:30 +03003132 loop = wl_display_get_event_loop(compositor->wl_display);
3133 b->drm_source =
3134 wl_event_loop_add_fd(loop, b->drm.fd,
3135 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003136
Giulio Camuffo954f1832014-10-11 18:27:30 +03003137 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3138 if (b->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003139 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003140 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003141 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003142 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003143 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003144 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003145 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003146 udev_monitor_get_fd(b->udev_monitor),
3147 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003148
Giulio Camuffo954f1832014-10-11 18:27:30 +03003149 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003150 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003151 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003152 }
3153
Daniel Stonea96b93c2012-06-22 14:04:37 +01003154 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003155
Giulio Camuffo954f1832014-10-11 18:27:30 +03003156 weston_compositor_add_debug_binding(compositor, KEY_O,
3157 planes_binding, b);
3158 weston_compositor_add_debug_binding(compositor, KEY_C,
3159 planes_binding, b);
3160 weston_compositor_add_debug_binding(compositor, KEY_V,
3161 planes_binding, b);
3162 weston_compositor_add_debug_binding(compositor, KEY_Q,
3163 recorder_binding, b);
3164 weston_compositor_add_debug_binding(compositor, KEY_W,
3165 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003166
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003167 if (compositor->renderer->import_dmabuf) {
3168 if (linux_dmabuf_setup(compositor) < 0)
3169 weston_log("Error: initializing dmabuf "
3170 "support failed.\n");
3171 }
3172
Giulio Camuffo954f1832014-10-11 18:27:30 +03003173 compositor->backend = &b->base;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003174
Giulio Camuffo954f1832014-10-11 18:27:30 +03003175 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003176
3177err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003178 wl_event_source_remove(b->udev_drm_source);
3179 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003180err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003181 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003182err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003183 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003184err_sprite:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003185 gbm_device_destroy(b->gbm);
3186 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003187err_udev_dev:
3188 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003189err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003190 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003191err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003192 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003193err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003194 weston_compositor_shutdown(compositor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003195err_base:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003196 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003197 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003198}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003199
Giulio Camuffo954f1832014-10-11 18:27:30 +03003200WL_EXPORT int
3201backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003202 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003203{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003204 struct drm_backend *b;
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003205 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003206
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003207 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003208 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3209 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3210 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003211 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003212 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003213 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003214
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003215 param.seat_id = default_seat;
3216
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003217 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003218
Giulio Camuffo954f1832014-10-11 18:27:30 +03003219 b = drm_backend_create(compositor, &param, argc, argv, config);
3220 if (b == NULL)
3221 return -1;
3222 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003223}