blob: 1bfe263eefec619186a0384084471c14847413f4 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07005 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040012 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070013 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040025 */
26
Daniel Stonec228e232013-05-22 18:03:19 +030027#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040028
Jesse Barnes58ef3792012-02-23 09:45:49 -050029#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040030#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010031#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040032#include <string.h>
33#include <fcntl.h>
34#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040035#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070036#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030037#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020038#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030039#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030040#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040041
Benjamin Franzkec649a922011-03-02 11:56:04 +010042#include <xf86drm.h>
43#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050044#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010045
Benjamin Franzke060cf802011-04-30 09:32:11 +020046#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040047#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020048
Jon Cruz35b2eaa2015-06-15 15:37:08 -070049#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020050#include "shared/timespec-util.h"
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080051#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040052#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010053#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020054#include "pixman-renderer.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100055#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010056#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030057#include "vaapi-recorder.h"
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020058#include "presentation_timing-server-protocol.h"
Pekka Paalanene4d231e2014-06-12 15:12:48 +030059#include "linux-dmabuf.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040060
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030061#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
62#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
63#endif
64
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030065#ifndef DRM_CAP_CURSOR_WIDTH
66#define DRM_CAP_CURSOR_WIDTH 0x8
67#endif
68
69#ifndef DRM_CAP_CURSOR_HEIGHT
70#define DRM_CAP_CURSOR_HEIGHT 0x9
71#endif
72
73#ifndef GBM_BO_USE_CURSOR
74#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
75#endif
76
Kristian Høgsberg061c4252012-06-28 11:28:15 -040077static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060078
79enum output_config {
80 OUTPUT_CONFIG_INVALID = 0,
81 OUTPUT_CONFIG_OFF,
82 OUTPUT_CONFIG_PREFERRED,
83 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060084 OUTPUT_CONFIG_MODE,
85 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060086};
87
Giulio Camuffo954f1832014-10-11 18:27:30 +030088struct drm_backend {
89 struct weston_backend base;
90 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040091
92 struct udev *udev;
93 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040094
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010095 struct udev_monitor *udev_monitor;
96 struct wl_event_source *udev_drm_source;
97
Benjamin Franzke2af7f102011-03-02 11:14:59 +010098 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010099 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100100 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300101 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100102 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200103 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500104 uint32_t *crtcs;
105 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -0500106 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100107 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700108 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700109 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200110
Rob Clark4339add2012-08-09 14:18:28 -0500111 /* we need these parameters in order to not fail drmModeAddFB2()
112 * due to out of bounds dimensions, and then mistakenly set
113 * sprites_are_broken:
114 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200115 uint32_t min_width, max_width;
116 uint32_t min_height, max_height;
117 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500118
Jesse Barnes58ef3792012-02-23 09:45:49 -0500119 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500120 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200121 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500122
Rob Clarkab5b1e32012-08-09 13:24:45 -0500123 int cursors_are_broken;
124
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200125 int use_pixman;
126
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200127 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300128
Rob Bradfordd355b802013-05-31 18:09:55 +0100129 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300130
Daniel Stone70d337d2015-06-16 18:42:23 +0100131 int32_t cursor_width;
132 int32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400133};
134
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400135struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500136 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400137 drmModeModeInfo mode_info;
138};
139
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300140struct drm_output;
141
142struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300143 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200144 uint32_t fb_id, stride, handle, size;
145 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300146 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200147 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200148
149 /* Used by gbm fbs */
150 struct gbm_bo *bo;
151
152 /* Used by dumb fbs */
153 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300154};
155
Richard Hughes2b2092a2013-04-24 14:58:02 +0100156struct drm_edid {
157 char eisa_id[13];
158 char monitor_name[13];
159 char pnp_id[5];
160 char serial_number[13];
161};
162
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400163struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500164 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400165
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400166 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500167 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400168 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700169 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100170 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300171 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000172 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200173
Daniel Stone36609c72015-06-18 07:49:02 +0100174 enum dpms_enum dpms;
175
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300176 int vblank_pending;
177 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800178 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300179
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400180 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400181 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400182 struct weston_plane cursor_plane;
183 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500184 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400185 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300186 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200187 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200188
189 struct drm_fb *dumb[2];
190 pixman_image_t *image[2];
191 int current_image;
192 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300193
194 struct vaapi_recorder *recorder;
195 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400196};
197
Jesse Barnes58ef3792012-02-23 09:45:49 -0500198/*
199 * An output has a primary display plane plus zero or more sprites for
200 * blending display contents.
201 */
202struct drm_sprite {
203 struct wl_list link;
204
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400205 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500206
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200207 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300208 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300209 struct drm_backend *backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500210
Jesse Barnes58ef3792012-02-23 09:45:49 -0500211 uint32_t possible_crtcs;
212 uint32_t plane_id;
213 uint32_t count_formats;
214
215 int32_t src_x, src_y;
216 uint32_t src_w, src_h;
217 uint32_t dest_x, dest_y;
218 uint32_t dest_w, dest_h;
219
220 uint32_t formats[];
221};
222
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700223struct drm_parameters {
224 int connector;
225 int tty;
226 int use_pixman;
227 const char *seat_id;
228};
229
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300230static struct gl_renderer_interface *gl_renderer;
231
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500232static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400233
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400234static void
235drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400236
Mario Kleinerf507ec32015-06-21 21:25:14 +0200237static void
238drm_output_update_msc(struct drm_output *output, unsigned int seq);
239
Jesse Barnes58ef3792012-02-23 09:45:49 -0500240static int
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200241drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500242{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200243 struct weston_compositor *ec = output->base.compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300244 struct drm_backend *b =(struct drm_backend *)ec->backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500245 int crtc;
246
Giulio Camuffo954f1832014-10-11 18:27:30 +0300247 for (crtc = 0; crtc < b->num_crtcs; crtc++) {
248 if (b->crtcs[crtc] != output->crtc_id)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500249 continue;
250
251 if (supported & (1 << crtc))
252 return -1;
253 }
254
255 return 0;
256}
257
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300258static void
259drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
260{
261 struct drm_fb *fb = data;
262 struct gbm_device *gbm = gbm_bo_get_device(bo);
263
264 if (fb->fb_id)
265 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
266
Pekka Paalanende685b82012-12-04 15:58:12 +0200267 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300268
269 free(data);
270}
271
272static struct drm_fb *
Giulio Camuffo954f1832014-10-11 18:27:30 +0300273drm_fb_create_dumb(struct drm_backend *b, unsigned width, unsigned height)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200274{
275 struct drm_fb *fb;
276 int ret;
277
278 struct drm_mode_create_dumb create_arg;
279 struct drm_mode_destroy_dumb destroy_arg;
280 struct drm_mode_map_dumb map_arg;
281
Peter Huttererf3d62272013-08-08 11:57:05 +1000282 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200283 if (!fb)
284 return NULL;
285
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700286 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200287 create_arg.bpp = 32;
288 create_arg.width = width;
289 create_arg.height = height;
290
Giulio Camuffo954f1832014-10-11 18:27:30 +0300291 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200292 if (ret)
293 goto err_fb;
294
295 fb->handle = create_arg.handle;
296 fb->stride = create_arg.pitch;
297 fb->size = create_arg.size;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300298 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200299
Giulio Camuffo954f1832014-10-11 18:27:30 +0300300 ret = drmModeAddFB(b->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200301 fb->stride, fb->handle, &fb->fb_id);
302 if (ret)
303 goto err_bo;
304
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700305 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200306 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400307 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200308 if (ret)
309 goto err_add_fb;
310
311 fb->map = mmap(0, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300312 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200313 if (fb->map == MAP_FAILED)
314 goto err_add_fb;
315
316 return fb;
317
318err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300319 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200320err_bo:
321 memset(&destroy_arg, 0, sizeof(destroy_arg));
322 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300323 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200324err_fb:
325 free(fb);
326 return NULL;
327}
328
329static void
330drm_fb_destroy_dumb(struct drm_fb *fb)
331{
332 struct drm_mode_destroy_dumb destroy_arg;
333
334 if (!fb->map)
335 return;
336
337 if (fb->fb_id)
338 drmModeRmFB(fb->fd, fb->fb_id);
339
340 weston_buffer_reference(&fb->buffer_ref, NULL);
341
342 munmap(fb->map, fb->size);
343
344 memset(&destroy_arg, 0, sizeof(destroy_arg));
345 destroy_arg.handle = fb->handle;
346 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
347
348 free(fb);
349}
350
351static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500352drm_fb_get_from_bo(struct gbm_bo *bo,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300353 struct drm_backend *backend, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354{
355 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200356 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200357 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300358 int ret;
359
360 if (fb)
361 return fb;
362
Bryce Harringtonde16d892014-11-20 22:21:57 -0800363 fb = zalloc(sizeof *fb);
364 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200365 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366
367 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368
369 width = gbm_bo_get_width(bo);
370 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200371 fb->stride = gbm_bo_get_stride(bo);
372 fb->handle = gbm_bo_get_handle(bo).u32;
373 fb->size = fb->stride * height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300374 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300375
Giulio Camuffo954f1832014-10-11 18:27:30 +0300376 if (backend->min_width > width || width > backend->max_width ||
377 backend->min_height > height ||
378 height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 weston_log("bo geometry out of bounds\n");
380 goto err_free;
381 }
382
383 ret = -1;
384
Giulio Camuffo954f1832014-10-11 18:27:30 +0300385 if (format && !backend->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200386 handles[0] = fb->handle;
387 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200388 offsets[0] = 0;
389
Giulio Camuffo954f1832014-10-11 18:27:30 +0300390 ret = drmModeAddFB2(backend->drm.fd, width, height,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200391 format, handles, pitches, offsets,
392 &fb->fb_id, 0);
393 if (ret) {
394 weston_log("addfb2 failed: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300395 backend->no_addfb2 = 1;
396 backend->sprites_are_broken = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397 }
398 }
399
400 if (ret)
Giulio Camuffo954f1832014-10-11 18:27:30 +0300401 ret = drmModeAddFB(backend->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200402 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200403
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200405 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200406 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300407 }
408
409 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
410
411 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200412
413err_free:
414 free(fb);
415 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300416}
417
418static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500419drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200420{
Pekka Paalanende685b82012-12-04 15:58:12 +0200421 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200422
423 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200424
Pekka Paalanende685b82012-12-04 15:58:12 +0200425 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200426}
427
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200428static void
429drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
430{
431 if (!fb)
432 return;
433
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200434 if (fb->map &&
435 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200436 drm_fb_destroy_dumb(fb);
437 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200438 if (fb->is_client_buffer)
439 gbm_bo_destroy(fb->bo);
440 else
441 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600442 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200443 }
444}
445
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500446static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200447drm_output_check_scanout_format(struct drm_output *output,
448 struct weston_surface *es, struct gbm_bo *bo)
449{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200450 uint32_t format;
451 pixman_region32_t r;
452
453 format = gbm_bo_get_format(bo);
454
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700455 if (format == GBM_FORMAT_ARGB8888) {
456 /* We can scanout an ARGB buffer if the surface's
457 * opaque region covers the whole output, but we have
458 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800459 pixman_region32_init_rect(&r, 0, 0,
460 output->base.width,
461 output->base.height);
462 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200463
464 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500465 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200466
467 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500468 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700469
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000470 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700471 return format;
472
473 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200474}
475
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400476static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200477drm_output_prepare_scanout_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500478 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500479{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300480 struct drm_backend *b =
481 (struct drm_backend *)output->base.compositor->backend;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500482 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200483 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300484 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500485 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500486
Jason Ekstranda7af7042013-10-12 22:38:11 -0500487 if (ev->geometry.x != output->base.x ||
488 ev->geometry.y != output->base.y ||
Giulio Camuffo954f1832014-10-11 18:27:30 +0300489 buffer == NULL || b->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200490 buffer->width != output->base.current_mode->width ||
491 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200492 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500493 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400494 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500495
Pekka Paalanen5580f222015-02-17 16:33:18 +0200496 if (ev->geometry.scissor_enabled)
497 return NULL;
498
Giulio Camuffo954f1832014-10-11 18:27:30 +0300499 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700500 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500501
Rob Bradford9b101872012-09-14 23:25:41 +0100502 /* Unable to use the buffer for scanout */
503 if (!bo)
504 return NULL;
505
Jason Ekstranda7af7042013-10-12 22:38:11 -0500506 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500507 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300508 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400509 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300510 }
511
Giulio Camuffo954f1832014-10-11 18:27:30 +0300512 output->next = drm_fb_get_from_bo(bo, b, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300513 if (!output->next) {
514 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400515 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300516 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500517
Pekka Paalanende685b82012-12-04 15:58:12 +0200518 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500519
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400520 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500521}
522
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500523static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200524drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400525{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300526 struct drm_backend *b =
527 (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300528 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400529
Giulio Camuffo954f1832014-10-11 18:27:30 +0300530 output->base.compositor->renderer->repaint_output(&output->base,
531 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400532
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300533 bo = gbm_surface_lock_front_buffer(output->surface);
534 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200535 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400536 return;
537 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300538
Giulio Camuffo954f1832014-10-11 18:27:30 +0300539 output->next = drm_fb_get_from_bo(bo, b, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300540 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200541 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300542 gbm_surface_release_buffer(output->surface, bo);
543 return;
544 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400545}
546
547static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200548drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
549{
550 struct weston_compositor *ec = output->base.compositor;
551 pixman_region32_t total_damage, previous_damage;
552
553 pixman_region32_init(&total_damage);
554 pixman_region32_init(&previous_damage);
555
556 pixman_region32_copy(&previous_damage, damage);
557
558 pixman_region32_union(&total_damage, damage, &output->previous_damage);
559 pixman_region32_copy(&output->previous_damage, &previous_damage);
560
561 output->current_image ^= 1;
562
563 output->next = output->dumb[output->current_image];
564 pixman_renderer_output_set_buffer(&output->base,
565 output->image[output->current_image]);
566
567 ec->renderer->repaint_output(&output->base, &total_damage);
568
569 pixman_region32_fini(&total_damage);
570 pixman_region32_fini(&previous_damage);
571}
572
573static void
574drm_output_render(struct drm_output *output, pixman_region32_t *damage)
575{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300576 struct weston_compositor *c = output->base.compositor;
577 struct drm_backend *b = (struct drm_backend *)c->backend;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200578
Giulio Camuffo954f1832014-10-11 18:27:30 +0300579 if (b->use_pixman)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200580 drm_output_render_pixman(output, damage);
581 else
582 drm_output_render_gl(output, damage);
583
Giulio Camuffo954f1832014-10-11 18:27:30 +0300584 pixman_region32_subtract(&c->primary_plane.damage,
585 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200586}
587
588static void
Richard Hughese7299962013-05-01 21:52:12 +0100589drm_output_set_gamma(struct weston_output *output_base,
590 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
591{
592 int rc;
593 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300594 struct drm_backend *backend =
595 (struct drm_backend *) output->base.compositor->backend;
Richard Hughese7299962013-05-01 21:52:12 +0100596
597 /* check */
598 if (output_base->gamma_size != size)
599 return;
600 if (!output->original_crtc)
601 return;
602
Giulio Camuffo954f1832014-10-11 18:27:30 +0300603 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +0100604 output->crtc_id,
605 size, r, g, b);
606 if (rc)
607 weston_log("set gamma failed: %m\n");
608}
609
Bryce Harringtonada4f072015-06-30 13:25:46 -0700610/* Determine the type of vblank synchronization to use for the output.
611 *
612 * The pipe parameter indicates which CRTC is in use. Knowing this, we
613 * can determine which vblank sequence type to use for it. Traditional
614 * cards had only two CRTCs, with CRTC 0 using no special flags, and
615 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
616 * parameter indicates this.
617 *
618 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
619 * 0-31. If this is non-zero it indicates we're dealing with a
620 * multi-gpu situation and we need to calculate the vblank sync
621 * using DRM_BLANK_HIGH_CRTC_MASK.
622 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +0300623static unsigned int
624drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200625{
626 if (output->pipe > 1)
627 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
628 DRM_VBLANK_HIGH_CRTC_MASK;
629 else if (output->pipe > 0)
630 return DRM_VBLANK_SECONDARY;
631 else
632 return 0;
633}
634
David Herrmann1edf44c2013-10-22 17:11:26 +0200635static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500636drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400637 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100638{
639 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300640 struct drm_backend *backend =
641 (struct drm_backend *)output->base.compositor->backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500642 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400643 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500644 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100645
Xiong Zhangabd5d472013-10-11 14:43:07 +0800646 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200647 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800648
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300649 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400650 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300651 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200652 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100653
Hardeningff39efa2013-09-18 23:56:35 +0200654 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200655 if (!output->current ||
656 output->current->stride != output->next->stride) {
Giulio Camuffo954f1832014-10-11 18:27:30 +0300657 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300658 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400659 &output->connector_id, 1,
660 &mode->mode_info);
661 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200662 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200663 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400664 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300665 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200666 }
667
Giulio Camuffo954f1832014-10-11 18:27:30 +0300668 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300669 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500670 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200671 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200672 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500673 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100674
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300675 output->page_flip_pending = 1;
676
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400677 drm_output_set_cursor(output);
678
Jesse Barnes58ef3792012-02-23 09:45:49 -0500679 /*
680 * Now, update all the sprite surfaces
681 */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300682 wl_list_for_each(s, &backend->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200683 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500684 drmVBlank vbl = {
685 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
686 .request.sequence = 1,
687 };
688
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200689 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200690 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500691 continue;
692
Giulio Camuffo954f1832014-10-11 18:27:30 +0300693 if (s->next && !backend->sprites_hidden)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200694 fb_id = s->next->fb_id;
695
Giulio Camuffo954f1832014-10-11 18:27:30 +0300696 ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200697 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500698 s->dest_x, s->dest_y,
699 s->dest_w, s->dest_h,
700 s->src_x, s->src_y,
701 s->src_w, s->src_h);
702 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200703 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500704 ret, strerror(errno));
705
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200706 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -0500707
Jesse Barnes58ef3792012-02-23 09:45:49 -0500708 /*
709 * Queue a vblank signal so we know when the surface
710 * becomes active on the display or has been replaced.
711 */
712 vbl.request.signal = (unsigned long)s;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300713 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500714 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200715 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500716 ret, strerror(errno));
717 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300718
719 s->output = output;
720 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500721 }
722
David Herrmann1edf44c2013-10-22 17:11:26 +0200723 return 0;
724
725err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800726 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200727 if (output->next) {
728 drm_output_release_fb(output, output->next);
729 output->next = NULL;
730 }
731
732 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400733}
734
735static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200736drm_output_start_repaint_loop(struct weston_output *output_base)
737{
738 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300739 struct drm_backend *backend = (struct drm_backend *)
740 output_base->compositor->backend;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200741 uint32_t fb_id;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200742 struct timespec ts, tnow;
743 struct timespec vbl2now;
744 int64_t refresh_nsec;
745 int ret;
746 drmVBlank vbl = {
747 .request.type = DRM_VBLANK_RELATIVE,
748 .request.sequence = 0,
749 .request.signal = 0,
750 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300751
Xiong Zhangabd5d472013-10-11 14:43:07 +0800752 if (output->destroy_pending)
753 return;
754
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300755 if (!output->current) {
756 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200757 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300758 }
759
Mario Kleinerf507ec32015-06-21 21:25:14 +0200760 /* Try to get current msc and timestamp via instant query */
761 vbl.request.type |= drm_waitvblank_pipe(output);
762 ret = drmWaitVBlank(backend->drm.fd, &vbl);
763
764 /* Error ret or zero timestamp means failure to get valid timestamp */
765 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
766 ts.tv_sec = vbl.reply.tval_sec;
767 ts.tv_nsec = vbl.reply.tval_usec * 1000;
768
769 /* Valid timestamp for most recent vblank - not stale?
770 * Stale ts could happen on Linux 3.17+, so make sure it
771 * is not older than 1 refresh duration since now.
772 */
773 weston_compositor_read_presentation_clock(backend->compositor,
774 &tnow);
775 timespec_sub(&vbl2now, &tnow, &ts);
776 refresh_nsec =
777 millihz_to_nsec(output->base.current_mode->refresh);
778 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
779 drm_output_update_msc(output, vbl.reply.sequence);
780 weston_output_finish_frame(output_base, &ts,
781 PRESENTATION_FEEDBACK_INVALID);
782 return;
783 }
784 }
785
786 /* Immediate query didn't provide valid timestamp.
787 * Use pageflip fallback.
788 */
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300789 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200790
Giulio Camuffo954f1832014-10-11 18:27:30 +0300791 if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
Jonas Ådahle5a12252013-04-05 23:07:11 +0200792 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
793 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200794 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200795 }
David Herrmann3c688c52013-10-22 17:11:25 +0200796
797 return;
798
799finish_frame:
800 /* if we cannot page-flip, immediately finish frame */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300801 weston_compositor_read_presentation_clock(output_base->compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200802 weston_output_finish_frame(output_base, &ts,
803 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200804}
805
806static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400807drm_output_update_msc(struct drm_output *output, unsigned int seq)
808{
809 uint64_t msc_hi = output->base.msc >> 32;
810
811 if (seq < (output->base.msc & 0xffffffff))
812 msc_hi++;
813
814 output->base.msc = (msc_hi << 32) + seq;
815}
816
817static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
819 void *data)
820{
821 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300822 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400823 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200824 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
825 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300826
Pekka Paalanen641307c2014-09-23 22:08:47 -0400827 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300828 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500829
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200830 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200831 s->current = s->next;
832 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300833
834 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400835 ts.tv_sec = sec;
836 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200837 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300838 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839}
840
841static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800842drm_output_destroy(struct weston_output *output_base);
843
844static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400845page_flip_handler(int fd, unsigned int frame,
846 unsigned int sec, unsigned int usec, void *data)
847{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200848 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400849 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200850 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
851 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
852 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400853
Pekka Paalanen641307c2014-09-23 22:08:47 -0400854 drm_output_update_msc(output, frame);
855
Jonas Ådahle5a12252013-04-05 23:07:11 +0200856 /* We don't set page_flip_pending on start_repaint_loop, in that case
857 * we just want to page flip to the current buffer to get an accurate
858 * timestamp */
859 if (output->page_flip_pending) {
860 drm_output_release_fb(output, output->current);
861 output->current = output->next;
862 output->next = NULL;
863 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300864
Jonas Ådahle5a12252013-04-05 23:07:11 +0200865 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400866
Xiong Zhangabd5d472013-10-11 14:43:07 +0800867 if (output->destroy_pending)
868 drm_output_destroy(&output->base);
869 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400870 ts.tv_sec = sec;
871 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200872 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300873
874 /* We can't call this from frame_notify, because the output's
875 * repaint needed flag is cleared just after that */
876 if (output->recorder)
877 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300878 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200879}
880
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500881static uint32_t
882drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500883 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500884{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500885 uint32_t i, format;
886
887 format = gbm_bo_get_format(bo);
888
889 if (format == GBM_FORMAT_ARGB8888) {
890 pixman_region32_t r;
891
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500892 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600893 ev->surface->width,
894 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500895 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500896
897 if (!pixman_region32_not_empty(&r))
898 format = GBM_FORMAT_XRGB8888;
899
900 pixman_region32_fini(&r);
901 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500902
903 for (i = 0; i < s->count_formats; i++)
904 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500905 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500906
907 return 0;
908}
909
910static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500911drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500912{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500913 return !ev->transform.enabled ||
914 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500915}
916
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400917static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200918drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500919 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500920{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200921 struct weston_compositor *ec = output->base.compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300922 struct drm_backend *b = (struct drm_backend *)ec->backend;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200923 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300924 struct wl_resource *buffer_resource;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925 struct drm_sprite *s;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300926 struct linux_dmabuf_buffer *dmabuf;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500927 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500928 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500929 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200930 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400932 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500933
Giulio Camuffo954f1832014-10-11 18:27:30 +0300934 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200935 return NULL;
936
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200937 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200938 return NULL;
939
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200940 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200941 return NULL;
942
Giulio Camuffo954f1832014-10-11 18:27:30 +0300943 if (b->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400944 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500945
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200946 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400947 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300948
Jason Ekstranda7af7042013-10-12 22:38:11 -0500949 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400950 return NULL;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300951 buffer_resource = ev->surface->buffer_ref.buffer->resource;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500952
Jason Ekstranda7af7042013-10-12 22:38:11 -0500953 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200954 return NULL;
955
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300956 if (wl_shm_buffer_get(buffer_resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500957 return NULL;
958
Jason Ekstranda7af7042013-10-12 22:38:11 -0500959 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400960 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500961
Giulio Camuffo954f1832014-10-11 18:27:30 +0300962 wl_list_for_each(s, &b->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200963 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500964 continue;
965
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200966 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500967 found = 1;
968 break;
969 }
970 }
971
972 /* No sprites available */
973 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400974 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500975
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +0300976 if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) {
977 /* XXX: TODO:
978 *
979 * Use AddFB2 directly, do not go via GBM.
980 * Add support for multiplanar formats.
981 * Both require refactoring in the DRM-backend to
982 * support a mix of gbm_bos and drmfbs.
983 */
984 struct gbm_import_fd_data gbm_dmabuf = {
985 .fd = dmabuf->dmabuf_fd[0],
986 .width = dmabuf->width,
987 .height = dmabuf->height,
988 .stride = dmabuf->stride[0],
989 .format = dmabuf->format
990 };
991
992 if (dmabuf->n_planes != 1 || dmabuf->offset[0] != 0)
993 return NULL;
994
995 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
996 GBM_BO_USE_SCANOUT);
997 } else {
998 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
999 buffer_resource, GBM_BO_USE_SCANOUT);
1000 }
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -04001001 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001002 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -04001003
Jason Ekstranda7af7042013-10-12 22:38:11 -05001004 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001005 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001006 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001007 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001008 }
1009
Giulio Camuffo954f1832014-10-11 18:27:30 +03001010 s->next = drm_fb_get_from_bo(bo, b, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001011 if (!s->next) {
1012 gbm_bo_destroy(bo);
1013 return NULL;
1014 }
1015
Jason Ekstranda7af7042013-10-12 22:38:11 -05001016 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001017
Jason Ekstranda7af7042013-10-12 22:38:11 -05001018 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001019 s->plane.x = box->x1;
1020 s->plane.y = box->y1;
1021
Jesse Barnes58ef3792012-02-23 09:45:49 -05001022 /*
1023 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -05001024 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -05001025 * for us already).
1026 */
1027 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001028 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001029 &output->base.region);
1030 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001031 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001032 tbox = weston_transformed_rect(output->base.width,
1033 output->base.height,
1034 output->base.transform,
1035 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001036 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001037 s->dest_x = tbox.x1;
1038 s->dest_y = tbox.y1;
1039 s->dest_w = tbox.x2 - tbox.x1;
1040 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001041 pixman_region32_fini(&dest_rect);
1042
1043 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001044 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001045 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001046 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001047
Jason Ekstranda7af7042013-10-12 22:38:11 -05001048 weston_view_from_global_fixed(ev,
1049 wl_fixed_from_int(box->x1),
1050 wl_fixed_from_int(box->y1),
1051 &sx1, &sy1);
1052 weston_view_from_global_fixed(ev,
1053 wl_fixed_from_int(box->x2),
1054 wl_fixed_from_int(box->y2),
1055 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001056
1057 if (sx1 < 0)
1058 sx1 = 0;
1059 if (sy1 < 0)
1060 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001061 if (sx2 > wl_fixed_from_int(ev->surface->width))
1062 sx2 = wl_fixed_from_int(ev->surface->width);
1063 if (sy2 > wl_fixed_from_int(ev->surface->height))
1064 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001065
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001066 tbox.x1 = sx1;
1067 tbox.y1 = sy1;
1068 tbox.x2 = sx2;
1069 tbox.y2 = sy2;
1070
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001071 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
1072 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001073 viewport->buffer.transform,
1074 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01001075 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001076
1077 s->src_x = tbox.x1 << 8;
1078 s->src_y = tbox.y1 << 8;
1079 s->src_w = (tbox.x2 - tbox.x1) << 8;
1080 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001081 pixman_region32_fini(&src_rect);
1082
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001083 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001084}
1085
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001086static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001087drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001088 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001089{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001090 struct drm_backend *b =
1091 (struct drm_backend *)output->base.compositor->backend;
Neil Robertsf37f82c2014-05-01 18:00:41 +01001092 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001093
Giulio Camuffo954f1832014-10-11 18:27:30 +03001094 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001095 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +02001096 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1097 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001098 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001099 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001100 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001101 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001102 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001103 return NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001104 if (b->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001105 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001106 if (ev->geometry.scissor_enabled)
1107 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001108 if (ev->surface->buffer_ref.buffer == NULL ||
1109 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Daniel Stone70d337d2015-06-16 18:42:23 +01001110 ev->surface->width > b->cursor_width ||
1111 ev->surface->height > b->cursor_height)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001112 return NULL;
1113
Jason Ekstranda7af7042013-10-12 22:38:11 -05001114 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001115
1116 return &output->cursor_plane;
1117}
1118
Pekka Paalanend0ead482014-06-16 12:05:40 +03001119/**
1120 * Update the image for the current cursor surface
1121 *
1122 * @param b DRM backend structure
1123 * @param bo GBM buffer object to write into
1124 * @param ev View to use for cursor image
1125 */
1126static void
1127cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
1128 struct weston_view *ev)
1129{
1130 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
1131 uint32_t buf[b->cursor_width * b->cursor_height];
1132 int32_t stride;
1133 uint8_t *s;
1134 int i;
1135
1136 assert(buffer && buffer->shm_buffer);
1137 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
1138 assert(ev->surface->width <= b->cursor_width);
1139 assert(ev->surface->height <= b->cursor_height);
1140
1141 memset(buf, 0, sizeof buf);
1142 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1143 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1144
1145 wl_shm_buffer_begin_access(buffer->shm_buffer);
1146 for (i = 0; i < ev->surface->height; i++)
1147 memcpy(buf + i * b->cursor_width,
1148 s + i * stride,
1149 ev->surface->width * 4);
1150 wl_shm_buffer_end_access(buffer->shm_buffer);
1151
1152 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
1153 weston_log("failed update cursor: %m\n");
1154}
1155
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001156static void
1157drm_output_set_cursor(struct drm_output *output)
1158{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001159 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001160 struct weston_buffer *buffer;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001161 struct drm_backend *b =
1162 (struct drm_backend *) output->base.compositor->backend;
Pekka Paalanend0ead482014-06-16 12:05:40 +03001163 EGLint handle;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001164 struct gbm_bo *bo;
Pekka Paalanend0ead482014-06-16 12:05:40 +03001165 int x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001166
Jason Ekstranda7af7042013-10-12 22:38:11 -05001167 output->cursor_view = NULL;
1168 if (ev == NULL) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001169 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001170 return;
1171 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001172
Neil Robertse5051712013-11-13 15:44:06 +00001173 buffer = ev->surface->buffer_ref.buffer;
1174
1175 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001176 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001177 pixman_region32_fini(&output->cursor_plane.damage);
1178 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001179 output->current_cursor ^= 1;
1180 bo = output->cursor_bo[output->current_cursor];
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001181
Pekka Paalanend0ead482014-06-16 12:05:40 +03001182 cursor_bo_update(b, bo, ev);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001183 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001184 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
1185 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001186 weston_log("failed to set cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001187 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001188 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001189 }
1190
Jason Ekstranda7af7042013-10-12 22:38:11 -05001191 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1192 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001193 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001194 if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001195 weston_log("failed to move cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001196 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001197 }
1198
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001199 output->cursor_plane.x = x;
1200 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001201 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001202}
1203
Jesse Barnes58ef3792012-02-23 09:45:49 -05001204static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001205drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001206{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001207 struct drm_backend *b =
1208 (struct drm_backend *)output_base->compositor->backend;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001209 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001210 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001211 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001212 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001213
1214 /*
1215 * Find a surface for each sprite in the output using some heuristics:
1216 * 1) size
1217 * 2) frequency of update
1218 * 3) opacity (though some hw might support alpha blending)
1219 * 4) clipping (this can be fixed with color keys)
1220 *
1221 * The idea is to save on blitting since this should save power.
1222 * If we can get a large video surface on the sprite for example,
1223 * the main display surface may not need to update at all, and
1224 * the client buffer can be used directly for the sprite surface
1225 * as we do for flipping full screen surfaces.
1226 */
1227 pixman_region32_init(&overlap);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001228 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001229
Giulio Camuffo954f1832014-10-11 18:27:30 +03001230 wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001231 struct weston_surface *es = ev->surface;
1232
1233 /* Test whether this buffer can ever go into a plane:
1234 * non-shm, or small enough to be a cursor.
1235 *
1236 * Also, keep a reference when using the pixman renderer.
1237 * That makes it possible to do a seamless switch to the GL
1238 * renderer and since the pixman renderer keeps a reference
1239 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001240 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001241 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001242 (es->buffer_ref.buffer &&
1243 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001244 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001245 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001246 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001247 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001248
Jesse Barnes58ef3792012-02-23 09:45:49 -05001249 pixman_region32_init(&surface_overlap);
1250 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001251 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001252
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001253 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001254 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001255 next_plane = primary;
1256 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001257 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001258 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001259 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001260 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001261 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001262 if (next_plane == NULL)
1263 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001264
Jason Ekstranda7af7042013-10-12 22:38:11 -05001265 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001266
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001267 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001268 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001269 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001270
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001271 if (next_plane == primary ||
1272 next_plane == &output->cursor_plane) {
1273 /* cursor plane involves a copy */
1274 ev->psf_flags = 0;
1275 } else {
1276 /* All other planes are a direct scanout of a
1277 * single client buffer.
1278 */
1279 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1280 }
1281
Jesse Barnes58ef3792012-02-23 09:45:49 -05001282 pixman_region32_fini(&surface_overlap);
1283 }
1284 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001285}
1286
Matt Roper361d2ad2011-08-29 13:52:23 -07001287static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001288drm_output_fini_pixman(struct drm_output *output);
1289
1290static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001291drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001292{
1293 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001294 struct drm_backend *b =
1295 (struct drm_backend *)output->base.compositor->backend;
Matt Roper361d2ad2011-08-29 13:52:23 -07001296 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001297
Xiong Zhangabd5d472013-10-11 14:43:07 +08001298 if (output->page_flip_pending) {
1299 output->destroy_pending = 1;
1300 weston_log("destroy output while page flip pending\n");
1301 return;
1302 }
1303
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001304 if (output->backlight)
1305 backlight_destroy(output->backlight);
1306
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001307 drmModeFreeProperty(output->dpms_prop);
1308
Matt Roper361d2ad2011-08-29 13:52:23 -07001309 /* Turn off hardware cursor */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001310 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001311
1312 /* Restore original CRTC state */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001313 drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001314 origcrtc->x, origcrtc->y,
1315 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001316 drmModeFreeCrtc(origcrtc);
1317
Giulio Camuffo954f1832014-10-11 18:27:30 +03001318 b->crtc_allocator &= ~(1 << output->crtc_id);
1319 b->connector_allocator &= ~(1 << output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001320
Giulio Camuffo954f1832014-10-11 18:27:30 +03001321 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001322 drm_output_fini_pixman(output);
1323 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001324 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001325 gbm_surface_destroy(output->surface);
1326 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001327
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001328 weston_plane_release(&output->fb_plane);
1329 weston_plane_release(&output->cursor_plane);
1330
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001331 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001332
Matt Roper361d2ad2011-08-29 13:52:23 -07001333 free(output);
1334}
1335
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001336/**
1337 * Find the closest-matching mode for a given target
1338 *
1339 * Given a target mode, find the most suitable mode amongst the output's
1340 * current mode list to use, preferring the current mode if possible, to
1341 * avoid an expensive mode switch.
1342 *
1343 * @param output DRM output
1344 * @param target_mode Mode to attempt to match
1345 * @returns Pointer to a mode from the output's mode list
1346 */
Alex Wub7b8bda2012-04-17 17:20:48 +08001347static struct drm_mode *
1348choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1349{
1350 struct drm_mode *tmp_mode = NULL, *mode;
1351
Hardeningff39efa2013-09-18 23:56:35 +02001352 if (output->base.current_mode->width == target_mode->width &&
1353 output->base.current_mode->height == target_mode->height &&
1354 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001355 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001356 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001357
1358 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1359 if (mode->mode_info.hdisplay == target_mode->width &&
1360 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001361 if (mode->base.refresh == target_mode->refresh ||
1362 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001363 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001364 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001365 tmp_mode = mode;
1366 }
1367 }
1368
1369 return tmp_mode;
1370}
1371
1372static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001373drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001374static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001375drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001376
1377static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001378drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1379{
1380 struct drm_output *output;
1381 struct drm_mode *drm_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001382 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08001383
1384 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001385 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001386 return -1;
1387 }
1388
1389 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001390 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001391 return -1;
1392 }
1393
Giulio Camuffo954f1832014-10-11 18:27:30 +03001394 b = (struct drm_backend *)output_base->compositor->backend;
Alex Wub7b8bda2012-04-17 17:20:48 +08001395 output = (struct drm_output *)output_base;
1396 drm_mode = choose_mode (output, mode);
1397
1398 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001399 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001400 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001401 }
1402
Hardeningff39efa2013-09-18 23:56:35 +02001403 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001404 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001405
Hardeningff39efa2013-09-18 23:56:35 +02001406 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001407
Hardeningff39efa2013-09-18 23:56:35 +02001408 output->base.current_mode = &drm_mode->base;
1409 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001410 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1411
Alex Wub7b8bda2012-04-17 17:20:48 +08001412 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001413 drm_output_release_fb(output, output->current);
1414 drm_output_release_fb(output, output->next);
1415 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001416
Giulio Camuffo954f1832014-10-11 18:27:30 +03001417 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001418 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001419 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001420 weston_log("failed to init output pixman state with "
1421 "new mode\n");
1422 return -1;
1423 }
1424 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001425 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001426 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001427
Giulio Camuffo954f1832014-10-11 18:27:30 +03001428 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001429 weston_log("failed to init output egl state with "
1430 "new mode");
1431 return -1;
1432 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001433 }
1434
Alex Wub7b8bda2012-04-17 17:20:48 +08001435 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001436}
1437
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001438static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001439on_drm_input(int fd, uint32_t mask, void *data)
1440{
1441 drmEventContext evctx;
1442
1443 memset(&evctx, 0, sizeof evctx);
1444 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1445 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001446 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001447 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001448
1449 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001450}
1451
1452static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001453init_drm(struct drm_backend *b, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001454{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001455 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001456 uint64_t cap;
1457 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001458 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001459
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001460 sysnum = udev_device_get_sysnum(device);
1461 if (sysnum)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001462 b->drm.id = atoi(sysnum);
1463 if (!sysnum || b->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001464 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001465 return -1;
1466 }
1467
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001468 filename = udev_device_get_devnode(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001469 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001470 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001471 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001472 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001473 udev_device_get_devnode(device));
1474 return -1;
1475 }
1476
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001477 weston_log("using %s\n", filename);
1478
Giulio Camuffo954f1832014-10-11 18:27:30 +03001479 b->drm.fd = fd;
1480 b->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001481
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001482 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1483 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001484 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001485 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001486 clk_id = CLOCK_REALTIME;
1487
Giulio Camuffo954f1832014-10-11 18:27:30 +03001488 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001489 weston_log("Error: failed to set presentation clock %d.\n",
1490 clk_id);
1491 return -1;
1492 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001493
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001494 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1495 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001496 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001497 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001498 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001499
1500 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1501 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001502 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001503 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001504 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001505
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001506 return 0;
1507}
1508
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001509static struct gbm_device *
1510create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001511{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001512 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001513
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001514 gl_renderer = weston_load_module("gl-renderer.so",
1515 "gl_renderer_interface");
1516 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001517 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001518
1519 /* GBM will load a dri driver, but even though they need symbols from
1520 * libglapi, in some version of Mesa they are not linked to it. Since
1521 * only the gl-renderer module links to it, the call above won't make
1522 * these symbols globally available, and loading the DRI driver fails.
1523 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1524 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1525
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001526 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001527
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001528 return gbm;
1529}
1530
Bryce Harringtonc056a982015-05-19 15:25:18 -07001531/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001532 * we may be able to susbstitute an ARGB format for an XRGB one.
1533 *
1534 * This returns 0 if substitution isn't possible, but 0 might be a
1535 * legitimate format for other EGL platforms, so the caller is
1536 * responsible for checking for 0 before calling gl_renderer->create().
1537 *
1538 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1539 * but it's entirely possible we'll see this again on other implementations.
1540 */
1541static int
1542fallback_format_for(uint32_t format)
1543{
1544 switch (format) {
1545 case GBM_FORMAT_XRGB8888:
1546 return GBM_FORMAT_ARGB8888;
1547 case GBM_FORMAT_XRGB2101010:
1548 return GBM_FORMAT_ARGB2101010;
1549 default:
1550 return 0;
1551 }
1552}
1553
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001554static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001555drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001556{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001557 EGLint format[2] = {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001558 b->format,
1559 fallback_format_for(b->format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05001560 };
1561 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001562
Derek Foremanc4cfe852015-05-15 12:12:40 -05001563 if (format[1])
1564 n_formats = 2;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001565 if (gl_renderer->create(b->compositor,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001566 EGL_PLATFORM_GBM_KHR,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001567 (void *)b->gbm,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001568 gl_renderer->opaque_attribs,
1569 format,
1570 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001571 return -1;
1572 }
1573
1574 return 0;
1575}
1576
1577static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001578init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001579{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001580 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001581
Giulio Camuffo954f1832014-10-11 18:27:30 +03001582 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001583 return -1;
1584
Giulio Camuffo954f1832014-10-11 18:27:30 +03001585 if (drm_backend_create_gl_renderer(b) < 0) {
1586 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001587 return -1;
1588 }
1589
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001590 return 0;
1591}
1592
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001593static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001594init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001595{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001596 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001597}
1598
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001599/**
1600 * Add a mode to output's mode list
1601 *
1602 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
1603 * output's mode list.
1604 *
1605 * @param output DRM output to add mode to
1606 * @param info DRM mode structure to add
1607 * @returns Newly-allocated Weston/DRM mode structure
1608 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001609static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001610drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001611{
1612 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001613 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001614
1615 mode = malloc(sizeof *mode);
1616 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001617 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001618
1619 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001620 mode->base.width = info->hdisplay;
1621 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001622
1623 /* Calculate higher precision (mHz) refresh rate */
1624 refresh = (info->clock * 1000000LL / info->htotal +
1625 info->vtotal / 2) / info->vtotal;
1626
1627 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1628 refresh *= 2;
1629 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1630 refresh /= 2;
1631 if (info->vscan > 1)
1632 refresh /= info->vscan;
1633
1634 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001635 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001636
1637 if (info->type & DRM_MODE_TYPE_PREFERRED)
1638 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1639
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001640 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1641
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001642 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001643}
1644
1645static int
1646drm_subpixel_to_wayland(int drm_value)
1647{
1648 switch (drm_value) {
1649 default:
1650 case DRM_MODE_SUBPIXEL_UNKNOWN:
1651 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1652 case DRM_MODE_SUBPIXEL_NONE:
1653 return WL_OUTPUT_SUBPIXEL_NONE;
1654 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1655 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1656 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1657 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1658 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1659 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1660 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1661 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1662 }
1663}
1664
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001665/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001666static uint32_t
1667drm_get_backlight(struct drm_output *output)
1668{
1669 long brightness, max_brightness, norm;
1670
1671 brightness = backlight_get_brightness(output->backlight);
1672 max_brightness = backlight_get_max_brightness(output->backlight);
1673
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001674 /* convert it on a scale of 0 to 255 */
1675 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001676
1677 return (uint32_t) norm;
1678}
1679
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001680/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001681static void
1682drm_set_backlight(struct weston_output *output_base, uint32_t value)
1683{
1684 struct drm_output *output = (struct drm_output *) output_base;
1685 long max_brightness, new_brightness;
1686
1687 if (!output->backlight)
1688 return;
1689
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001690 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001691 return;
1692
1693 max_brightness = backlight_get_max_brightness(output->backlight);
1694
1695 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001696 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001697
1698 backlight_set_brightness(output->backlight, new_brightness);
1699}
1700
1701static drmModePropertyPtr
1702drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1703{
1704 drmModePropertyPtr props;
1705 int i;
1706
1707 for (i = 0; i < connector->count_props; i++) {
1708 props = drmModeGetProperty(fd, connector->props[i]);
1709 if (!props)
1710 continue;
1711
1712 if (!strcmp(props->name, name))
1713 return props;
1714
1715 drmModeFreeProperty(props);
1716 }
1717
1718 return NULL;
1719}
1720
1721static void
1722drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1723{
1724 struct drm_output *output = (struct drm_output *) output_base;
1725 struct weston_compositor *ec = output_base->compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001726 struct drm_backend *b = (struct drm_backend *)ec->backend;
Daniel Stone36609c72015-06-18 07:49:02 +01001727 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001728
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001729 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001730 return;
1731
Daniel Stone36609c72015-06-18 07:49:02 +01001732 ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
1733 output->dpms_prop->prop_id, level);
1734 if (ret) {
1735 weston_log("DRM: DPMS: failed property set for %s\n",
1736 output->base.name);
1737 return;
1738 }
1739
1740 output->dpms = level;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001741}
1742
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001743static const char * const connector_type_names[] = {
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001744 "None",
1745 "VGA",
1746 "DVI",
1747 "DVI",
1748 "DVI",
1749 "Composite",
1750 "TV",
1751 "LVDS",
1752 "CTV",
1753 "DIN",
1754 "DP",
1755 "HDMI",
1756 "HDMI",
1757 "TV",
1758 "eDP",
1759};
1760
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001761static char *
1762make_connector_name(const drmModeConnector *con)
1763{
1764 char name[32];
1765 const char *type_name;
1766
1767 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1768 type_name = connector_type_names[con->connector_type];
1769 else
1770 type_name = "UNKNOWN";
1771 snprintf(name, sizeof name, "%s%d", type_name, con->connector_type_id);
1772
1773 return strdup(name);
1774}
1775
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001776static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001777find_crtc_for_connector(struct drm_backend *b,
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001778 drmModeRes *resources, drmModeConnector *connector)
1779{
1780 drmModeEncoder *encoder;
1781 uint32_t possible_crtcs;
1782 int i, j;
1783
1784 for (j = 0; j < connector->count_encoders; j++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001785 encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001786 if (encoder == NULL) {
1787 weston_log("Failed to get encoder.\n");
1788 return -1;
1789 }
1790 possible_crtcs = encoder->possible_crtcs;
1791 drmModeFreeEncoder(encoder);
1792
1793 for (i = 0; i < resources->count_crtcs; i++) {
1794 if (possible_crtcs & (1 << i) &&
Giulio Camuffo954f1832014-10-11 18:27:30 +03001795 !(b->crtc_allocator & (1 << resources->crtcs[i])))
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001796 return i;
1797 }
1798 }
1799
1800 return -1;
1801}
1802
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001803/* Init output state that depends on gl or gbm */
1804static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001805drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001806{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001807 EGLint format[2] = {
1808 output->format,
1809 fallback_format_for(output->format),
1810 };
1811 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001812
Giulio Camuffo954f1832014-10-11 18:27:30 +03001813 output->surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001814 output->base.current_mode->width,
1815 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001816 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001817 GBM_BO_USE_SCANOUT |
1818 GBM_BO_USE_RENDERING);
1819 if (!output->surface) {
1820 weston_log("failed to create gbm surface\n");
1821 return -1;
1822 }
1823
Derek Foremanc4cfe852015-05-15 12:12:40 -05001824 if (format[1])
1825 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001826 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001827 (EGLNativeDisplayType)output->surface,
1828 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001829 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001830 format,
1831 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001832 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001833 gbm_surface_destroy(output->surface);
1834 return -1;
1835 }
1836
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001837 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001838
1839 for (i = 0; i < 2; i++) {
1840 if (output->cursor_bo[i])
1841 continue;
1842
1843 output->cursor_bo[i] =
Giulio Camuffo954f1832014-10-11 18:27:30 +03001844 gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001845 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001846 }
1847
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001848 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1849 weston_log("cursor buffers unavailable, using gl cursors\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001850 b->cursors_are_broken = 1;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001851 }
1852
1853 return 0;
1854}
1855
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001856static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001857drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001858{
Hardeningff39efa2013-09-18 23:56:35 +02001859 int w = output->base.current_mode->width;
1860 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001861 unsigned int i;
1862
1863 /* FIXME error checking */
1864
1865 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001866 output->dumb[i] = drm_fb_create_dumb(b, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001867 if (!output->dumb[i])
1868 goto err;
1869
1870 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001871 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001872 output->dumb[i]->map,
1873 output->dumb[i]->stride);
1874 if (!output->image[i])
1875 goto err;
1876 }
1877
1878 if (pixman_renderer_output_create(&output->base) < 0)
1879 goto err;
1880
1881 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001882 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001883
1884 return 0;
1885
1886err:
1887 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1888 if (output->dumb[i])
1889 drm_fb_destroy_dumb(output->dumb[i]);
1890 if (output->image[i])
1891 pixman_image_unref(output->image[i]);
1892
1893 output->dumb[i] = NULL;
1894 output->image[i] = NULL;
1895 }
1896
1897 return -1;
1898}
1899
1900static void
1901drm_output_fini_pixman(struct drm_output *output)
1902{
1903 unsigned int i;
1904
1905 pixman_renderer_output_destroy(&output->base);
1906 pixman_region32_fini(&output->previous_damage);
1907
1908 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1909 drm_fb_destroy_dumb(output->dumb[i]);
1910 pixman_image_unref(output->image[i]);
1911 output->dumb[i] = NULL;
1912 output->image[i] = NULL;
1913 }
1914}
1915
Richard Hughes2b2092a2013-04-24 14:58:02 +01001916static void
1917edid_parse_string(const uint8_t *data, char text[])
1918{
1919 int i;
1920 int replaced = 0;
1921
1922 /* this is always 12 bytes, but we can't guarantee it's null
1923 * terminated or not junk. */
1924 strncpy(text, (const char *) data, 12);
1925
1926 /* remove insane chars */
1927 for (i = 0; text[i] != '\0'; i++) {
1928 if (text[i] == '\n' ||
1929 text[i] == '\r') {
1930 text[i] = '\0';
1931 break;
1932 }
1933 }
1934
1935 /* ensure string is printable */
1936 for (i = 0; text[i] != '\0'; i++) {
1937 if (!isprint(text[i])) {
1938 text[i] = '-';
1939 replaced++;
1940 }
1941 }
1942
1943 /* if the string is random junk, ignore the string */
1944 if (replaced > 4)
1945 text[0] = '\0';
1946}
1947
1948#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1949#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1950#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1951#define EDID_OFFSET_DATA_BLOCKS 0x36
1952#define EDID_OFFSET_LAST_BLOCK 0x6c
1953#define EDID_OFFSET_PNPID 0x08
1954#define EDID_OFFSET_SERIAL 0x0c
1955
1956static int
1957edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1958{
1959 int i;
1960 uint32_t serial_number;
1961
1962 /* check header */
1963 if (length < 128)
1964 return -1;
1965 if (data[0] != 0x00 || data[1] != 0xff)
1966 return -1;
1967
1968 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1969 * /--08--\/--09--\
1970 * 7654321076543210
1971 * |\---/\---/\---/
1972 * R C1 C2 C3 */
1973 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1974 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1975 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1976 edid->pnp_id[3] = '\0';
1977
1978 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1979 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1980 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1981 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1982 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1983 if (serial_number > 0)
1984 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1985
1986 /* parse EDID data */
1987 for (i = EDID_OFFSET_DATA_BLOCKS;
1988 i <= EDID_OFFSET_LAST_BLOCK;
1989 i += 18) {
1990 /* ignore pixel clock data */
1991 if (data[i] != 0)
1992 continue;
1993 if (data[i+2] != 0)
1994 continue;
1995
1996 /* any useful blocks? */
1997 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1998 edid_parse_string(&data[i+5],
1999 edid->monitor_name);
2000 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
2001 edid_parse_string(&data[i+5],
2002 edid->serial_number);
2003 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
2004 edid_parse_string(&data[i+5],
2005 edid->eisa_id);
2006 }
2007 }
2008 return 0;
2009}
2010
2011static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002012find_and_parse_output_edid(struct drm_backend *b,
Richard Hughes2b2092a2013-04-24 14:58:02 +01002013 struct drm_output *output,
2014 drmModeConnector *connector)
2015{
2016 drmModePropertyBlobPtr edid_blob = NULL;
2017 drmModePropertyPtr property;
2018 int i;
2019 int rc;
2020
2021 for (i = 0; i < connector->count_props && !edid_blob; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002022 property = drmModeGetProperty(b->drm.fd, connector->props[i]);
Richard Hughes2b2092a2013-04-24 14:58:02 +01002023 if (!property)
2024 continue;
2025 if ((property->flags & DRM_MODE_PROP_BLOB) &&
2026 !strcmp(property->name, "EDID")) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002027 edid_blob = drmModeGetPropertyBlob(b->drm.fd,
Richard Hughes2b2092a2013-04-24 14:58:02 +01002028 connector->prop_values[i]);
2029 }
2030 drmModeFreeProperty(property);
2031 }
2032 if (!edid_blob)
2033 return;
2034
2035 rc = edid_parse(&output->edid,
2036 edid_blob->data,
2037 edid_blob->length);
2038 if (!rc) {
2039 weston_log("EDID data '%s', '%s', '%s'\n",
2040 output->edid.pnp_id,
2041 output->edid.monitor_name,
2042 output->edid.serial_number);
2043 if (output->edid.pnp_id[0] != '\0')
2044 output->base.make = output->edid.pnp_id;
2045 if (output->edid.monitor_name[0] != '\0')
2046 output->base.model = output->edid.monitor_name;
2047 if (output->edid.serial_number[0] != '\0')
2048 output->base.serial_number = output->edid.serial_number;
2049 }
2050 drmModeFreePropertyBlob(edid_blob);
2051}
2052
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002053
2054
2055static int
2056parse_modeline(const char *s, drmModeModeInfo *mode)
2057{
2058 char hsync[16];
2059 char vsync[16];
2060 float fclock;
2061
2062 mode->type = DRM_MODE_TYPE_USERDEF;
2063 mode->hskew = 0;
2064 mode->vscan = 0;
2065 mode->vrefresh = 0;
2066 mode->flags = 0;
2067
Rob Bradford307e09e2013-07-26 16:29:40 +01002068 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002069 &fclock,
2070 &mode->hdisplay,
2071 &mode->hsync_start,
2072 &mode->hsync_end,
2073 &mode->htotal,
2074 &mode->vdisplay,
2075 &mode->vsync_start,
2076 &mode->vsync_end,
2077 &mode->vtotal, hsync, vsync) != 11)
2078 return -1;
2079
2080 mode->clock = fclock * 1000;
2081 if (strcmp(hsync, "+hsync") == 0)
2082 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2083 else if (strcmp(hsync, "-hsync") == 0)
2084 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2085 else
2086 return -1;
2087
2088 if (strcmp(vsync, "+vsync") == 0)
2089 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2090 else if (strcmp(vsync, "-vsync") == 0)
2091 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2092 else
2093 return -1;
2094
2095 return 0;
2096}
2097
Rob Bradford66bd9f52013-06-25 18:56:42 +01002098static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002099setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01002100 struct weston_output *output,
2101 const char *s)
2102{
2103 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05002104 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01002105 struct udev_seat *seat;
2106
Giulio Camuffo954f1832014-10-11 18:27:30 +03002107 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05002108 if (!seat)
2109 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01002110
Derek Foreman0720ea32015-07-15 13:00:35 -05002111 seat->base.output = output;
2112
Derek Foreman1281a362015-07-31 16:55:32 -05002113 pointer = weston_seat_get_pointer(&seat->base);
2114 if (pointer)
2115 weston_pointer_clamp(pointer,
2116 &pointer->x,
2117 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002118 }
2119}
2120
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002121static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002122get_gbm_format_from_section(struct weston_config_section *section,
2123 uint32_t default_value,
2124 uint32_t *format)
2125{
2126 char *s;
2127 int ret = 0;
2128
2129 weston_config_section_get_string(section,
2130 "gbm-format", &s, NULL);
2131
2132 if (s == NULL)
2133 *format = default_value;
2134 else if (strcmp(s, "xrgb8888") == 0)
2135 *format = GBM_FORMAT_XRGB8888;
2136 else if (strcmp(s, "rgb565") == 0)
2137 *format = GBM_FORMAT_RGB565;
2138 else if (strcmp(s, "xrgb2101010") == 0)
2139 *format = GBM_FORMAT_XRGB2101010;
2140 else {
2141 weston_log("fatal: unrecognized pixel format: %s\n", s);
2142 ret = -1;
2143 }
2144
2145 free(s);
2146
2147 return ret;
2148}
2149
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002150/**
2151 * Choose suitable mode for an output
2152 *
2153 * Find the most suitable mode to use for initial setup (or reconfiguration on
2154 * hotplug etc) for a DRM output.
2155 *
2156 * @param output DRM output to choose mode for
2157 * @param kind Strategy and preference to use when choosing mode
2158 * @param width Desired width for this output
2159 * @param height Desired height for this output
2160 * @param current_mode Mode currently being displayed on this output
2161 * @param modeline Manually-entered mode (may be NULL)
2162 * @returns A mode from the output's mode list, or NULL if none available
2163 */
2164static struct drm_mode *
2165drm_output_choose_initial_mode(struct drm_output *output,
2166 enum output_config kind,
2167 int width, int height,
2168 const drmModeModeInfo *current_mode,
2169 const drmModeModeInfo *modeline)
2170{
2171 struct drm_mode *preferred = NULL;
2172 struct drm_mode *current = NULL;
2173 struct drm_mode *configured = NULL;
2174 struct drm_mode *best = NULL;
2175 struct drm_mode *drm_mode;
2176
2177 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
2178 if (kind == OUTPUT_CONFIG_MODE &&
2179 width == drm_mode->base.width &&
2180 height == drm_mode->base.height)
2181 configured = drm_mode;
2182
2183 if (memcmp(&current_mode, &drm_mode->mode_info,
2184 sizeof *current_mode) == 0)
2185 current = drm_mode;
2186
2187 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
2188 preferred = drm_mode;
2189
2190 best = drm_mode;
2191 }
2192
2193 if (kind == OUTPUT_CONFIG_MODELINE) {
2194 configured = drm_output_add_mode(output, modeline);
2195 if (!configured)
2196 return NULL;
2197 }
2198
2199 if (current == NULL && current_mode->clock != 0) {
2200 current = drm_output_add_mode(output, current_mode);
2201 if (!current)
2202 return NULL;
2203 }
2204
2205 if (kind == OUTPUT_CONFIG_CURRENT)
2206 configured = current;
2207
2208 if (option_current_mode && current)
2209 return current;
2210
2211 if (configured)
2212 return configured;
2213
2214 if (preferred)
2215 return preferred;
2216
2217 if (current)
2218 return current;
2219
2220 if (best)
2221 return best;
2222
2223 weston_log("no available modes for %s\n", output->base.name);
2224 return NULL;
2225}
2226
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002227static int
2228connector_get_current_mode(drmModeConnector *connector, int drm_fd,
2229 drmModeModeInfo *mode)
2230{
2231 drmModeEncoder *encoder;
2232 drmModeCrtc *crtc;
2233
2234 /* Get the current mode on the crtc that's currently driving
2235 * this connector. */
2236 encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
2237 memset(mode, 0, sizeof *mode);
2238 if (encoder != NULL) {
2239 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
2240 drmModeFreeEncoder(encoder);
2241 if (crtc == NULL)
2242 return -1;
2243 if (crtc->mode_valid)
2244 *mode = crtc->mode;
2245 drmModeFreeCrtc(crtc);
2246 }
2247
2248 return 0;
2249}
2250
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002251/**
2252 * Create and configure a Weston output structure
2253 *
2254 * Given a DRM connector, create a matching drm_output structure and add it
2255 * to Weston's output list.
2256 *
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002257 * @param b Weston backend structure structure
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002258 * @param resources DRM resources for this device
2259 * @param connector DRM connector to use for this new output
2260 * @param x Horizontal offset to use into global co-ordinate space
2261 * @param y Vertical offset to use into global co-ordinate space
2262 * @param drm_device udev device pointer
2263 * @returns 0 on success, or -1 on failure
2264 */
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002265static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002266create_output_for_connector(struct drm_backend *b,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002267 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002268 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002269 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002270{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002271 struct drm_output *output;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002272 struct drm_mode *drm_mode, *next, *current;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002273 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002274 struct weston_config_section *section;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002275 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002276 int i, width, height, scale;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002277 char *s;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002278 enum output_config config;
2279 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002280
Giulio Camuffo954f1832014-10-11 18:27:30 +03002281 i = find_crtc_for_connector(b, resources, connector);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002282 if (i < 0) {
2283 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002284 return -1;
2285 }
2286
Peter Huttererf3d62272013-08-08 11:57:05 +10002287 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002288 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002289 return -1;
2290
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002291 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002292 output->base.name = make_connector_name(connector);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002293 output->base.make = "unknown";
2294 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002295 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002296 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002297
Giulio Camuffo954f1832014-10-11 18:27:30 +03002298 section = weston_config_get_section(b->compositor->config, "output", "name",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002299 output->base.name);
2300 weston_config_section_get_string(section, "mode", &s, "preferred");
2301 if (strcmp(s, "off") == 0)
2302 config = OUTPUT_CONFIG_OFF;
2303 else if (strcmp(s, "preferred") == 0)
2304 config = OUTPUT_CONFIG_PREFERRED;
2305 else if (strcmp(s, "current") == 0)
2306 config = OUTPUT_CONFIG_CURRENT;
2307 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2308 config = OUTPUT_CONFIG_MODE;
2309 else if (parse_modeline(s, &modeline) == 0)
2310 config = OUTPUT_CONFIG_MODELINE;
2311 else {
2312 weston_log("Invalid mode \"%s\" for output %s\n",
2313 s, output->base.name);
2314 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002315 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002316 free(s);
2317
2318 weston_config_section_get_int(section, "scale", &scale, 1);
2319 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002320 if (weston_parse_transform(s, &transform) < 0)
2321 weston_log("Invalid transform \"%s\" for output %s\n",
2322 s, output->base.name);
2323
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002324 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002325
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002326 if (get_gbm_format_from_section(section,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002327 b->format,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002328 &output->format) == -1)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002329 output->format = b->format;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002330
Rob Bradford66bd9f52013-06-25 18:56:42 +01002331 weston_config_section_get_string(section, "seat", &s, "");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002332 setup_output_seat_constraint(b, &output->base, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002333 free(s);
2334
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002335 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002336 output->pipe = i;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002337 b->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002338 output->connector_id = connector->connector_id;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002339 b->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002340
Giulio Camuffo954f1832014-10-11 18:27:30 +03002341 output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
2342 output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002343
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002344 if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
2345 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002346
David Herrmann0f0d54e2011-12-08 17:05:45 +01002347 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002348 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002349 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002350 goto err_free;
2351 }
2352
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002353 if (config == OUTPUT_CONFIG_OFF) {
2354 weston_log("Disabling output %s\n", output->base.name);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002355 drmModeSetCrtc(b->drm.fd, output->crtc_id,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002356 0, 0, 0, 0, 0, NULL);
2357 goto err_free;
2358 }
2359
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002360 current = drm_output_choose_initial_mode(output, config,
2361 width, height,
2362 &crtc_mode, &modeline);
2363 if (!current)
Wang Quanxianacb805a2012-07-30 18:09:46 -04002364 goto err_free;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002365 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02002366 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002367
Giulio Camuffo954f1832014-10-11 18:27:30 +03002368 weston_output_init(&output->base, b->compositor, x, y,
John Kåre Alsaker94659272012-11-13 19:10:18 +01002369 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002370 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002371
Giulio Camuffo954f1832014-10-11 18:27:30 +03002372 if (b->use_pixman) {
2373 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002374 weston_log("Failed to init output pixman state\n");
2375 goto err_output;
2376 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03002377 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002378 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002379 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002380 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002381
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002382 output->backlight = backlight_init(drm_device,
2383 connector->connector_type);
2384 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002385 weston_log("Initialized backlight, device %s\n",
2386 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002387 output->base.set_backlight = drm_set_backlight;
2388 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002389 } else {
2390 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002391 }
2392
Giulio Camuffo954f1832014-10-11 18:27:30 +03002393 weston_compositor_add_output(b->compositor, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002394
Giulio Camuffo954f1832014-10-11 18:27:30 +03002395 find_and_parse_output_edid(b, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002396 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2397 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002398
Jonas Ådahle5a12252013-04-05 23:07:11 +02002399 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002400 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002401 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002402 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002403 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002404 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002405
Richard Hughese7299962013-05-01 21:52:12 +01002406 output->base.gamma_size = output->original_crtc->gamma_size;
2407 output->base.set_gamma = drm_output_set_gamma;
2408
Giulio Camuffo954f1832014-10-11 18:27:30 +03002409 weston_plane_init(&output->cursor_plane, b->compositor, 0, 0);
2410 weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002411
Giulio Camuffo954f1832014-10-11 18:27:30 +03002412 weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
2413 weston_compositor_stack_plane(b->compositor, &output->fb_plane,
2414 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002415
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002416 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002417 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002418 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002419 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002420 m->width, m->height, m->refresh / 1000.0,
2421 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2422 ", preferred" : "",
2423 m->flags & WL_OUTPUT_MODE_CURRENT ?
2424 ", current" : "",
2425 connector->count_modes == 0 ?
2426 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002427
Mario Kleiner80817042015-06-21 21:25:11 +02002428 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2429 output->base.native_mode = output->base.current_mode;
2430 output->base.native_scale = output->base.current_scale;
2431
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002432 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002433
John Kåre Alsaker94659272012-11-13 19:10:18 +01002434err_output:
2435 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002436err_free:
2437 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2438 base.link) {
2439 wl_list_remove(&drm_mode->base.link);
2440 free(drm_mode);
2441 }
2442
2443 drmModeFreeCrtc(output->original_crtc);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002444 b->crtc_allocator &= ~(1 << output->crtc_id);
2445 b->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002446 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002447
David Herrmann0f0d54e2011-12-08 17:05:45 +01002448 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002449}
2450
Jesse Barnes58ef3792012-02-23 09:45:49 -05002451static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002452create_sprites(struct drm_backend *b)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002453{
2454 struct drm_sprite *sprite;
2455 drmModePlaneRes *plane_res;
2456 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002457 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002458
Giulio Camuffo954f1832014-10-11 18:27:30 +03002459 plane_res = drmModeGetPlaneResources(b->drm.fd);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002460 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002461 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002462 strerror(errno));
2463 return;
2464 }
2465
2466 for (i = 0; i < plane_res->count_planes; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002467 plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002468 if (!plane)
2469 continue;
2470
Peter Huttererf3d62272013-08-08 11:57:05 +10002471 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002472 plane->count_formats));
2473 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002474 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002475 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002476 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002477 continue;
2478 }
2479
Jesse Barnes58ef3792012-02-23 09:45:49 -05002480 sprite->possible_crtcs = plane->possible_crtcs;
2481 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002482 sprite->current = NULL;
2483 sprite->next = NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002484 sprite->backend = b;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002485 sprite->count_formats = plane->count_formats;
2486 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002487 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002488 drmModeFreePlane(plane);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002489 weston_plane_init(&sprite->plane, b->compositor, 0, 0);
2490 weston_compositor_stack_plane(b->compositor, &sprite->plane,
2491 &b->compositor->primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002492
Giulio Camuffo954f1832014-10-11 18:27:30 +03002493 wl_list_insert(&b->sprite_list, &sprite->link);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002494 }
2495
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002496 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002497}
2498
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002499static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002500destroy_sprites(struct drm_backend *backend)
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002501{
2502 struct drm_sprite *sprite, *next;
2503 struct drm_output *output;
2504
Giulio Camuffo954f1832014-10-11 18:27:30 +03002505 output = container_of(backend->compositor->output_list.next,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002506 struct drm_output, base.link);
2507
Giulio Camuffo954f1832014-10-11 18:27:30 +03002508 wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
2509 drmModeSetPlane(backend->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002510 sprite->plane_id,
2511 output->crtc_id, 0, 0,
2512 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002513 drm_output_release_fb(output, sprite->current);
2514 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002515 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002516 free(sprite);
2517 }
2518}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002519
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002520static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002521create_outputs(struct drm_backend *b, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002522 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002523{
2524 drmModeConnector *connector;
2525 drmModeRes *resources;
2526 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002527 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002528
Giulio Camuffo954f1832014-10-11 18:27:30 +03002529 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002530 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002531 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002532 return -1;
2533 }
2534
Giulio Camuffo954f1832014-10-11 18:27:30 +03002535 b->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
2536 if (!b->crtcs) {
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002537 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002538 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002539 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002540
Giulio Camuffo954f1832014-10-11 18:27:30 +03002541 b->min_width = resources->min_width;
2542 b->max_width = resources->max_width;
2543 b->min_height = resources->min_height;
2544 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002545
Giulio Camuffo954f1832014-10-11 18:27:30 +03002546 b->num_crtcs = resources->count_crtcs;
2547 memcpy(b->crtcs, resources->crtcs, sizeof(uint32_t) * b->num_crtcs);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002548
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002549 for (i = 0; i < resources->count_connectors; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002550 connector = drmModeGetConnector(b->drm.fd,
Benjamin Franzke117483d2011-08-30 11:38:26 +02002551 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002552 if (connector == NULL)
2553 continue;
2554
2555 if (connector->connection == DRM_MODE_CONNECTED &&
2556 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002557 connector->connector_id == option_connector)) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002558 if (create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002559 connector, x, y,
2560 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002561 drmModeFreeConnector(connector);
2562 continue;
2563 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002564
Giulio Camuffo954f1832014-10-11 18:27:30 +03002565 x += container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002566 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002567 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002568 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002569
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002570 drmModeFreeConnector(connector);
2571 }
2572
Giulio Camuffo954f1832014-10-11 18:27:30 +03002573 if (wl_list_empty(&b->compositor->output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002574 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002575 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002576 return -1;
2577 }
2578
2579 drmModeFreeResources(resources);
2580
2581 return 0;
2582}
2583
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002584static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002585update_outputs(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002586{
2587 drmModeConnector *connector;
2588 drmModeRes *resources;
2589 struct drm_output *output, *next;
2590 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002591 uint32_t connected = 0, disconnects = 0;
2592 int i;
2593
Giulio Camuffo954f1832014-10-11 18:27:30 +03002594 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002595 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002596 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002597 return;
2598 }
2599
2600 /* collect new connects */
2601 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002602 int connector_id = resources->connectors[i];
2603
Giulio Camuffo954f1832014-10-11 18:27:30 +03002604 connector = drmModeGetConnector(b->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002605 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002606 continue;
2607
David Herrmann7551cff2011-12-08 17:05:43 +01002608 if (connector->connection != DRM_MODE_CONNECTED) {
2609 drmModeFreeConnector(connector);
2610 continue;
2611 }
2612
Benjamin Franzke117483d2011-08-30 11:38:26 +02002613 connected |= (1 << connector_id);
2614
Giulio Camuffo954f1832014-10-11 18:27:30 +03002615 if (!(b->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002616 struct weston_output *last =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002617 container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002618 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002619
2620 /* XXX: not yet needed, we die with 0 outputs */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002621 if (!wl_list_empty(&b->compositor->output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002622 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002623 else
2624 x = 0;
2625 y = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002626 create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002627 connector, x, y,
2628 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002629 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002630
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002631 }
2632 drmModeFreeConnector(connector);
2633 }
2634 drmModeFreeResources(resources);
2635
Giulio Camuffo954f1832014-10-11 18:27:30 +03002636 disconnects = b->connector_allocator & ~connected;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002637 if (disconnects) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002638 wl_list_for_each_safe(output, next, &b->compositor->output_list,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002639 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002640 if (disconnects & (1 << output->connector_id)) {
2641 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002642 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002643 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002644 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002645 }
2646 }
2647 }
2648
Daniel Stonef556ebe2015-05-21 08:28:58 +01002649 /* FIXME: handle zero outputs, without terminating */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002650 if (b->connector_allocator == 0)
Giulio Camuffo459137b2014-10-11 23:56:24 +03002651 weston_compositor_exit(b->compositor);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002652}
2653
2654static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002655udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002656{
David Herrmannd7488c22012-03-11 20:05:21 +01002657 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002658 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002659
2660 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002661 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002662 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002663
David Herrmann6ac52db2012-03-11 20:05:22 +01002664 val = udev_device_get_property_value(device, "HOTPLUG");
2665 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002666 return 0;
2667
David Herrmann6ac52db2012-03-11 20:05:22 +01002668 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002669}
2670
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002671static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002672udev_drm_event(int fd, uint32_t mask, void *data)
2673{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002674 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002675 struct udev_device *event;
2676
Giulio Camuffo954f1832014-10-11 18:27:30 +03002677 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002678
Giulio Camuffo954f1832014-10-11 18:27:30 +03002679 if (udev_event_is_hotplug(b, event))
2680 update_outputs(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002681
2682 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002683
2684 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002685}
2686
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002687static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002688drm_restore(struct weston_compositor *ec)
2689{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002690 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002691}
2692
2693static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002694drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002695{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002696 struct drm_backend *b = (struct drm_backend *) ec->backend;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002697
Giulio Camuffo954f1832014-10-11 18:27:30 +03002698 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002699
Giulio Camuffo954f1832014-10-11 18:27:30 +03002700 wl_event_source_remove(b->udev_drm_source);
2701 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002702
Giulio Camuffo954f1832014-10-11 18:27:30 +03002703 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002704
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002705 weston_compositor_shutdown(ec);
2706
Giulio Camuffo954f1832014-10-11 18:27:30 +03002707 if (b->gbm)
2708 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002709
Giulio Camuffo954f1832014-10-11 18:27:30 +03002710 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002711
Giulio Camuffo954f1832014-10-11 18:27:30 +03002712 close(b->drm.fd);
Rob Bradford45c15b82013-07-26 16:29:35 +01002713
Giulio Camuffo954f1832014-10-11 18:27:30 +03002714 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002715}
2716
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002717static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002718drm_backend_set_modes(struct drm_backend *backend)
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002719{
2720 struct drm_output *output;
2721 struct drm_mode *drm_mode;
2722 int ret;
2723
Giulio Camuffo954f1832014-10-11 18:27:30 +03002724 wl_list_for_each(output, &backend->compositor->output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002725 if (!output->current) {
2726 /* If something that would cause the output to
2727 * switch mode happened while in another vt, we
2728 * might not have a current drm_fb. In that case,
2729 * schedule a repaint and let drm_output_repaint
2730 * handle setting the mode. */
2731 weston_output_schedule_repaint(&output->base);
2732 continue;
2733 }
2734
Hardeningff39efa2013-09-18 23:56:35 +02002735 drm_mode = (struct drm_mode *) output->base.current_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002736 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002737 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002738 &output->connector_id, 1,
2739 &drm_mode->mode_info);
2740 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002741 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002742 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002743 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002744 output->base.x, output->base.y);
2745 }
2746 }
2747}
2748
2749static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002750session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002751{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002752 struct weston_compositor *compositor = data;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002753 struct drm_backend *b = (struct drm_backend *)compositor->backend;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002754 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002755 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002756
Giulio Camuffo954f1832014-10-11 18:27:30 +03002757 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002758 weston_log("activating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002759 compositor->state = b->prev_state;
2760 drm_backend_set_modes(b);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002761 weston_compositor_damage_all(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002762 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002763 } else {
2764 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002765 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002766
Giulio Camuffo954f1832014-10-11 18:27:30 +03002767 b->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002768 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002769
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002770 /* If we have a repaint scheduled (either from a
2771 * pending pageflip or the idle handler), make sure we
2772 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002773 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002774 * further attemps at repainting. When we switch
2775 * back, we schedule a repaint, which will process
2776 * pending frame callbacks. */
2777
Giulio Camuffo954f1832014-10-11 18:27:30 +03002778 wl_list_for_each(output, &compositor->output_list, base.link) {
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002779 output->base.repaint_needed = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002780 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002781 }
2782
Giulio Camuffo954f1832014-10-11 18:27:30 +03002783 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002784 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002785
Giulio Camuffo954f1832014-10-11 18:27:30 +03002786 wl_list_for_each(sprite, &b->sprite_list, link)
2787 drmModeSetPlane(b->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002788 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002789 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002790 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002791 };
2792}
2793
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002794static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002795switch_vt_binding(struct weston_keyboard *keyboard, uint32_t time,
2796 uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002797{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002798 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002799
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002800 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002801}
2802
David Herrmann0af066f2012-10-29 19:21:16 +01002803/*
2804 * Find primary GPU
2805 * Some systems may have multiple DRM devices attached to a single seat. This
2806 * function loops over all devices and tries to find a PCI device with the
2807 * boot_vga sysfs attribute set to 1.
2808 * If no such device is found, the first DRM device reported by udev is used.
2809 */
2810static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002811find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002812{
2813 struct udev_enumerate *e;
2814 struct udev_list_entry *entry;
2815 const char *path, *device_seat, *id;
2816 struct udev_device *device, *drm_device, *pci;
2817
Giulio Camuffo954f1832014-10-11 18:27:30 +03002818 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002819 udev_enumerate_add_match_subsystem(e, "drm");
2820 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2821
2822 udev_enumerate_scan_devices(e);
2823 drm_device = NULL;
2824 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2825 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002826 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002827 if (!device)
2828 continue;
2829 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2830 if (!device_seat)
2831 device_seat = default_seat;
2832 if (strcmp(device_seat, seat)) {
2833 udev_device_unref(device);
2834 continue;
2835 }
2836
2837 pci = udev_device_get_parent_with_subsystem_devtype(device,
2838 "pci", NULL);
2839 if (pci) {
2840 id = udev_device_get_sysattr_value(pci, "boot_vga");
2841 if (id && !strcmp(id, "1")) {
2842 if (drm_device)
2843 udev_device_unref(drm_device);
2844 drm_device = device;
2845 break;
2846 }
2847 }
2848
2849 if (!drm_device)
2850 drm_device = device;
2851 else
2852 udev_device_unref(device);
2853 }
2854
2855 udev_enumerate_unref(e);
2856 return drm_device;
2857}
2858
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002859static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002860planes_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
2861 void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002862{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002863 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002864
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002865 switch (key) {
2866 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002867 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002868 break;
2869 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002870 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002871 break;
2872 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002873 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002874 break;
2875 default:
2876 break;
2877 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002878}
2879
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002880#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002881static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002882recorder_destroy(struct drm_output *output)
2883{
2884 vaapi_recorder_destroy(output->recorder);
2885 output->recorder = NULL;
2886
2887 output->base.disable_planes--;
2888
2889 wl_list_remove(&output->recorder_frame_listener.link);
2890 weston_log("[libva recorder] done\n");
2891}
2892
2893static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002894recorder_frame_notify(struct wl_listener *listener, void *data)
2895{
2896 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002897 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002898 int fd, ret;
2899
2900 output = container_of(listener, struct drm_output,
2901 recorder_frame_listener);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002902 b = (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002903
2904 if (!output->recorder)
2905 return;
2906
Giulio Camuffo954f1832014-10-11 18:27:30 +03002907 ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002908 DRM_CLOEXEC, &fd);
2909 if (ret) {
2910 weston_log("[libva recorder] "
2911 "failed to create prime fd for front buffer\n");
2912 return;
2913 }
2914
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002915 ret = vaapi_recorder_frame(output->recorder, fd,
2916 output->current->stride);
2917 if (ret < 0) {
2918 weston_log("[libva recorder] aborted: %m\n");
2919 recorder_destroy(output);
2920 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002921}
2922
2923static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002924create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002925 const char *filename)
2926{
2927 int fd;
2928 drm_magic_t magic;
2929
Giulio Camuffo954f1832014-10-11 18:27:30 +03002930 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002931 if (fd < 0)
2932 return NULL;
2933
2934 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002935 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002936
2937 return vaapi_recorder_create(fd, width, height, filename);
2938}
2939
2940static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05002941recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002942 void *data)
2943{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002944 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002945 struct drm_output *output;
2946 int width, height;
2947
Giulio Camuffo954f1832014-10-11 18:27:30 +03002948 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002949 struct drm_output, base.link);
2950
2951 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002952 if (output->format != GBM_FORMAT_XRGB8888) {
2953 weston_log("failed to start vaapi recorder: "
2954 "output format not supported\n");
2955 return;
2956 }
2957
Hardeningff39efa2013-09-18 23:56:35 +02002958 width = output->base.current_mode->width;
2959 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002960
2961 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002962 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002963 if (!output->recorder) {
2964 weston_log("failed to create vaapi recorder\n");
2965 return;
2966 }
2967
2968 output->base.disable_planes++;
2969
2970 output->recorder_frame_listener.notify = recorder_frame_notify;
2971 wl_signal_add(&output->base.frame_signal,
2972 &output->recorder_frame_listener);
2973
2974 weston_output_schedule_repaint(&output->base);
2975
2976 weston_log("[libva recorder] initialized\n");
2977 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002978 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002979 }
2980}
2981#else
2982static void
Bryce Harrington4a8a3a12015-07-16 19:12:26 -07002983recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002984 void *data)
2985{
2986 weston_log("Compiled without libva support\n");
2987}
2988#endif
2989
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002990static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002991switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002992{
2993 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002994 bool dmabuf_support_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002995
Giulio Camuffo954f1832014-10-11 18:27:30 +03002996 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002997 return;
2998
Pekka Paalanene4d231e2014-06-12 15:12:48 +03002999 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
3000
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003001 weston_log("Switching to GL renderer\n");
3002
Giulio Camuffo954f1832014-10-11 18:27:30 +03003003 b->gbm = create_gbm_device(b->drm.fd);
3004 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003005 weston_log("Failed to create gbm device. "
3006 "Aborting renderer switch\n");
3007 return;
3008 }
3009
Giulio Camuffo954f1832014-10-11 18:27:30 +03003010 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003011 pixman_renderer_output_destroy(&output->base);
3012
Giulio Camuffo954f1832014-10-11 18:27:30 +03003013 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003014
Giulio Camuffo954f1832014-10-11 18:27:30 +03003015 if (drm_backend_create_gl_renderer(b) < 0) {
3016 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003017 weston_log("Failed to create GL renderer. Quitting.\n");
3018 /* FIXME: we need a function to shutdown cleanly */
3019 assert(0);
3020 }
3021
Giulio Camuffo954f1832014-10-11 18:27:30 +03003022 wl_list_for_each(output, &b->compositor->output_list, base.link)
3023 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003024
Giulio Camuffo954f1832014-10-11 18:27:30 +03003025 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003026
3027 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
3028 if (linux_dmabuf_setup(b->compositor) < 0)
3029 weston_log("Error: initializing dmabuf "
3030 "support failed.\n");
3031 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003032}
3033
3034static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05003035renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
3036 uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003037{
Derek Foreman8ae2db52015-07-15 13:00:36 -05003038 struct drm_backend *b =
3039 (struct drm_backend *) keyboard->seat->compositor;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003040
Giulio Camuffo954f1832014-10-11 18:27:30 +03003041 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003042}
3043
Giulio Camuffo954f1832014-10-11 18:27:30 +03003044static struct drm_backend *
3045drm_backend_create(struct weston_compositor *compositor,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003046 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003047 int *argc, char *argv[],
3048 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003049{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003050 struct drm_backend *b;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003051 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01003052 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003053 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01003054 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003055 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003056
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04003057 weston_log("initializing drm backend\n");
3058
Giulio Camuffo954f1832014-10-11 18:27:30 +03003059 b = zalloc(sizeof *b);
3060 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003061 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01003062
Pekka Paalanen68583832015-05-19 09:53:16 +03003063 /*
3064 * KMS support for hardware planes cannot properly synchronize
3065 * without nuclear page flip. Without nuclear/atomic, hw plane
3066 * and cursor plane updates would either tear or cause extra
3067 * waits for vblanks which means dropping the compositor framerate
3068 * to a fraction.
3069 *
3070 * These can be enabled again when nuclear/atomic support lands.
3071 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003072 b->sprites_are_broken = 1;
3073 b->cursors_are_broken = 1;
3074 b->compositor = compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003075
3076 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003077 if (get_gbm_format_from_section(section,
3078 GBM_FORMAT_XRGB8888,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003079 &b->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003080 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003081
Giulio Camuffo954f1832014-10-11 18:27:30 +03003082 b->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003083
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003084 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003085 compositor->launcher = weston_launcher_connect(compositor, param->tty,
3086 param->seat_id, true);
3087 if (compositor->launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003088 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04003089 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003090 goto err_compositor;
3091 }
3092
Giulio Camuffo954f1832014-10-11 18:27:30 +03003093 b->udev = udev_new();
3094 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003095 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003096 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003097 }
3098
Giulio Camuffo954f1832014-10-11 18:27:30 +03003099 b->session_listener.notify = session_notify;
3100 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003101
Giulio Camuffo954f1832014-10-11 18:27:30 +03003102 drm_device = find_primary_gpu(b, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003103 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003104 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003105 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003106 }
David Herrmann0af066f2012-10-29 19:21:16 +01003107 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003108
Giulio Camuffo954f1832014-10-11 18:27:30 +03003109 if (init_drm(b, drm_device) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003110 weston_log("failed to initialize kms\n");
3111 goto err_udev_dev;
3112 }
3113
Giulio Camuffo954f1832014-10-11 18:27:30 +03003114 if (b->use_pixman) {
3115 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003116 weston_log("failed to initialize pixman renderer\n");
3117 goto err_udev_dev;
3118 }
3119 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003120 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003121 weston_log("failed to initialize egl\n");
3122 goto err_udev_dev;
3123 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003124 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003125
Giulio Camuffo954f1832014-10-11 18:27:30 +03003126 b->base.destroy = drm_destroy;
3127 b->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003128
Giulio Camuffo954f1832014-10-11 18:27:30 +03003129 b->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02003130
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003131 for (key = KEY_F1; key < KEY_F9; key++)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003132 weston_compositor_add_key_binding(compositor, key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003133 MODIFIER_CTRL | MODIFIER_ALT,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003134 switch_vt_binding, compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003135
Giulio Camuffo954f1832014-10-11 18:27:30 +03003136 wl_list_init(&b->sprite_list);
3137 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003138
Giulio Camuffo954f1832014-10-11 18:27:30 +03003139 if (udev_input_init(&b->input,
3140 compositor, b->udev, param->seat_id) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003141 weston_log("failed to create input devices\n");
3142 goto err_sprite;
3143 }
3144
Giulio Camuffo954f1832014-10-11 18:27:30 +03003145 if (create_outputs(b, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003146 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003147 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003148 }
3149
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003150 /* A this point we have some idea of whether or not we have a working
3151 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003152 if (!b->cursors_are_broken)
3153 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003154
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02003155 path = NULL;
3156
Giulio Camuffo954f1832014-10-11 18:27:30 +03003157 loop = wl_display_get_event_loop(compositor->wl_display);
3158 b->drm_source =
3159 wl_event_loop_add_fd(loop, b->drm.fd,
3160 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003161
Giulio Camuffo954f1832014-10-11 18:27:30 +03003162 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3163 if (b->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003164 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003165 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003166 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003167 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003168 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003169 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003170 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003171 udev_monitor_get_fd(b->udev_monitor),
3172 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003173
Giulio Camuffo954f1832014-10-11 18:27:30 +03003174 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003175 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003176 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003177 }
3178
Daniel Stonea96b93c2012-06-22 14:04:37 +01003179 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003180
Giulio Camuffo954f1832014-10-11 18:27:30 +03003181 weston_compositor_add_debug_binding(compositor, KEY_O,
3182 planes_binding, b);
3183 weston_compositor_add_debug_binding(compositor, KEY_C,
3184 planes_binding, b);
3185 weston_compositor_add_debug_binding(compositor, KEY_V,
3186 planes_binding, b);
3187 weston_compositor_add_debug_binding(compositor, KEY_Q,
3188 recorder_binding, b);
3189 weston_compositor_add_debug_binding(compositor, KEY_W,
3190 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003191
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003192 if (compositor->renderer->import_dmabuf) {
3193 if (linux_dmabuf_setup(compositor) < 0)
3194 weston_log("Error: initializing dmabuf "
3195 "support failed.\n");
3196 }
3197
Giulio Camuffo954f1832014-10-11 18:27:30 +03003198 compositor->backend = &b->base;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003199
Giulio Camuffo954f1832014-10-11 18:27:30 +03003200 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003201
3202err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003203 wl_event_source_remove(b->udev_drm_source);
3204 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003205err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003206 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003207err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003208 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003209err_sprite:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003210 gbm_device_destroy(b->gbm);
3211 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003212err_udev_dev:
3213 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003214err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003215 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003216err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003217 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003218err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003219 weston_compositor_shutdown(compositor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003220err_base:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003221 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003222 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003223}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003224
Giulio Camuffo954f1832014-10-11 18:27:30 +03003225WL_EXPORT int
3226backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003227 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003228{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003229 struct drm_backend *b;
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003230 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003231
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003232 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003233 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3234 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3235 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003236 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003237 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003238 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003239
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003240 param.seat_id = default_seat;
3241
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003242 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003243
Giulio Camuffo954f1832014-10-11 18:27:30 +03003244 b = drm_backend_create(compositor, &param, argc, argv, config);
3245 if (b == NULL)
3246 return -1;
3247 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003248}