blob: 3ca437bac04c261aa5ffc40865c6fc0471d1774a [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>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030030#include <stdint.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040031#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010032#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033#include <string.h>
34#include <fcntl.h>
35#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040036#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070037#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030038#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020039#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030040#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030041#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042
Benjamin Franzkec649a922011-03-02 11:56:04 +010043#include <xf86drm.h>
44#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050045#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010046
Benjamin Franzke060cf802011-04-30 09:32:11 +020047#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040048#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020049
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070050#include "compositor.h"
51#include "compositor-drm.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070052#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020053#include "shared/timespec-util.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010054#include "gl-renderer.h"
Vincent Abriouc9506672016-10-05 16:14:07 +020055#include "weston-egl-ext.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020056#include "pixman-renderer.h"
Daniel Stone0b70fa42017-04-04 17:54:23 +010057#include "pixel-formats.h"
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070058#include "libbacklight.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100059#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010060#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030061#include "vaapi-recorder.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020062#include "presentation-time-server-protocol.h"
Pekka Paalanene4d231e2014-06-12 15:12:48 +030063#include "linux-dmabuf.h"
Micah Fedkec8890122017-02-01 15:28:23 -050064#include "linux-dmabuf-unstable-v1-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040065
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030066#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
67#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
68#endif
69
Pekka Paalanenc5de57f2015-05-20 23:01:44 +010070#ifndef DRM_CLIENT_CAP_UNIVERSAL_PLANES
71#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
72#endif
73
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030074#ifndef DRM_CAP_CURSOR_WIDTH
75#define DRM_CAP_CURSOR_WIDTH 0x8
76#endif
77
78#ifndef DRM_CAP_CURSOR_HEIGHT
79#define DRM_CAP_CURSOR_HEIGHT 0x9
80#endif
81
82#ifndef GBM_BO_USE_CURSOR
83#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
84#endif
85
Daniel Stone02cf4662017-03-03 16:19:39 +000086/**
Pekka Paalanenc5de57f2015-05-20 23:01:44 +010087 * List of properties attached to DRM planes
88 */
89enum wdrm_plane_property {
90 WDRM_PLANE_TYPE = 0,
91 WDRM_PLANE__COUNT
92};
93
94/**
95 * Possible values for the WDRM_PLANE_TYPE property.
96 */
97enum wdrm_plane_type {
98 WDRM_PLANE_TYPE_PRIMARY = 0,
99 WDRM_PLANE_TYPE_CURSOR,
100 WDRM_PLANE_TYPE_OVERLAY,
101 WDRM_PLANE_TYPE__COUNT
102};
103
104/**
Daniel Stone02cf4662017-03-03 16:19:39 +0000105 * List of properties attached to a DRM connector
106 */
107enum wdrm_connector_property {
108 WDRM_CONNECTOR_EDID = 0,
109 WDRM_CONNECTOR_DPMS,
110 WDRM_CONNECTOR__COUNT
111};
112
113/**
114 * Represents the values of an enum-type KMS property
115 */
116struct drm_property_enum_info {
117 const char *name; /**< name as string (static, not freed) */
118 bool valid; /**< true if value is supported; ignore if false */
119 uint64_t value; /**< raw value */
120};
121
122/**
123 * Holds information on a DRM property, including its ID and the enum
124 * values it holds.
125 *
126 * DRM properties are allocated dynamically, and maintained as DRM objects
127 * within the normal object ID space; they thus do not have a stable ID
128 * to refer to. This includes enum values, which must be referred to by
129 * integer values, but these are not stable.
130 *
131 * drm_property_info allows a cache to be maintained where Weston can use
132 * enum values internally to refer to properties, with the mapping to DRM
133 * ID values being maintained internally.
134 */
135struct drm_property_info {
136 const char *name; /**< name as string (static, not freed) */
137 uint32_t prop_id; /**< KMS property object ID */
138 unsigned int num_enum_values; /**< number of enum values */
139 struct drm_property_enum_info *enum_values; /**< array of enum values */
140};
141
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000142/**
143 * Mode for drm_output_state_duplicate.
144 */
145enum drm_output_state_duplicate_mode {
146 DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
147 DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
148};
149
150/**
151 * Mode for drm_pending_state_apply and co.
152 */
153enum drm_state_apply_mode {
154 DRM_STATE_APPLY_SYNC, /**< state fully processed */
155 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
156};
157
Giulio Camuffo954f1832014-10-11 18:27:30 +0300158struct drm_backend {
159 struct weston_backend base;
160 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400161
162 struct udev *udev;
163 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400164
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100165 struct udev_monitor *udev_monitor;
166 struct wl_event_source *udev_drm_source;
167
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100168 struct {
David Herrmannd7488c22012-03-11 20:05:21 +0100169 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100170 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300171 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100172 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200173 struct gbm_device *gbm;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700174 struct wl_listener session_listener;
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +0100175 uint32_t gbm_format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200176
Rob Clark4339add2012-08-09 14:18:28 -0500177 /* we need these parameters in order to not fail drmModeAddFB2()
178 * due to out of bounds dimensions, and then mistakenly set
179 * sprites_are_broken:
180 */
Daniel Stonef214fdc2016-11-14 17:43:57 +0000181 int min_width, max_width;
182 int min_height, max_height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200183 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500184
Daniel Stone085d2b92015-05-21 00:00:57 +0100185 struct wl_list plane_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500186 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200187 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500188
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000189 void *repaint_data;
190
Rob Clarkab5b1e32012-08-09 13:24:45 -0500191 int cursors_are_broken;
192
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100193 bool universal_planes;
194
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200195 int use_pixman;
196
Rob Bradfordd355b802013-05-31 18:09:55 +0100197 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300198
Daniel Stone70d337d2015-06-16 18:42:23 +0100199 int32_t cursor_width;
200 int32_t cursor_height;
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +0000201
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000202 uint32_t pageflip_timeout;
Daniel Stoneb57c6a02017-10-05 16:27:21 +0100203
204 bool shutting_down;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400205};
206
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400207struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500208 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400209 drmModeModeInfo mode_info;
210};
211
Daniel Stonefc175a72017-04-04 17:54:22 +0100212enum drm_fb_type {
213 BUFFER_INVALID = 0, /**< never used */
214 BUFFER_CLIENT, /**< directly sourced from client */
215 BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
216 BUFFER_GBM_SURFACE, /**< internal EGL rendering */
Daniel Stonee4256832017-04-04 17:54:27 +0100217 BUFFER_CURSOR, /**< internal cursor buffer */
Daniel Stonefc175a72017-04-04 17:54:22 +0100218};
219
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300220struct drm_fb {
Daniel Stonefc175a72017-04-04 17:54:22 +0100221 enum drm_fb_type type;
222
Daniel Stone6e7a9612017-04-04 17:54:26 +0100223 int refcnt;
224
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200225 uint32_t fb_id, stride, handle, size;
Daniel Stone0b70fa42017-04-04 17:54:23 +0100226 const struct pixel_format_info *format;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000227 int width, height;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200228 int fd;
Pekka Paalanende685b82012-12-04 15:58:12 +0200229 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200230
231 /* Used by gbm fbs */
232 struct gbm_bo *bo;
Daniel Stone05a5ac22017-04-04 17:54:25 +0100233 struct gbm_surface *gbm_surface;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200234
235 /* Used by dumb fbs */
236 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300237};
238
Richard Hughes2b2092a2013-04-24 14:58:02 +0100239struct drm_edid {
240 char eisa_id[13];
241 char monitor_name[13];
242 char pnp_id[5];
243 char serial_number[13];
244};
245
Daniel Stone08d4edf2017-04-04 17:54:34 +0100246/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000247 * Pending state holds one or more drm_output_state structures, collected from
248 * performing repaint. This pending state is transient, and only lives between
249 * beginning a repaint group and flushing the results: after flush, each
250 * output state will complete and be retired separately.
251 */
252struct drm_pending_state {
253 struct drm_backend *backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000254 struct wl_list output_list;
255};
256
257/*
258 * Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
259 * plus >= 1 each of encoder/connector/plane. Since everything but the planes
260 * is currently statically assigned per-output, we mainly use this to track
261 * plane state.
262 *
263 * pending_state is set when the output state is owned by a pending_state,
264 * i.e. when it is being constructed and has not yet been applied. When the
265 * output state has been applied, the owning pending_state is freed.
266 */
267struct drm_output_state {
268 struct drm_pending_state *pending_state;
269 struct drm_output *output;
270 struct wl_list link;
Daniel Stonebc15f682016-11-14 16:57:01 +0000271 struct wl_list plane_list;
272};
273
274/**
275 * Plane state holds the dynamic state for a plane: where it is positioned,
276 * and which buffer it is currently displaying.
277 *
278 * The plane state is owned by an output state, except when setting an initial
279 * state. See drm_output_state for notes on state object lifetime.
280 */
281struct drm_plane_state {
282 struct drm_plane *plane;
283 struct drm_output *output;
284 struct drm_output_state *output_state;
285
286 struct drm_fb *fb;
287
288 int32_t src_x, src_y;
289 uint32_t src_w, src_h;
290 int32_t dest_x, dest_y;
291 uint32_t dest_w, dest_h;
292
293 bool complete;
294
295 struct wl_list link; /* drm_output_state::plane_list */
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000296};
297
298/**
Daniel Stone08d4edf2017-04-04 17:54:34 +0100299 * A plane represents one buffer, positioned within a CRTC, and stacked
300 * relative to other planes on the same CRTC.
301 *
302 * Each CRTC has a 'primary plane', which use used to display the classic
303 * framebuffer contents, as accessed through the legacy drmModeSetCrtc
304 * call (which combines setting the CRTC's actual physical mode, and the
305 * properties of the primary plane).
306 *
307 * The cursor plane also has its own alternate legacy API.
308 *
309 * Other planes are used opportunistically to display content we do not
310 * wish to blit into the primary plane. These non-primary/cursor planes
311 * are referred to as 'sprites'.
312 */
313struct drm_plane {
Daniel Stone08d4edf2017-04-04 17:54:34 +0100314 struct weston_plane base;
315
Daniel Stone08d4edf2017-04-04 17:54:34 +0100316 struct drm_backend *backend;
317
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100318 enum wdrm_plane_type type;
319
Daniel Stone08d4edf2017-04-04 17:54:34 +0100320 uint32_t possible_crtcs;
321 uint32_t plane_id;
322 uint32_t count_formats;
323
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100324 struct drm_property_info props[WDRM_PLANE__COUNT];
325
Daniel Stonebc15f682016-11-14 16:57:01 +0000326 /* The last state submitted to the kernel for this plane. */
327 struct drm_plane_state *state_cur;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100328
Daniel Stonebc15f682016-11-14 16:57:01 +0000329 struct wl_list link;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100330
331 uint32_t formats[];
332};
333
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400334struct drm_output {
Armin Krezović08368132016-09-30 14:11:05 +0200335 struct weston_output base;
336 drmModeConnector *connector;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400337
Daniel Stone17339232015-11-28 12:09:47 +0000338 uint32_t crtc_id; /* object ID to pass to DRM functions */
339 int pipe; /* index of CRTC in resource array / bitmasks */
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400340 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700341 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100342 struct drm_edid edid;
Daniel Stone02cf4662017-03-03 16:19:39 +0000343
344 /* Holds the properties for the connector */
345 struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200346
Daniel Stone36609c72015-06-18 07:49:02 +0100347 enum dpms_enum dpms;
Daniel Stone5bb8f582017-04-04 17:54:28 +0100348 struct backlight *backlight;
Daniel Stone36609c72015-06-18 07:49:02 +0100349
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300350 bool state_invalid;
351
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300352 int vblank_pending;
353 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800354 int destroy_pending;
Armin Krezović08368132016-09-30 14:11:05 +0200355 int disable_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300356
Daniel Stonee4256832017-04-04 17:54:27 +0100357 struct drm_fb *gbm_cursor_fb[2];
Daniel Stone2ba17f42015-05-19 20:02:41 +0100358 struct drm_plane *cursor_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500359 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400360 int current_cursor;
Daniel Stone5bb8f582017-04-04 17:54:28 +0100361
362 struct gbm_surface *gbm_surface;
363 uint32_t gbm_format;
364
Daniel Stonee2e80132018-01-16 15:37:33 +0000365 /* Plane being displayed directly on the CRTC */
366 struct drm_plane *scanout_plane;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200367
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000368 /* The last state submitted to the kernel for this CRTC. */
369 struct drm_output_state *state_cur;
370 /* The previously-submitted state, where the hardware has not
371 * yet acknowledged completion of state_cur. */
372 struct drm_output_state *state_last;
373
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200374 struct drm_fb *dumb[2];
375 pixman_image_t *image[2];
376 int current_image;
377 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300378
379 struct vaapi_recorder *recorder;
380 struct wl_listener recorder_frame_listener;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000381
382 struct wl_event_source *pageflip_timer;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400383};
384
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300385static struct gl_renderer_interface *gl_renderer;
386
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500387static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400388
Armin Krezović545dba62016-08-05 15:54:18 +0200389static inline struct drm_output *
390to_drm_output(struct weston_output *base)
391{
392 return container_of(base, struct drm_output, base);
393}
394
395static inline struct drm_backend *
396to_drm_backend(struct weston_compositor *base)
397{
398 return container_of(base->backend, struct drm_backend, base);
399}
400
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000401static int
402pageflip_timeout(void *data) {
403 /*
404 * Our timer just went off, that means we're not receiving drm
405 * page flip events anymore for that output. Let's gracefully exit
406 * weston with a return value so devs can debug what's going on.
407 */
408 struct drm_output *output = data;
409 struct weston_compositor *compositor = output->base.compositor;
410
411 weston_log("Pageflip timeout reached on output %s, your "
412 "driver is probably buggy! Exiting.\n",
413 output->base.name);
414 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
415
416 return 0;
417}
418
419/* Creates the pageflip timer. Note that it isn't armed by default */
420static int
421drm_output_pageflip_timer_create(struct drm_output *output)
422{
423 struct wl_event_loop *loop = NULL;
424 struct weston_compositor *ec = output->base.compositor;
425
426 loop = wl_display_get_event_loop(ec->wl_display);
427 assert(loop);
428 output->pageflip_timer = wl_event_loop_add_timer(loop,
429 pageflip_timeout,
430 output);
431
432 if (output->pageflip_timer == NULL) {
433 weston_log("creating drm pageflip timer failed: %m\n");
434 return -1;
435 }
436
437 return 0;
438}
439
Daniel Stone02cf4662017-03-03 16:19:39 +0000440/**
441 * Get the current value of a KMS property
442 *
443 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
444 * for the target property, return the current value of that property,
445 * with an optional default. If the property is a KMS enum type, the return
446 * value will be translated into the appropriate internal enum.
447 *
448 * If the property is not present, the default value will be returned.
449 *
450 * @param info Internal structure for property to look up
451 * @param props Raw KMS properties for the target object
452 * @param def Value to return if property is not found
453 */
454static uint64_t
455drm_property_get_value(struct drm_property_info *info,
456 drmModeObjectPropertiesPtr props,
457 uint64_t def)
458{
459 unsigned int i;
460
461 if (info->prop_id == 0)
462 return def;
463
464 for (i = 0; i < props->count_props; i++) {
465 unsigned int j;
466
467 if (props->props[i] != info->prop_id)
468 continue;
469
470 /* Simple (non-enum) types can return the value directly */
471 if (info->num_enum_values == 0)
472 return props->prop_values[i];
473
474 /* Map from raw value to enum value */
475 for (j = 0; j < info->num_enum_values; j++) {
476 if (!info->enum_values[j].valid)
477 continue;
478 if (info->enum_values[j].value != props->prop_values[i])
479 continue;
480
481 return j;
482 }
483
484 /* We don't have a mapping for this enum; return default. */
485 break;
486 }
487
488 return def;
489}
490
491/**
492 * Cache DRM property values
493 *
494 * Update a per-object array of drm_property_info structures, given the
495 * DRM properties of the object.
496 *
497 * Call this every time an object newly appears (note that only connectors
498 * can be hotplugged), the first time it is seen, or when its status changes
499 * in a way which invalidates the potential property values (currently, the
500 * only case for this is connector hotplug).
501 *
502 * This updates the property IDs and enum values within the drm_property_info
503 * array.
504 *
505 * DRM property enum values are dynamic at runtime; the user must query the
506 * property to find out the desired runtime value for a requested string
507 * name. Using the 'type' field on planes as an example, there is no single
508 * hardcoded constant for primary plane types; instead, the property must be
509 * queried at runtime to find the value associated with the string "Primary".
510 *
511 * This helper queries and caches the enum values, to allow us to use a set
512 * of compile-time-constant enums portably across various implementations.
513 * The values given in enum_names are searched for, and stored in the
514 * same-indexed field of the map array.
515 *
516 * @param b DRM backend object
517 * @param src DRM property info array to source from
518 * @param info DRM property info array to copy into
519 * @param num_infos Number of entries in the source array
520 * @param props DRM object properties for the object
521 */
522static void
523drm_property_info_populate(struct drm_backend *b,
524 const struct drm_property_info *src,
525 struct drm_property_info *info,
526 unsigned int num_infos,
527 drmModeObjectProperties *props)
528{
529 drmModePropertyRes *prop;
530 unsigned i, j;
531
532 for (i = 0; i < num_infos; i++) {
533 unsigned int j;
534
535 info[i].name = src[i].name;
536 info[i].prop_id = 0;
537 info[i].num_enum_values = src[i].num_enum_values;
538
539 if (src[i].num_enum_values == 0)
540 continue;
541
542 info[i].enum_values =
543 malloc(src[i].num_enum_values *
544 sizeof(*info[i].enum_values));
545 assert(info[i].enum_values);
546 for (j = 0; j < info[i].num_enum_values; j++) {
547 info[i].enum_values[j].name = src[i].enum_values[j].name;
548 info[i].enum_values[j].valid = false;
549 }
550 }
551
552 for (i = 0; i < props->count_props; i++) {
553 unsigned int k;
554
555 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
556 if (!prop)
557 continue;
558
559 for (j = 0; j < num_infos; j++) {
560 if (!strcmp(prop->name, info[j].name))
561 break;
562 }
563
564 /* We don't know/care about this property. */
565 if (j == num_infos) {
566#ifdef DEBUG
567 weston_log("DRM debug: unrecognized property %u '%s'\n",
568 prop->prop_id, prop->name);
569#endif
570 drmModeFreeProperty(prop);
571 continue;
572 }
573
574 if (info[j].num_enum_values == 0 &&
575 (prop->flags & DRM_MODE_PROP_ENUM)) {
576 weston_log("DRM: expected property %s to not be an"
577 " enum, but it is; ignoring\n", prop->name);
578 drmModeFreeProperty(prop);
579 continue;
580 }
581
582 info[j].prop_id = props->props[i];
583
584 if (info[j].num_enum_values == 0) {
585 drmModeFreeProperty(prop);
586 continue;
587 }
588
589 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
590 weston_log("DRM: expected property %s to be an enum,"
591 " but it is not; ignoring\n", prop->name);
592 drmModeFreeProperty(prop);
593 info[j].prop_id = 0;
594 continue;
595 }
596
597 for (k = 0; k < info[j].num_enum_values; k++) {
598 int l;
599
600 for (l = 0; l < prop->count_enums; l++) {
601 if (!strcmp(prop->enums[l].name,
602 info[j].enum_values[k].name))
603 break;
604 }
605
606 if (l == prop->count_enums)
607 continue;
608
609 info[j].enum_values[k].valid = true;
610 info[j].enum_values[k].value = prop->enums[l].value;
611 }
612
613 drmModeFreeProperty(prop);
614 }
615
616#ifdef DEBUG
617 for (i = 0; i < num_infos; i++) {
618 if (info[i].prop_id == 0)
619 weston_log("DRM warning: property '%s' missing\n",
620 info[i].name);
621 }
622#endif
623}
624
625/**
626 * Free DRM property information
627 *
628 * Frees all memory associated with a DRM property info array.
629 *
630 * @param info DRM property info array
631 * @param num_props Number of entries in array to free
632 */
633static void
634drm_property_info_free(struct drm_property_info *info, int num_props)
635{
636 int i;
637
638 for (i = 0; i < num_props; i++)
639 free(info[i].enum_values);
640}
641
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400642static void
Daniel Stone2ba17f42015-05-19 20:02:41 +0100643drm_output_set_cursor(struct drm_output_state *output_state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400644
Mario Kleinerf507ec32015-06-21 21:25:14 +0200645static void
646drm_output_update_msc(struct drm_output *output, unsigned int seq);
647
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000648static void
649drm_output_destroy(struct weston_output *output_base);
650
Daniel Stone5ff289a2017-10-07 12:59:02 +0100651/**
652 * Returns true if the plane can be used on the given output for its current
653 * repaint cycle.
654 */
655static bool
656drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100658 assert(plane->state_cur);
659
660 /* The plane still has a request not yet completed by the kernel. */
661 if (!plane->state_cur->complete)
662 return false;
663
664 /* The plane is still active on another output. */
665 if (plane->state_cur->output && plane->state_cur->output != output)
666 return false;
667
668 /* Check whether the plane can be used with this CRTC; possible_crtcs
669 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Daniel Stone08d4edf2017-04-04 17:54:34 +0100670 return !!(plane->possible_crtcs & (1 << output->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500671}
672
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000673static struct drm_output *
674drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
675{
676 struct drm_output *output;
677
678 wl_list_for_each(output, &b->compositor->output_list, base.link) {
679 if (output->crtc_id == crtc_id)
680 return output;
681 }
682
683 wl_list_for_each(output, &b->compositor->pending_output_list,
684 base.link) {
685 if (output->crtc_id == crtc_id)
686 return output;
687 }
688
689 return NULL;
690}
691
Daniel Stonec0ec7592017-02-09 13:58:35 +0000692static struct drm_output *
693drm_output_find_by_connector(struct drm_backend *b, uint32_t connector_id)
694{
695 struct drm_output *output;
696
697 wl_list_for_each(output, &b->compositor->output_list, base.link) {
698 if (output->connector_id == connector_id)
699 return output;
700 }
701
702 wl_list_for_each(output, &b->compositor->pending_output_list,
703 base.link) {
704 if (output->connector_id == connector_id)
705 return output;
706 }
707
708 return NULL;
709}
710
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300711static void
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100712drm_fb_destroy(struct drm_fb *fb)
713{
714 if (fb->fb_id != 0)
715 drmModeRmFB(fb->fd, fb->fb_id);
716 weston_buffer_reference(&fb->buffer_ref, NULL);
717 free(fb);
718}
719
720static void
721drm_fb_destroy_dumb(struct drm_fb *fb)
722{
723 struct drm_mode_destroy_dumb destroy_arg;
724
725 assert(fb->type == BUFFER_PIXMAN_DUMB);
726
727 if (fb->map && fb->size > 0)
728 munmap(fb->map, fb->size);
729
730 memset(&destroy_arg, 0, sizeof(destroy_arg));
731 destroy_arg.handle = fb->handle;
732 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
733
734 drm_fb_destroy(fb);
735}
736
737static void
738drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300739{
740 struct drm_fb *fb = data;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300741
Daniel Stonee4256832017-04-04 17:54:27 +0100742 assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
743 fb->type == BUFFER_CURSOR);
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100744 drm_fb_destroy(fb);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300745}
746
747static struct drm_fb *
Daniel Stonef214fdc2016-11-14 17:43:57 +0000748drm_fb_create_dumb(struct drm_backend *b, int width, int height,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300749 uint32_t format)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200750{
751 struct drm_fb *fb;
752 int ret;
753
754 struct drm_mode_create_dumb create_arg;
755 struct drm_mode_destroy_dumb destroy_arg;
756 struct drm_mode_map_dumb map_arg;
757
Peter Huttererf3d62272013-08-08 11:57:05 +1000758 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200759 if (!fb)
760 return NULL;
761
Daniel Stone6e7a9612017-04-04 17:54:26 +0100762 fb->refcnt = 1;
763
Daniel Stone0b70fa42017-04-04 17:54:23 +0100764 fb->format = pixel_format_get_info(format);
765 if (!fb->format) {
766 weston_log("failed to look up format 0x%lx\n",
767 (unsigned long) format);
768 goto err_fb;
769 }
770
771 if (!fb->format->depth || !fb->format->bpp) {
772 weston_log("format 0x%lx is not compatible with dumb buffers\n",
773 (unsigned long) format);
774 goto err_fb;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300775 }
776
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700777 memset(&create_arg, 0, sizeof create_arg);
Daniel Stone0b70fa42017-04-04 17:54:23 +0100778 create_arg.bpp = fb->format->bpp;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200779 create_arg.width = width;
780 create_arg.height = height;
781
Giulio Camuffo954f1832014-10-11 18:27:30 +0300782 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200783 if (ret)
784 goto err_fb;
785
Daniel Stonefc175a72017-04-04 17:54:22 +0100786 fb->type = BUFFER_PIXMAN_DUMB;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200787 fb->handle = create_arg.handle;
788 fb->stride = create_arg.pitch;
789 fb->size = create_arg.size;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000790 fb->width = width;
791 fb->height = height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300792 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200793
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300794 ret = -1;
795
796 if (!b->no_addfb2) {
Yong Bakos4b6321f2016-08-17 17:37:55 -0700797 uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300798
799 handles[0] = fb->handle;
800 pitches[0] = fb->stride;
801 offsets[0] = 0;
802
803 ret = drmModeAddFB2(b->drm.fd, width, height,
Daniel Stone0b70fa42017-04-04 17:54:23 +0100804 fb->format->format,
805 handles, pitches, offsets,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300806 &fb->fb_id, 0);
807 if (ret) {
808 weston_log("addfb2 failed: %m\n");
809 b->no_addfb2 = 1;
810 }
811 }
812
813 if (ret) {
Daniel Stone0b70fa42017-04-04 17:54:23 +0100814 ret = drmModeAddFB(b->drm.fd, width, height,
815 fb->format->depth, fb->format->bpp,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300816 fb->stride, fb->handle, &fb->fb_id);
817 }
818
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200819 if (ret)
820 goto err_bo;
821
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700822 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200823 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400824 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200825 if (ret)
826 goto err_add_fb;
827
Chris Michael4a7ce1f2015-11-10 10:40:37 -0500828 fb->map = mmap(NULL, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300829 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200830 if (fb->map == MAP_FAILED)
831 goto err_add_fb;
832
833 return fb;
834
835err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300836 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200837err_bo:
838 memset(&destroy_arg, 0, sizeof(destroy_arg));
839 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300840 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200841err_fb:
842 free(fb);
843 return NULL;
844}
845
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200846static struct drm_fb *
Daniel Stone6e7a9612017-04-04 17:54:26 +0100847drm_fb_ref(struct drm_fb *fb)
848{
849 fb->refcnt++;
850 return fb;
851}
852
853static struct drm_fb *
Daniel Stonefc175a72017-04-04 17:54:22 +0100854drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
855 uint32_t format, enum drm_fb_type type)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300856{
857 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Derek Foreman482ffdf2016-07-08 12:50:57 -0500858 uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300859 int ret;
860
Daniel Stonefc175a72017-04-04 17:54:22 +0100861 if (fb) {
862 assert(fb->type == type);
Daniel Stone6e7a9612017-04-04 17:54:26 +0100863 return drm_fb_ref(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +0100864 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300865
Bryce Harringtonde16d892014-11-20 22:21:57 -0800866 fb = zalloc(sizeof *fb);
867 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200868 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300869
Daniel Stonefc175a72017-04-04 17:54:22 +0100870 fb->type = type;
Daniel Stone6e7a9612017-04-04 17:54:26 +0100871 fb->refcnt = 1;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300872 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300873
Daniel Stonec8c917c2016-11-14 17:45:58 +0000874 fb->width = gbm_bo_get_width(bo);
875 fb->height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200876 fb->stride = gbm_bo_get_stride(bo);
877 fb->handle = gbm_bo_get_handle(bo).u32;
Daniel Stone0b70fa42017-04-04 17:54:23 +0100878 fb->format = pixel_format_get_info(format);
Daniel Stonec8c917c2016-11-14 17:45:58 +0000879 fb->size = fb->stride * fb->height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300880 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300881
Daniel Stone0b70fa42017-04-04 17:54:23 +0100882 if (!fb->format) {
883 weston_log("couldn't look up format 0x%lx\n",
884 (unsigned long) format);
885 goto err_free;
886 }
887
Daniel Stonec8c917c2016-11-14 17:45:58 +0000888 if (backend->min_width > fb->width ||
889 fb->width > backend->max_width ||
890 backend->min_height > fb->height ||
891 fb->height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200892 weston_log("bo geometry out of bounds\n");
893 goto err_free;
894 }
895
896 ret = -1;
897
Giulio Camuffo954f1832014-10-11 18:27:30 +0300898 if (format && !backend->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200899 handles[0] = fb->handle;
900 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200901 offsets[0] = 0;
902
Daniel Stonec8c917c2016-11-14 17:45:58 +0000903 ret = drmModeAddFB2(backend->drm.fd, fb->width, fb->height,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200904 format, handles, pitches, offsets,
905 &fb->fb_id, 0);
906 if (ret) {
907 weston_log("addfb2 failed: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300908 backend->no_addfb2 = 1;
909 backend->sprites_are_broken = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200910 }
911 }
912
Daniel Stone0b70fa42017-04-04 17:54:23 +0100913 if (ret && fb->format->depth && fb->format->bpp)
Daniel Stonec8c917c2016-11-14 17:45:58 +0000914 ret = drmModeAddFB(backend->drm.fd, fb->width, fb->height,
Daniel Stone0b70fa42017-04-04 17:54:23 +0100915 fb->format->depth, fb->format->bpp,
916 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200917
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300918 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200919 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200920 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300921 }
922
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100923 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300924
925 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200926
927err_free:
928 free(fb);
929 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300930}
931
932static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500933drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200934{
Pekka Paalanende685b82012-12-04 15:58:12 +0200935 assert(fb->buffer_ref.buffer == NULL);
Daniel Stonefc175a72017-04-04 17:54:22 +0100936 assert(fb->type == BUFFER_CLIENT);
Pekka Paalanende685b82012-12-04 15:58:12 +0200937 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200938}
939
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200940static void
Daniel Stone05a5ac22017-04-04 17:54:25 +0100941drm_fb_unref(struct drm_fb *fb)
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200942{
943 if (!fb)
944 return;
945
Daniel Stone6e7a9612017-04-04 17:54:26 +0100946 assert(fb->refcnt > 0);
947 if (--fb->refcnt > 0)
948 return;
949
Daniel Stonefc175a72017-04-04 17:54:22 +0100950 switch (fb->type) {
951 case BUFFER_PIXMAN_DUMB:
Daniel Stone6e7a9612017-04-04 17:54:26 +0100952 drm_fb_destroy_dumb(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +0100953 break;
Daniel Stonee4256832017-04-04 17:54:27 +0100954 case BUFFER_CURSOR:
Daniel Stonefc175a72017-04-04 17:54:22 +0100955 case BUFFER_CLIENT:
956 gbm_bo_destroy(fb->bo);
957 break;
958 case BUFFER_GBM_SURFACE:
Daniel Stone05a5ac22017-04-04 17:54:25 +0100959 gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
Daniel Stonefc175a72017-04-04 17:54:22 +0100960 break;
961 default:
962 assert(NULL);
963 break;
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200964 }
965}
966
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000967/**
Daniel Stonebc15f682016-11-14 16:57:01 +0000968 * Allocate a new, empty, plane state.
969 */
970static struct drm_plane_state *
971drm_plane_state_alloc(struct drm_output_state *state_output,
972 struct drm_plane *plane)
973{
974 struct drm_plane_state *state = zalloc(sizeof(*state));
975
976 assert(state);
977 state->output_state = state_output;
978 state->plane = plane;
979
980 /* Here we only add the plane state to the desired link, and not
981 * set the member. Having an output pointer set means that the
982 * plane will be displayed on the output; this won't be the case
983 * when we go to disable a plane. In this case, it must be part of
984 * the commit (and thus the output state), but the member must be
985 * NULL, as it will not be on any output when the state takes
986 * effect.
987 */
988 if (state_output)
989 wl_list_insert(&state_output->plane_list, &state->link);
990 else
991 wl_list_init(&state->link);
992
993 return state;
994}
995
996/**
997 * Free an existing plane state. As a special case, the state will not
998 * normally be freed if it is the current state; see drm_plane_set_state.
999 */
1000static void
1001drm_plane_state_free(struct drm_plane_state *state, bool force)
1002{
1003 if (!state)
1004 return;
1005
1006 wl_list_remove(&state->link);
1007 wl_list_init(&state->link);
1008 state->output_state = NULL;
1009
1010 if (force || state != state->plane->state_cur) {
1011 drm_fb_unref(state->fb);
1012 free(state);
1013 }
1014}
1015
1016/**
1017 * Duplicate an existing plane state into a new plane state, storing it within
1018 * the given output state. If the output state already contains a plane state
1019 * for the drm_plane referenced by 'src', that plane state is freed first.
1020 */
1021static struct drm_plane_state *
1022drm_plane_state_duplicate(struct drm_output_state *state_output,
1023 struct drm_plane_state *src)
1024{
1025 struct drm_plane_state *dst = malloc(sizeof(*dst));
1026 struct drm_plane_state *old, *tmp;
1027
1028 assert(src);
1029 assert(dst);
1030 *dst = *src;
1031 wl_list_init(&dst->link);
1032
1033 wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
1034 /* Duplicating a plane state into the same output state, so
1035 * it can replace itself with an identical copy of itself,
1036 * makes no sense. */
1037 assert(old != src);
1038 if (old->plane == dst->plane)
1039 drm_plane_state_free(old, false);
1040 }
1041
1042 wl_list_insert(&state_output->plane_list, &dst->link);
1043 if (src->fb)
1044 dst->fb = drm_fb_ref(src->fb);
1045 dst->output_state = state_output;
1046 dst->complete = false;
1047
1048 return dst;
1049}
1050
1051/**
1052 * Remove a plane state from an output state; if the plane was previously
1053 * enabled, then replace it with a disabling state. This ensures that the
1054 * output state was untouched from it was before the plane state was
1055 * modified by the caller of this function.
1056 *
1057 * This is required as drm_output_state_get_plane may either allocate a
1058 * new plane state, in which case this function will just perform a matching
1059 * drm_plane_state_free, or it may instead repurpose an existing disabling
1060 * state (if the plane was previously active), in which case this function
1061 * will reset it.
1062 */
1063static void
1064drm_plane_state_put_back(struct drm_plane_state *state)
1065{
1066 struct drm_output_state *state_output;
1067 struct drm_plane *plane;
1068
1069 if (!state)
1070 return;
1071
1072 state_output = state->output_state;
1073 plane = state->plane;
1074 drm_plane_state_free(state, false);
1075
1076 /* Plane was previously disabled; no need to keep this temporary
1077 * state around. */
1078 if (!plane->state_cur->fb)
1079 return;
1080
1081 (void) drm_plane_state_alloc(state_output, plane);
1082}
1083
1084/**
Daniel Stone2ba17f42015-05-19 20:02:41 +01001085 * Return a plane state from a drm_output_state.
1086 */
1087static struct drm_plane_state *
1088drm_output_state_get_existing_plane(struct drm_output_state *state_output,
1089 struct drm_plane *plane)
1090{
1091 struct drm_plane_state *ps;
1092
1093 wl_list_for_each(ps, &state_output->plane_list, link) {
1094 if (ps->plane == plane)
1095 return ps;
1096 }
1097
1098 return NULL;
1099}
1100
1101/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001102 * Return a plane state from a drm_output_state, either existing or
1103 * freshly allocated.
1104 */
1105static struct drm_plane_state *
1106drm_output_state_get_plane(struct drm_output_state *state_output,
1107 struct drm_plane *plane)
1108{
1109 struct drm_plane_state *ps;
1110
Daniel Stone2ba17f42015-05-19 20:02:41 +01001111 ps = drm_output_state_get_existing_plane(state_output, plane);
1112 if (ps)
1113 return ps;
Daniel Stonebc15f682016-11-14 16:57:01 +00001114
1115 return drm_plane_state_alloc(state_output, plane);
1116}
1117
1118/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001119 * Allocate a new, empty drm_output_state. This should not generally be used
1120 * in the repaint cycle; see drm_output_state_duplicate.
1121 */
1122static struct drm_output_state *
1123drm_output_state_alloc(struct drm_output *output,
1124 struct drm_pending_state *pending_state)
Daniel Stone90648872016-10-21 18:08:37 +01001125{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001126 struct drm_output_state *state = zalloc(sizeof(*state));
1127
1128 assert(state);
1129 state->output = output;
1130 state->pending_state = pending_state;
1131 if (pending_state)
1132 wl_list_insert(&pending_state->output_list, &state->link);
1133 else
1134 wl_list_init(&state->link);
1135
Daniel Stonebc15f682016-11-14 16:57:01 +00001136 wl_list_init(&state->plane_list);
1137
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001138 return state;
1139}
1140
1141/**
1142 * Duplicate an existing drm_output_state into a new one. This is generally
1143 * used during the repaint cycle, to capture the existing state of an output
1144 * and modify it to create a new state to be used.
1145 *
1146 * The mode determines whether the output will be reset to an a blank state,
1147 * or an exact mirror of the current state.
1148 */
1149static struct drm_output_state *
1150drm_output_state_duplicate(struct drm_output_state *src,
1151 struct drm_pending_state *pending_state,
1152 enum drm_output_state_duplicate_mode plane_mode)
1153{
1154 struct drm_output_state *dst = malloc(sizeof(*dst));
Daniel Stonebc15f682016-11-14 16:57:01 +00001155 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001156
1157 assert(dst);
1158
1159 /* Copy the whole structure, then individually modify the
1160 * pending_state, as well as the list link into our pending
1161 * state. */
1162 *dst = *src;
1163
1164 dst->pending_state = pending_state;
1165 if (pending_state)
1166 wl_list_insert(&pending_state->output_list, &dst->link);
1167 else
1168 wl_list_init(&dst->link);
1169
Daniel Stonebc15f682016-11-14 16:57:01 +00001170 wl_list_init(&dst->plane_list);
1171
1172 wl_list_for_each(ps, &src->plane_list, link) {
1173 /* Don't carry planes which are now disabled; these should be
1174 * free for other outputs to reuse. */
1175 if (!ps->output)
1176 continue;
1177
1178 if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
1179 (void) drm_plane_state_alloc(dst, ps->plane);
1180 else
1181 (void) drm_plane_state_duplicate(dst, ps);
1182 }
1183
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001184 return dst;
1185}
1186
1187/**
1188 * Free an unused drm_output_state.
1189 */
1190static void
1191drm_output_state_free(struct drm_output_state *state)
1192{
Daniel Stonebc15f682016-11-14 16:57:01 +00001193 struct drm_plane_state *ps, *next;
1194
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001195 if (!state)
1196 return;
1197
Daniel Stonebc15f682016-11-14 16:57:01 +00001198 wl_list_for_each_safe(ps, next, &state->plane_list, link)
1199 drm_plane_state_free(ps, false);
1200
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001201 wl_list_remove(&state->link);
Daniel Stonebc15f682016-11-14 16:57:01 +00001202
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001203 free(state);
Daniel Stone90648872016-10-21 18:08:37 +01001204}
1205
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001206/**
1207 * Allocate a new drm_pending_state
1208 *
1209 * Allocate a new, empty, 'pending state' structure to be used across a
1210 * repaint cycle or similar.
1211 *
1212 * @param backend DRM backend
1213 * @returns Newly-allocated pending state structure
1214 */
1215static struct drm_pending_state *
1216drm_pending_state_alloc(struct drm_backend *backend)
1217{
1218 struct drm_pending_state *ret;
1219
1220 ret = calloc(1, sizeof(*ret));
1221 if (!ret)
1222 return NULL;
1223
1224 ret->backend = backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001225 wl_list_init(&ret->output_list);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001226
1227 return ret;
1228}
1229
1230/**
1231 * Free a drm_pending_state structure
1232 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001233 * Frees a pending_state structure, as well as any output_states connected
1234 * to this pending state.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001235 *
1236 * @param pending_state Pending state structure to free
1237 */
1238static void
1239drm_pending_state_free(struct drm_pending_state *pending_state)
1240{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001241 struct drm_output_state *output_state, *tmp;
1242
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001243 if (!pending_state)
1244 return;
1245
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001246 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1247 link) {
1248 drm_output_state_free(output_state);
1249 }
1250
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001251 free(pending_state);
1252}
1253
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001254/**
1255 * Find an output state in a pending state
1256 *
1257 * Given a pending_state structure, find the output_state for a particular
1258 * output.
1259 *
1260 * @param pending_state Pending state structure to search
1261 * @param output Output to find state for
1262 * @returns Output state if present, or NULL if not
1263 */
1264static struct drm_output_state *
1265drm_pending_state_get_output(struct drm_pending_state *pending_state,
1266 struct drm_output *output)
1267{
1268 struct drm_output_state *output_state;
1269
1270 wl_list_for_each(output_state, &pending_state->output_list, link) {
1271 if (output_state->output == output)
1272 return output_state;
1273 }
1274
1275 return NULL;
1276}
1277
1278/**
1279 * Mark a drm_output_state (the output's last state) as complete. This handles
1280 * any post-completion actions such as updating the repaint timer, disabling the
1281 * output, and finally freeing the state.
1282 */
1283static void
1284drm_output_update_complete(struct drm_output *output, uint32_t flags,
1285 unsigned int sec, unsigned int usec)
1286{
Daniel Stonebc15f682016-11-14 16:57:01 +00001287 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001288 struct timespec ts;
1289
1290 /* Stop the pageflip timer instead of rearming it here */
1291 if (output->pageflip_timer)
1292 wl_event_source_timer_update(output->pageflip_timer, 0);
1293
Daniel Stonebc15f682016-11-14 16:57:01 +00001294 wl_list_for_each(ps, &output->state_cur->plane_list, link)
1295 ps->complete = true;
1296
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001297 drm_output_state_free(output->state_last);
1298 output->state_last = NULL;
1299
1300 if (output->destroy_pending) {
1301 drm_output_destroy(&output->base);
1302 return;
1303 } else if (output->disable_pending) {
1304 weston_output_disable(&output->base);
1305 output->disable_pending = 0;
1306 return;
1307 }
1308
1309 ts.tv_sec = sec;
1310 ts.tv_nsec = usec * 1000;
1311 weston_output_finish_frame(&output->base, &ts, flags);
1312
1313 /* We can't call this from frame_notify, because the output's
1314 * repaint needed flag is cleared just after that */
1315 if (output->recorder)
1316 weston_output_schedule_repaint(&output->base);
1317}
1318
1319/**
1320 * Mark an output state as current on the output, i.e. it has been
1321 * submitted to the kernel. The mode argument determines whether this
1322 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
1323 * or asynchronously (in which case we wait for events to complete).
1324 */
1325static void
1326drm_output_assign_state(struct drm_output_state *state,
1327 enum drm_state_apply_mode mode)
1328{
1329 struct drm_output *output = state->output;
Daniel Stonebc15f682016-11-14 16:57:01 +00001330 struct drm_plane_state *plane_state;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001331
1332 assert(!output->state_last);
1333
1334 if (mode == DRM_STATE_APPLY_ASYNC)
1335 output->state_last = output->state_cur;
1336 else
1337 drm_output_state_free(output->state_cur);
1338
1339 wl_list_remove(&state->link);
1340 wl_list_init(&state->link);
1341 state->pending_state = NULL;
1342
1343 output->state_cur = state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001344
1345 /* Replace state_cur on each affected plane with the new state, being
1346 * careful to dispose of orphaned (but only orphaned) previous state.
1347 * If the previous state is not orphaned (still has an output_state
1348 * attached), it will be disposed of by freeing the output_state. */
1349 wl_list_for_each(plane_state, &state->plane_list, link) {
1350 struct drm_plane *plane = plane_state->plane;
1351
1352 if (plane->state_cur && !plane->state_cur->output_state)
1353 drm_plane_state_free(plane->state_cur, true);
1354 plane->state_cur = plane_state;
1355
1356 if (mode != DRM_STATE_APPLY_ASYNC) {
1357 plane_state->complete = true;
1358 continue;
1359 }
1360
1361 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
1362 output->vblank_pending++;
Daniel Stonee2e80132018-01-16 15:37:33 +00001363 else if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
1364 output->page_flip_pending = 1;
Daniel Stonebc15f682016-11-14 16:57:01 +00001365 }
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001366}
1367
1368
1369static int
1370drm_view_transform_supported(struct weston_view *ev)
1371{
1372 return !ev->transform.enabled ||
1373 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
1374}
1375
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001376static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001377drm_output_check_scanout_format(struct drm_output *output,
1378 struct weston_surface *es, struct gbm_bo *bo)
1379{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001380 uint32_t format;
1381 pixman_region32_t r;
1382
1383 format = gbm_bo_get_format(bo);
1384
Kristian Høgsberg3f97b342013-10-16 16:08:57 -07001385 if (format == GBM_FORMAT_ARGB8888) {
1386 /* We can scanout an ARGB buffer if the surface's
1387 * opaque region covers the whole output, but we have
1388 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -08001389 pixman_region32_init_rect(&r, 0, 0,
1390 output->base.width,
1391 output->base.height);
1392 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001393
1394 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001395 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001396
1397 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001398 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -07001399
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001400 if (output->gbm_format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -07001401 return format;
1402
1403 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001404}
1405
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001406static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001407drm_output_prepare_scanout_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001408 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001409{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001410 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02001411 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00001412 struct drm_plane *scanout_plane = output->scanout_plane;
1413 struct drm_plane_state *state;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001414 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001415 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001416 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001417 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001418
Daniel Stone90648872016-10-21 18:08:37 +01001419 /* Don't import buffers which span multiple outputs. */
1420 if (ev->output_mask != (1u << output->base.id))
1421 return NULL;
1422
Daniel Stone296d7a92016-10-21 18:05:37 +01001423 /* We use GBM to import buffers. */
1424 if (b->gbm == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001425 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001426
Daniel Stone296d7a92016-10-21 18:05:37 +01001427 if (buffer == NULL)
1428 return NULL;
Daniel Stone90648872016-10-21 18:08:37 +01001429 if (wl_shm_buffer_get(buffer->resource))
1430 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001431
1432 /* Make sure our view is exactly compatible with the output. */
1433 if (ev->geometry.x != output->base.x ||
1434 ev->geometry.y != output->base.y)
1435 return NULL;
Daniel Stone90648872016-10-21 18:08:37 +01001436 if (buffer->width != output->base.current_mode->width ||
1437 buffer->height != output->base.current_mode->height)
1438 return NULL;
1439
Daniel Stone296d7a92016-10-21 18:05:37 +01001440 if (ev->transform.enabled)
1441 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001442 if (ev->geometry.scissor_enabled)
1443 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001444 if (viewport->buffer.transform != output->base.transform)
1445 return NULL;
Daniel Stone90648872016-10-21 18:08:37 +01001446 if (viewport->buffer.scale != output->base.current_scale)
1447 return NULL;
1448 if (!drm_view_transform_supported(ev))
1449 return NULL;
1450
1451 if (ev->alpha != 1.0f)
1452 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001453
Daniel Stonee2e80132018-01-16 15:37:33 +00001454 state = drm_output_state_get_plane(output_state, scanout_plane);
1455 if (state->fb) {
1456 /* If there is already a framebuffer on the scanout plane,
1457 * a client view has already been placed on the scanout
1458 * view. In that case, do not free or put back the state,
1459 * but just leave it in place and quietly exit. */
1460 return NULL;
1461 }
1462
Giulio Camuffo954f1832014-10-11 18:27:30 +03001463 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -07001464 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001465
Rob Bradford9b101872012-09-14 23:25:41 +01001466 /* Unable to use the buffer for scanout */
1467 if (!bo)
1468 return NULL;
1469
Jason Ekstranda7af7042013-10-12 22:38:11 -05001470 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001471 if (format == 0) {
Daniel Stonee2e80132018-01-16 15:37:33 +00001472 drm_plane_state_put_back(state);
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +03001473 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001474 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +03001475 }
1476
Daniel Stonee2e80132018-01-16 15:37:33 +00001477 state->fb = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
1478 if (!state->fb) {
1479 drm_plane_state_put_back(state);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001480 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001481 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001482 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001483
Daniel Stonee2e80132018-01-16 15:37:33 +00001484 drm_fb_set_buffer(state->fb, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001485
Daniel Stonee2e80132018-01-16 15:37:33 +00001486 state->output = output;
1487
1488 state->src_x = 0;
1489 state->src_y = 0;
1490 state->src_w = state->fb->width << 16;
1491 state->src_h = state->fb->height << 16;
1492
1493 state->dest_x = 0;
1494 state->dest_y = 0;
1495 state->dest_w = output->base.current_mode->width;
1496 state->dest_h = output->base.current_mode->height;
1497
1498 return &scanout_plane->base;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001499}
1500
Daniel Stone95d48a22017-04-04 17:54:30 +01001501static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001502drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001503{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001504 struct drm_output *output = state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02001505 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001506 struct gbm_bo *bo;
Daniel Stone95d48a22017-04-04 17:54:30 +01001507 struct drm_fb *ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001508
Giulio Camuffo954f1832014-10-11 18:27:30 +03001509 output->base.compositor->renderer->repaint_output(&output->base,
1510 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001511
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001512 bo = gbm_surface_lock_front_buffer(output->gbm_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001513 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +02001514 weston_log("failed to lock front buffer: %m\n");
Daniel Stone95d48a22017-04-04 17:54:30 +01001515 return NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001516 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001517
Daniel Stone95d48a22017-04-04 17:54:30 +01001518 ret = drm_fb_get_from_bo(bo, b, output->gbm_format, BUFFER_GBM_SURFACE);
1519 if (!ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001520 weston_log("failed to get drm_fb for bo\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001521 gbm_surface_release_buffer(output->gbm_surface, bo);
Daniel Stone95d48a22017-04-04 17:54:30 +01001522 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001523 }
Daniel Stone95d48a22017-04-04 17:54:30 +01001524 ret->gbm_surface = output->gbm_surface;
1525
1526 return ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001527}
1528
Daniel Stone95d48a22017-04-04 17:54:30 +01001529static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001530drm_output_render_pixman(struct drm_output_state *state,
1531 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001532{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001533 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001534 struct weston_compositor *ec = output->base.compositor;
1535 pixman_region32_t total_damage, previous_damage;
1536
1537 pixman_region32_init(&total_damage);
1538 pixman_region32_init(&previous_damage);
1539
1540 pixman_region32_copy(&previous_damage, damage);
1541
1542 pixman_region32_union(&total_damage, damage, &output->previous_damage);
1543 pixman_region32_copy(&output->previous_damage, &previous_damage);
1544
1545 output->current_image ^= 1;
1546
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001547 pixman_renderer_output_set_buffer(&output->base,
1548 output->image[output->current_image]);
1549
1550 ec->renderer->repaint_output(&output->base, &total_damage);
1551
1552 pixman_region32_fini(&total_damage);
1553 pixman_region32_fini(&previous_damage);
Daniel Stone95d48a22017-04-04 17:54:30 +01001554
1555 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001556}
1557
1558static void
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001559drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001560{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001561 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001562 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +00001563 struct drm_plane_state *scanout_state;
Armin Krezović545dba62016-08-05 15:54:18 +02001564 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +01001565 struct drm_fb *fb;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001566
Daniel Stone4e84f7d2017-04-04 17:54:29 +01001567 /* If we already have a client buffer promoted to scanout, then we don't
1568 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +00001569 scanout_state = drm_output_state_get_plane(state,
1570 output->scanout_plane);
1571 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +01001572 return;
1573
Giulio Camuffo954f1832014-10-11 18:27:30 +03001574 if (b->use_pixman)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001575 fb = drm_output_render_pixman(state, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001576 else
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001577 fb = drm_output_render_gl(state, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +01001578
Daniel Stonee2e80132018-01-16 15:37:33 +00001579 if (!fb) {
1580 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +01001581 return;
Daniel Stonee2e80132018-01-16 15:37:33 +00001582 }
1583
1584 scanout_state->fb = fb;
1585 scanout_state->output = output;
1586
1587 scanout_state->src_x = 0;
1588 scanout_state->src_y = 0;
1589 scanout_state->src_w = output->base.current_mode->width << 16;
1590 scanout_state->src_h = output->base.current_mode->height << 16;
1591
1592 scanout_state->dest_x = 0;
1593 scanout_state->dest_y = 0;
1594 scanout_state->dest_w = scanout_state->src_w >> 16;
1595 scanout_state->dest_h = scanout_state->src_h >> 16;
1596
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001597
Giulio Camuffo954f1832014-10-11 18:27:30 +03001598 pixman_region32_subtract(&c->primary_plane.damage,
1599 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001600}
1601
1602static void
Richard Hughese7299962013-05-01 21:52:12 +01001603drm_output_set_gamma(struct weston_output *output_base,
1604 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
1605{
1606 int rc;
Armin Krezović545dba62016-08-05 15:54:18 +02001607 struct drm_output *output = to_drm_output(output_base);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001608 struct drm_backend *backend =
Armin Krezović545dba62016-08-05 15:54:18 +02001609 to_drm_backend(output->base.compositor);
Richard Hughese7299962013-05-01 21:52:12 +01001610
1611 /* check */
1612 if (output_base->gamma_size != size)
1613 return;
1614 if (!output->original_crtc)
1615 return;
1616
Giulio Camuffo954f1832014-10-11 18:27:30 +03001617 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +01001618 output->crtc_id,
1619 size, r, g, b);
1620 if (rc)
1621 weston_log("set gamma failed: %m\n");
1622}
1623
Bryce Harringtonada4f072015-06-30 13:25:46 -07001624/* Determine the type of vblank synchronization to use for the output.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001625 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07001626 * The pipe parameter indicates which CRTC is in use. Knowing this, we
1627 * can determine which vblank sequence type to use for it. Traditional
1628 * cards had only two CRTCs, with CRTC 0 using no special flags, and
1629 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
1630 * parameter indicates this.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001631 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07001632 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
1633 * 0-31. If this is non-zero it indicates we're dealing with a
1634 * multi-gpu situation and we need to calculate the vblank sync
1635 * using DRM_BLANK_HIGH_CRTC_MASK.
1636 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +03001637static unsigned int
1638drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02001639{
1640 if (output->pipe > 1)
1641 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
1642 DRM_VBLANK_HIGH_CRTC_MASK;
1643 else if (output->pipe > 0)
1644 return DRM_VBLANK_SECONDARY;
1645 else
1646 return 0;
1647}
1648
David Herrmann1edf44c2013-10-22 17:11:26 +02001649static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -05001650drm_output_repaint(struct weston_output *output_base,
Daniel Stoneb1f166d2017-03-01 11:34:10 +00001651 pixman_region32_t *damage,
1652 void *repaint_data)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001653{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001654 struct drm_pending_state *pending_state = repaint_data;
1655 struct drm_output_state *state = NULL;
Armin Krezović545dba62016-08-05 15:54:18 +02001656 struct drm_output *output = to_drm_output(output_base);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001657 struct drm_backend *backend =
Armin Krezović545dba62016-08-05 15:54:18 +02001658 to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00001659 struct drm_plane *scanout_plane = output->scanout_plane;
1660 struct drm_plane_state *scanout_state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001661 struct drm_plane_state *ps;
Daniel Stone085d2b92015-05-21 00:00:57 +01001662 struct drm_plane *p;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001663 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001664 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001665
Armin Krezović08368132016-09-30 14:11:05 +02001666 if (output->disable_pending || output->destroy_pending)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001667 goto err;
1668
1669 assert(!output->state_last);
1670
1671 /* If planes have been disabled in the core, we might not have
1672 * hit assign_planes at all, so might not have valid output state
1673 * here. */
1674 state = drm_pending_state_get_output(pending_state, output);
1675 if (!state)
1676 state = drm_output_state_duplicate(output->state_cur,
1677 pending_state,
1678 DRM_OUTPUT_STATE_CLEAR_PLANES);
Xiong Zhangabd5d472013-10-11 14:43:07 +08001679
Daniel Stonef30a18c2017-04-04 17:54:31 +01001680
Derek Foreman2cd87fe2017-04-13 13:48:48 -05001681 /* If disable_planes is set then assign_planes() wasn't
1682 * called for this render, so we could still have a stale
1683 * cursor plane set up.
1684 */
1685 if (output->base.disable_planes) {
1686 output->cursor_view = NULL;
Daniel Stone2ba17f42015-05-19 20:02:41 +01001687 output->cursor_plane->base.x = INT32_MIN;
1688 output->cursor_plane->base.y = INT32_MIN;
Derek Foreman2cd87fe2017-04-13 13:48:48 -05001689 }
1690
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001691 drm_output_render(state, damage);
Daniel Stonee2e80132018-01-16 15:37:33 +00001692 scanout_state = drm_output_state_get_plane(state, scanout_plane);
1693 if (!scanout_state || !scanout_state->fb)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001694 goto err;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001695
Daniel Stonee2e80132018-01-16 15:37:33 +00001696 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
1697 * legacy PageFlip API doesn't allow us to do clipping either. */
1698 assert(scanout_state->src_x == 0);
1699 assert(scanout_state->src_y == 0);
1700 assert(scanout_state->src_w ==
1701 (unsigned) (output->base.current_mode->width << 16));
1702 assert(scanout_state->src_h ==
1703 (unsigned) (output->base.current_mode->height << 16));
1704 assert(scanout_state->dest_x == 0);
1705 assert(scanout_state->dest_y == 0);
1706 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
1707 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
1708
Hardeningff39efa2013-09-18 23:56:35 +02001709 mode = container_of(output->base.current_mode, struct drm_mode, base);
Daniel Stonee2e80132018-01-16 15:37:33 +00001710 if (output->state_invalid || !scanout_plane->state_cur->fb ||
1711 scanout_plane->state_cur->fb->stride != scanout_state->fb->stride) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001712 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00001713 scanout_state->fb->fb_id,
1714 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001715 &output->connector_id, 1,
1716 &mode->mode_info);
1717 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001718 weston_log("set mode failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001719 goto err;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001720 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +03001721 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03001722
1723 output->state_invalid = false;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02001724 }
1725
Giulio Camuffo954f1832014-10-11 18:27:30 +03001726 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00001727 scanout_state->fb->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05001728 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001729 weston_log("queueing pageflip failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001730 goto err;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05001731 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01001732
Daniel Stone205c0a02017-04-04 17:54:33 +01001733 assert(!output->page_flip_pending);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03001734
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001735 if (output->pageflip_timer)
1736 wl_event_source_timer_update(output->pageflip_timer,
1737 backend->pageflip_timeout);
1738
Daniel Stone2ba17f42015-05-19 20:02:41 +01001739 drm_output_set_cursor(state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001740
Jesse Barnes58ef3792012-02-23 09:45:49 -05001741 /*
1742 * Now, update all the sprite surfaces
1743 */
Daniel Stonebc15f682016-11-14 16:57:01 +00001744 wl_list_for_each(ps, &state->plane_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001745 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001746 drmVBlank vbl = {
1747 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
1748 .request.sequence = 1,
1749 };
1750
Daniel Stonebc15f682016-11-14 16:57:01 +00001751 p = ps->plane;
Daniel Stone085d2b92015-05-21 00:00:57 +01001752 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001753 continue;
1754
Daniel Stonebc15f682016-11-14 16:57:01 +00001755 assert(p->state_cur->complete);
1756 assert(!!p->state_cur->output == !!p->state_cur->fb);
1757 assert(!p->state_cur->output || p->state_cur->output == output);
1758 assert(!ps->complete);
1759 assert(!ps->output || ps->output == output);
1760 assert(!!ps->output == !!ps->fb);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001761
Daniel Stonebc15f682016-11-14 16:57:01 +00001762 if (ps->fb && !backend->sprites_hidden)
1763 fb_id = ps->fb->fb_id;
Daniel Stone085d2b92015-05-21 00:00:57 +01001764
1765 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001766 output->crtc_id, fb_id, flags,
Daniel Stonebc15f682016-11-14 16:57:01 +00001767 ps->dest_x, ps->dest_y,
1768 ps->dest_w, ps->dest_h,
1769 ps->src_x, ps->src_y,
1770 ps->src_w, ps->src_h);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001771 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +02001772 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001773 ret, strerror(errno));
1774
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02001775 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -05001776
Jesse Barnes58ef3792012-02-23 09:45:49 -05001777 /*
1778 * Queue a vblank signal so we know when the surface
1779 * becomes active on the display or has been replaced.
1780 */
Daniel Stonebc15f682016-11-14 16:57:01 +00001781 vbl.request.signal = (unsigned long) ps;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001782 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001783 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001784 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001785 ret, strerror(errno));
1786 }
1787 }
1788
David Herrmann1edf44c2013-10-22 17:11:26 +02001789 return 0;
1790
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001791err:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -08001792 output->cursor_view = NULL;
Daniel Stonee2e80132018-01-16 15:37:33 +00001793
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001794 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +02001795
1796 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001797}
1798
1799static void
Jonas Ådahle5a12252013-04-05 23:07:11 +02001800drm_output_start_repaint_loop(struct weston_output *output_base)
1801{
Armin Krezović545dba62016-08-05 15:54:18 +02001802 struct drm_output *output = to_drm_output(output_base);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001803 struct drm_pending_state *pending_state = NULL;
1804 struct drm_output_state *state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001805 struct drm_plane_state *plane_state;
Daniel Stonee2e80132018-01-16 15:37:33 +00001806 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02001807 struct drm_backend *backend =
1808 to_drm_backend(output_base->compositor);
Jonas Ådahle5a12252013-04-05 23:07:11 +02001809 uint32_t fb_id;
Mario Kleinerf507ec32015-06-21 21:25:14 +02001810 struct timespec ts, tnow;
1811 struct timespec vbl2now;
1812 int64_t refresh_nsec;
1813 int ret;
1814 drmVBlank vbl = {
1815 .request.type = DRM_VBLANK_RELATIVE,
1816 .request.sequence = 0,
1817 .request.signal = 0,
1818 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001819
Armin Krezović08368132016-09-30 14:11:05 +02001820 if (output->disable_pending || output->destroy_pending)
Xiong Zhangabd5d472013-10-11 14:43:07 +08001821 return;
1822
Daniel Stonee2e80132018-01-16 15:37:33 +00001823 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001824 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +02001825 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001826 }
1827
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03001828 /* Need to smash all state in from scratch; current timings might not
1829 * be what we want, page flip might not work, etc.
1830 */
1831 if (output->state_invalid)
1832 goto finish_frame;
1833
Daniel Stonee2e80132018-01-16 15:37:33 +00001834 assert(scanout_plane->state_cur->output == output);
1835
Mario Kleinerf507ec32015-06-21 21:25:14 +02001836 /* Try to get current msc and timestamp via instant query */
1837 vbl.request.type |= drm_waitvblank_pipe(output);
1838 ret = drmWaitVBlank(backend->drm.fd, &vbl);
1839
1840 /* Error ret or zero timestamp means failure to get valid timestamp */
1841 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
1842 ts.tv_sec = vbl.reply.tval_sec;
1843 ts.tv_nsec = vbl.reply.tval_usec * 1000;
1844
1845 /* Valid timestamp for most recent vblank - not stale?
1846 * Stale ts could happen on Linux 3.17+, so make sure it
1847 * is not older than 1 refresh duration since now.
1848 */
1849 weston_compositor_read_presentation_clock(backend->compositor,
1850 &tnow);
1851 timespec_sub(&vbl2now, &tnow, &ts);
1852 refresh_nsec =
1853 millihz_to_nsec(output->base.current_mode->refresh);
1854 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
1855 drm_output_update_msc(output, vbl.reply.sequence);
1856 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001857 WP_PRESENTATION_FEEDBACK_INVALID);
Mario Kleinerf507ec32015-06-21 21:25:14 +02001858 return;
1859 }
1860 }
1861
1862 /* Immediate query didn't provide valid timestamp.
1863 * Use pageflip fallback.
1864 */
Daniel Stonee2e80132018-01-16 15:37:33 +00001865 fb_id = scanout_plane->state_cur->fb->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001866
Daniel Stone205c0a02017-04-04 17:54:33 +01001867 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001868 assert(!output->state_last);
1869
1870 pending_state = drm_pending_state_alloc(backend);
1871 state = drm_output_state_duplicate(output->state_cur, pending_state,
1872 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +01001873
Giulio Camuffo954f1832014-10-11 18:27:30 +03001874 if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
Jonas Ådahle5a12252013-04-05 23:07:11 +02001875 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
1876 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +02001877 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001878 }
David Herrmann3c688c52013-10-22 17:11:25 +02001879
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001880 if (output->pageflip_timer)
1881 wl_event_source_timer_update(output->pageflip_timer,
1882 backend->pageflip_timeout);
1883
Daniel Stonebc15f682016-11-14 16:57:01 +00001884 wl_list_for_each(plane_state, &state->plane_list, link) {
1885 if (plane_state->plane->type != WDRM_PLANE_TYPE_OVERLAY)
1886 continue;
1887
1888 vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
1889 vbl.request.type |= drm_waitvblank_pipe(output);
1890 vbl.request.sequence = 1;
1891 vbl.request.signal = (unsigned long) plane_state;
1892 drmWaitVBlank(backend->drm.fd, &vbl);
1893 }
1894
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001895 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
1896 drm_pending_state_free(pending_state);
1897
David Herrmann3c688c52013-10-22 17:11:25 +02001898 return;
1899
1900finish_frame:
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001901 drm_pending_state_free(pending_state);
1902
David Herrmann3c688c52013-10-22 17:11:25 +02001903 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +00001904 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001905 WP_PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +02001906}
1907
1908static void
Pekka Paalanen641307c2014-09-23 22:08:47 -04001909drm_output_update_msc(struct drm_output *output, unsigned int seq)
1910{
1911 uint64_t msc_hi = output->base.msc >> 32;
1912
1913 if (seq < (output->base.msc & 0xffffffff))
1914 msc_hi++;
1915
1916 output->base.msc = (msc_hi << 32) + seq;
1917}
1918
1919static void
Jesse Barnes58ef3792012-02-23 09:45:49 -05001920vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
1921 void *data)
1922{
Daniel Stonebc15f682016-11-14 16:57:01 +00001923 struct drm_plane_state *ps = (struct drm_plane_state *) data;
1924 struct drm_output_state *os = ps->output_state;
1925 struct drm_output *output = os->output;
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001926 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1927 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03001928
Pekka Paalanen641307c2014-09-23 22:08:47 -04001929 drm_output_update_msc(output, frame);
Daniel Stone65d87d02017-04-04 17:54:32 +01001930 output->vblank_pending--;
1931 assert(output->vblank_pending >= 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001932
Daniel Stonebc15f682016-11-14 16:57:01 +00001933 assert(ps->fb);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03001934
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001935 if (output->page_flip_pending || output->vblank_pending)
1936 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001937
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001938 drm_output_update_complete(output, flags, sec, usec);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001939}
1940
1941static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001942page_flip_handler(int fd, unsigned int frame,
1943 unsigned int sec, unsigned int usec, void *data)
1944{
Armin Krezović545dba62016-08-05 15:54:18 +02001945 struct drm_output *output = data;
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001946 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
1947 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
1948 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001949
Pekka Paalanen641307c2014-09-23 22:08:47 -04001950 drm_output_update_msc(output, frame);
1951
Daniel Stone205c0a02017-04-04 17:54:33 +01001952 assert(output->page_flip_pending);
Jonas Ådahle5a12252013-04-05 23:07:11 +02001953 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001954
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001955 if (output->vblank_pending)
1956 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001957
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001958 drm_output_update_complete(output, flags, sec, usec);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02001959}
1960
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001961/**
1962 * Begin a new repaint cycle
1963 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001964 * Called by the core compositor at the beginning of a repaint cycle. Creates
1965 * a new pending_state structure to own any output state created by individual
1966 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001967 */
1968static void *
1969drm_repaint_begin(struct weston_compositor *compositor)
1970{
1971 struct drm_backend *b = to_drm_backend(compositor);
1972 struct drm_pending_state *ret;
1973
1974 ret = drm_pending_state_alloc(b);
1975 b->repaint_data = ret;
1976
1977 return ret;
1978}
1979
1980/**
1981 * Flush a repaint set
1982 *
1983 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001984 * and should be flushed. Frees the pending state, transitioning ownership
1985 * of the output state from the pending state, to the update itself. When
1986 * the update completes (see drm_output_update_complete), the output
1987 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001988 */
1989static void
1990drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
1991{
1992 struct drm_backend *b = to_drm_backend(compositor);
1993 struct drm_pending_state *pending_state = repaint_data;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001994 struct drm_output_state *output_state, *tmp;
1995
1996 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1997 link) {
1998 drm_output_assign_state(output_state, DRM_STATE_APPLY_ASYNC);
1999 }
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002000
2001 drm_pending_state_free(pending_state);
2002 b->repaint_data = NULL;
2003}
2004
2005/**
2006 * Cancel a repaint set
2007 *
2008 * Called by the core compositor when a repaint has finished, so the data
2009 * held across the repaint cycle should be discarded.
2010 */
2011static void
2012drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
2013{
2014 struct drm_backend *b = to_drm_backend(compositor);
2015 struct drm_pending_state *pending_state = repaint_data;
2016
2017 drm_pending_state_free(pending_state);
2018 b->repaint_data = NULL;
2019}
2020
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05002021static uint32_t
Daniel Stone08d4edf2017-04-04 17:54:34 +01002022drm_output_check_plane_format(struct drm_plane *p,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002023 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002024{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05002025 uint32_t i, format;
2026
2027 format = gbm_bo_get_format(bo);
2028
2029 if (format == GBM_FORMAT_ARGB8888) {
2030 pixman_region32_t r;
2031
Kristian Høgsberg63093a32013-03-01 14:29:16 -05002032 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002033 ev->surface->width,
2034 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002035 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05002036
2037 if (!pixman_region32_not_empty(&r))
2038 format = GBM_FORMAT_XRGB8888;
2039
2040 pixman_region32_fini(&r);
2041 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002042
Daniel Stone08d4edf2017-04-04 17:54:34 +01002043 for (i = 0; i < p->count_formats; i++)
2044 if (p->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05002045 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002046
2047 return 0;
2048}
2049
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002050static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002051drm_output_prepare_overlay_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002052 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002053{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002054 struct drm_output *output = output_state->output;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002055 struct weston_compositor *ec = output->base.compositor;
Armin Krezović545dba62016-08-05 15:54:18 +02002056 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanen952b6c82014-03-14 14:38:15 +02002057 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002058 struct wl_resource *buffer_resource;
Daniel Stone08d4edf2017-04-04 17:54:34 +01002059 struct drm_plane *p;
Daniel Stonebc15f682016-11-14 16:57:01 +00002060 struct drm_plane_state *state = NULL;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002061 struct linux_dmabuf_buffer *dmabuf;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002062 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002063 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02002064 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002065 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04002066 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002067
Giulio Camuffo954f1832014-10-11 18:27:30 +03002068 if (b->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002069 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -05002070
Daniel Stone296d7a92016-10-21 18:05:37 +01002071 /* Don't import buffers which span multiple outputs. */
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002072 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002073 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +03002074
Daniel Stone296d7a92016-10-21 18:05:37 +01002075 /* We can only import GBM buffers. */
2076 if (b->gbm == NULL)
2077 return NULL;
2078
Jason Ekstranda7af7042013-10-12 22:38:11 -05002079 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002080 return NULL;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002081 buffer_resource = ev->surface->buffer_ref.buffer->resource;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002082 if (wl_shm_buffer_get(buffer_resource))
Rob Clark702ffae2012-08-09 14:18:27 -05002083 return NULL;
2084
Daniel Stone296d7a92016-10-21 18:05:37 +01002085 if (viewport->buffer.transform != output->base.transform)
2086 return NULL;
2087 if (viewport->buffer.scale != output->base.current_scale)
2088 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002089 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002090 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002091
Daniel Stone296d7a92016-10-21 18:05:37 +01002092 if (ev->alpha != 1.0f)
2093 return NULL;
2094
Daniel Stone085d2b92015-05-21 00:00:57 +01002095 wl_list_for_each(p, &b->plane_list, link) {
2096 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2097 continue;
2098
Daniel Stone5ff289a2017-10-07 12:59:02 +01002099 if (!drm_plane_is_available(p, output))
Daniel Stonebc15f682016-11-14 16:57:01 +00002100 continue;
2101
2102 state = drm_output_state_get_plane(output_state, p);
2103 if (state->fb) {
2104 state = NULL;
2105 continue;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002106 }
Daniel Stonebc15f682016-11-14 16:57:01 +00002107
2108 break;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002109 }
2110
2111 /* No sprites available */
Daniel Stonebc15f682016-11-14 16:57:01 +00002112 if (!state)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002113 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002114
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002115 if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) {
Bryce Harringtona3582072015-08-14 12:23:13 -07002116#ifdef HAVE_GBM_FD_IMPORT
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002117 /* XXX: TODO:
2118 *
2119 * Use AddFB2 directly, do not go via GBM.
2120 * Add support for multiplanar formats.
2121 * Both require refactoring in the DRM-backend to
2122 * support a mix of gbm_bos and drmfbs.
2123 */
2124 struct gbm_import_fd_data gbm_dmabuf = {
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +00002125 .fd = dmabuf->attributes.fd[0],
2126 .width = dmabuf->attributes.width,
2127 .height = dmabuf->attributes.height,
2128 .stride = dmabuf->attributes.stride[0],
2129 .format = dmabuf->attributes.format
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002130 };
2131
Micah Fedkec8890122017-02-01 15:28:23 -05002132 /* XXX: TODO:
2133 *
2134 * Currently the buffer is rejected if any dmabuf attribute
2135 * flag is set. This keeps us from passing an inverted /
2136 * interlaced / bottom-first buffer (or any other type that may
2137 * be added in the future) through to an overlay. Ultimately,
2138 * these types of buffers should be handled through buffer
2139 * transforms and not as spot-checks requiring specific
2140 * knowledge. */
2141 if (dmabuf->attributes.n_planes != 1 ||
2142 dmabuf->attributes.offset[0] != 0 ||
2143 dmabuf->attributes.flags)
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002144 return NULL;
2145
2146 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
2147 GBM_BO_USE_SCANOUT);
Bryce Harringtona3582072015-08-14 12:23:13 -07002148#else
Daniel Stonebc15f682016-11-14 16:57:01 +00002149 goto err;
Bryce Harringtona3582072015-08-14 12:23:13 -07002150#endif
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002151 } else {
2152 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
2153 buffer_resource, GBM_BO_USE_SCANOUT);
2154 }
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -04002155 if (!bo)
Daniel Stonebc15f682016-11-14 16:57:01 +00002156 goto err;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -04002157
Daniel Stone08d4edf2017-04-04 17:54:34 +01002158 format = drm_output_check_plane_format(p, ev, bo);
Daniel Stonebc15f682016-11-14 16:57:01 +00002159 if (format == 0)
2160 goto err;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002161
Daniel Stonebc15f682016-11-14 16:57:01 +00002162 state->fb = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
2163 if (!state->fb)
2164 goto err;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002165
Daniel Stonebc15f682016-11-14 16:57:01 +00002166 drm_fb_set_buffer(state->fb, ev->surface->buffer_ref.buffer);
2167
2168 state->output = output;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002169
Jason Ekstranda7af7042013-10-12 22:38:11 -05002170 box = pixman_region32_extents(&ev->transform.boundingbox);
Daniel Stone08d4edf2017-04-04 17:54:34 +01002171 p->base.x = box->x1;
2172 p->base.y = box->y1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002173
Jesse Barnes58ef3792012-02-23 09:45:49 -05002174 /*
2175 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -05002176 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -05002177 * for us already).
2178 */
2179 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002180 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002181 &output->base.region);
2182 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002183 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002184 tbox = weston_transformed_rect(output->base.width,
2185 output->base.height,
2186 output->base.transform,
2187 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002188 *box);
Daniel Stonebc15f682016-11-14 16:57:01 +00002189 state->dest_x = tbox.x1;
2190 state->dest_y = tbox.y1;
2191 state->dest_w = tbox.x2 - tbox.x1;
2192 state->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002193 pixman_region32_fini(&dest_rect);
2194
2195 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002196 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002197 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002198 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04002199
Jason Ekstranda7af7042013-10-12 22:38:11 -05002200 weston_view_from_global_fixed(ev,
2201 wl_fixed_from_int(box->x1),
2202 wl_fixed_from_int(box->y1),
2203 &sx1, &sy1);
2204 weston_view_from_global_fixed(ev,
2205 wl_fixed_from_int(box->x2),
2206 wl_fixed_from_int(box->y2),
2207 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04002208
2209 if (sx1 < 0)
2210 sx1 = 0;
2211 if (sy1 < 0)
2212 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002213 if (sx2 > wl_fixed_from_int(ev->surface->width))
2214 sx2 = wl_fixed_from_int(ev->surface->width);
2215 if (sy2 > wl_fixed_from_int(ev->surface->height))
2216 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04002217
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02002218 tbox.x1 = sx1;
2219 tbox.y1 = sy1;
2220 tbox.x2 = sx2;
2221 tbox.y2 = sy2;
2222
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002223 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
2224 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +02002225 viewport->buffer.transform,
2226 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01002227 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02002228
Daniel Stonebc15f682016-11-14 16:57:01 +00002229 state->src_x = tbox.x1 << 8;
2230 state->src_y = tbox.y1 << 8;
2231 state->src_w = (tbox.x2 - tbox.x1) << 8;
2232 state->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002233 pixman_region32_fini(&src_rect);
2234
Daniel Stone08d4edf2017-04-04 17:54:34 +01002235 return &p->base;
Daniel Stonebc15f682016-11-14 16:57:01 +00002236
2237err:
2238 drm_plane_state_put_back(state);
2239 if (bo)
2240 gbm_bo_destroy(bo);
2241 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002242}
2243
Pekka Paalanend0ead482014-06-16 12:05:40 +03002244/**
2245 * Update the image for the current cursor surface
2246 *
2247 * @param b DRM backend structure
2248 * @param bo GBM buffer object to write into
2249 * @param ev View to use for cursor image
2250 */
2251static void
2252cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
2253 struct weston_view *ev)
2254{
2255 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
2256 uint32_t buf[b->cursor_width * b->cursor_height];
2257 int32_t stride;
2258 uint8_t *s;
2259 int i;
2260
2261 assert(buffer && buffer->shm_buffer);
2262 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
2263 assert(ev->surface->width <= b->cursor_width);
2264 assert(ev->surface->height <= b->cursor_height);
2265
2266 memset(buf, 0, sizeof buf);
2267 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
2268 s = wl_shm_buffer_get_data(buffer->shm_buffer);
2269
2270 wl_shm_buffer_begin_access(buffer->shm_buffer);
2271 for (i = 0; i < ev->surface->height; i++)
2272 memcpy(buf + i * b->cursor_width,
2273 s + i * stride,
2274 ev->surface->width * 4);
2275 wl_shm_buffer_end_access(buffer->shm_buffer);
2276
2277 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
2278 weston_log("failed update cursor: %m\n");
2279}
2280
Daniel Stone2ba17f42015-05-19 20:02:41 +01002281static struct weston_plane *
2282drm_output_prepare_cursor_view(struct drm_output_state *output_state,
2283 struct weston_view *ev)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04002284{
Daniel Stone2ba17f42015-05-19 20:02:41 +01002285 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02002286 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stone2ba17f42015-05-19 20:02:41 +01002287 struct drm_plane *plane = output->cursor_plane;
2288 struct drm_plane_state *plane_state;
2289 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
2290 struct wl_shm_buffer *shmbuf;
2291 bool needs_update = false;
Derek Foremanbe428b32015-11-24 11:39:38 -06002292 float x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05002293
Daniel Stone2ba17f42015-05-19 20:02:41 +01002294 if (!plane)
2295 return NULL;
2296
2297 if (b->cursors_are_broken)
2298 return NULL;
2299
2300 if (!plane->state_cur->complete)
2301 return NULL;
2302
2303 if (plane->state_cur->output && plane->state_cur->output != output)
2304 return NULL;
2305
2306 /* Don't import buffers which span multiple outputs. */
2307 if (ev->output_mask != (1u << output->base.id))
2308 return NULL;
2309
2310 /* We use GBM to import SHM buffers. */
2311 if (b->gbm == NULL)
2312 return NULL;
2313
2314 if (ev->surface->buffer_ref.buffer == NULL)
2315 return NULL;
2316 shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
2317 if (!shmbuf)
2318 return NULL;
2319 if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)
2320 return NULL;
2321
2322 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
2323 return NULL;
2324 if (ev->transform.enabled &&
2325 (ev->transform.matrix.type > WESTON_MATRIX_TRANSFORM_TRANSLATE))
2326 return NULL;
2327 if (viewport->buffer.scale != output->base.current_scale)
2328 return NULL;
2329 if (ev->geometry.scissor_enabled)
2330 return NULL;
2331
2332 if (ev->surface->width > b->cursor_width ||
2333 ev->surface->height > b->cursor_height)
2334 return NULL;
2335
2336 plane_state =
2337 drm_output_state_get_plane(output_state, output->cursor_plane);
2338
2339 if (plane_state && plane_state->fb)
2340 return NULL;
2341
2342 /* Since we're setting plane state up front, we need to work out
2343 * whether or not we need to upload a new cursor. We can't use the
2344 * plane damage, since the planes haven't actually been calculated
2345 * yet: instead try to figure it out directly. KMS cursor planes are
2346 * pretty unique here, in that they lie partway between a Weston plane
2347 * (direct scanout) and a renderer. */
2348 if (ev != output->cursor_view ||
2349 pixman_region32_not_empty(&ev->surface->damage)) {
2350 output->current_cursor++;
2351 output->current_cursor =
2352 output->current_cursor %
2353 ARRAY_LENGTH(output->gbm_cursor_fb);
2354 needs_update = true;
2355 }
2356
2357 output->cursor_view = ev;
2358 weston_view_to_global_float(ev, 0, 0, &x, &y);
2359 plane->base.x = x;
2360 plane->base.y = y;
2361
2362 plane_state->fb =
2363 drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
2364 plane_state->output = output;
2365 plane_state->src_x = 0;
2366 plane_state->src_y = 0;
2367 plane_state->src_w = b->cursor_width << 16;
2368 plane_state->src_h = b->cursor_height << 16;
2369 plane_state->dest_x = (x - output->base.x) * output->base.current_scale;
2370 plane_state->dest_y = (y - output->base.y) * output->base.current_scale;
2371 plane_state->dest_w = b->cursor_width;
2372 plane_state->dest_h = b->cursor_height;
2373
2374 if (needs_update)
2375 cursor_bo_update(b, plane_state->fb->bo, ev);
2376
2377 return &plane->base;
2378}
2379
2380static void
2381drm_output_set_cursor(struct drm_output_state *output_state)
2382{
2383 struct drm_output *output = output_state->output;
2384 struct drm_backend *b = to_drm_backend(output->base.compositor);
2385 struct drm_plane *plane = output->cursor_plane;
2386 struct drm_plane_state *state;
2387 EGLint handle;
2388 struct gbm_bo *bo;
2389
2390 if (!plane)
2391 return;
2392
2393 state = drm_output_state_get_existing_plane(output_state, plane);
2394 if (!state)
2395 return;
2396
2397 if (!state->fb) {
2398 pixman_region32_fini(&plane->base.damage);
2399 pixman_region32_init(&plane->base.damage);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002400 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04002401 return;
2402 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05002403
Daniel Stone2ba17f42015-05-19 20:02:41 +01002404 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
2405 assert(!plane->state_cur->output || plane->state_cur->output == output);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05002406
Daniel Stone2ba17f42015-05-19 20:02:41 +01002407 if (plane->state_cur->fb != state->fb) {
2408 bo = state->fb->bo;
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04002409 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002410 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
Daniel Stone2ba17f42015-05-19 20:02:41 +01002411 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03002412 weston_log("failed to set cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01002413 goto err;
Rob Clarkab5b1e32012-08-09 13:24:45 -05002414 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002415 }
2416
Daniel Stone2ba17f42015-05-19 20:02:41 +01002417 pixman_region32_fini(&plane->base.damage);
2418 pixman_region32_init(&plane->base.damage);
Pekka Paalanen7eaed402015-11-27 14:20:58 +02002419
Daniel Stone2ba17f42015-05-19 20:02:41 +01002420 if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
2421 state->dest_x, state->dest_y)) {
Daniel Stonea7cba1d2017-04-04 17:54:21 +01002422 weston_log("failed to move cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01002423 goto err;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002424 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01002425
2426 return;
2427
2428err:
2429 b->cursors_are_broken = 1;
2430 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05002431}
2432
Jesse Barnes58ef3792012-02-23 09:45:49 -05002433static void
Daniel Stoneb1f166d2017-03-01 11:34:10 +00002434drm_assign_planes(struct weston_output *output_base, void *repaint_data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002435{
Armin Krezović545dba62016-08-05 15:54:18 +02002436 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002437 struct drm_pending_state *pending_state = repaint_data;
Armin Krezović545dba62016-08-05 15:54:18 +02002438 struct drm_output *output = to_drm_output(output_base);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002439 struct drm_output_state *state;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002440 struct drm_plane_state *plane_state;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002441 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002442 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002443 struct weston_plane *primary, *next_plane;
Matt Hoosierdf573032017-08-24 09:24:20 -05002444 bool picked_scanout = false;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002445
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002446 assert(!output->state_last);
2447 state = drm_output_state_duplicate(output->state_cur,
2448 pending_state,
2449 DRM_OUTPUT_STATE_CLEAR_PLANES);
2450
Jesse Barnes58ef3792012-02-23 09:45:49 -05002451 /*
2452 * Find a surface for each sprite in the output using some heuristics:
2453 * 1) size
2454 * 2) frequency of update
2455 * 3) opacity (though some hw might support alpha blending)
2456 * 4) clipping (this can be fixed with color keys)
2457 *
2458 * The idea is to save on blitting since this should save power.
2459 * If we can get a large video surface on the sprite for example,
2460 * the main display surface may not need to update at all, and
2461 * the client buffer can be used directly for the sprite surface
2462 * as we do for flipping full screen surfaces.
2463 */
2464 pixman_region32_init(&overlap);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002465 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002466
Giulio Camuffo954f1832014-10-11 18:27:30 +03002467 wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02002468 struct weston_surface *es = ev->surface;
2469
2470 /* Test whether this buffer can ever go into a plane:
2471 * non-shm, or small enough to be a cursor.
2472 *
2473 * Also, keep a reference when using the pixman renderer.
2474 * That makes it possible to do a seamless switch to the GL
2475 * renderer and since the pixman renderer keeps a reference
2476 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02002477 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002478 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02002479 (es->buffer_ref.buffer &&
2480 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Derek Foreman87430472015-10-15 10:24:48 -05002481 (ev->surface->width <= b->cursor_width &&
2482 ev->surface->height <= b->cursor_height))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05002483 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02002484 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05002485 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02002486
Jesse Barnes58ef3792012-02-23 09:45:49 -05002487 pixman_region32_init(&surface_overlap);
2488 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002489 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002490
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002491 next_plane = NULL;
Matt Hoosierdf573032017-08-24 09:24:20 -05002492 if (pixman_region32_not_empty(&surface_overlap) || picked_scanout)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002493 next_plane = primary;
2494 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002495 next_plane = drm_output_prepare_cursor_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05002496
2497 /* If a higher-stacked view already got assigned to scanout, it's incorrect to
2498 * assign a subsequent (lower-stacked) view to scanout.
2499 */
2500 if (next_plane == NULL) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002501 next_plane = drm_output_prepare_scanout_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05002502 if (next_plane)
2503 picked_scanout = true;
2504 }
2505
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002506 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002507 next_plane = drm_output_prepare_overlay_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05002508
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002509 if (next_plane == NULL)
2510 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002511
Jason Ekstranda7af7042013-10-12 22:38:11 -05002512 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002513
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002514 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002515 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002516 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04002517
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002518 if (next_plane == primary ||
Daniel Stone2ba17f42015-05-19 20:02:41 +01002519 (output->cursor_plane &&
2520 next_plane == &output->cursor_plane->base)) {
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002521 /* cursor plane involves a copy */
2522 ev->psf_flags = 0;
2523 } else {
2524 /* All other planes are a direct scanout of a
2525 * single client buffer.
2526 */
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002527 ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02002528 }
2529
Jesse Barnes58ef3792012-02-23 09:45:49 -05002530 pixman_region32_fini(&surface_overlap);
2531 }
2532 pixman_region32_fini(&overlap);
Daniel Stone2ba17f42015-05-19 20:02:41 +01002533
2534 /* We rely on output->cursor_view being both an accurate reflection of
2535 * the cursor plane's state, but also being maintained across repaints
2536 * to avoid unnecessary damage uploads, per the comment in
2537 * drm_output_prepare_cursor_view. In the event that we go from having
2538 * a cursor view to not having a cursor view, we need to clear it. */
2539 if (output->cursor_view) {
2540 plane_state =
2541 drm_output_state_get_existing_plane(state,
2542 output->cursor_plane);
2543 if (!plane_state || !plane_state->fb)
2544 output->cursor_view = NULL;
2545 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002546}
2547
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002548/**
2549 * Find the closest-matching mode for a given target
2550 *
2551 * Given a target mode, find the most suitable mode amongst the output's
2552 * current mode list to use, preferring the current mode if possible, to
2553 * avoid an expensive mode switch.
2554 *
2555 * @param output DRM output
2556 * @param target_mode Mode to attempt to match
2557 * @returns Pointer to a mode from the output's mode list
2558 */
Alex Wub7b8bda2012-04-17 17:20:48 +08002559static struct drm_mode *
2560choose_mode (struct drm_output *output, struct weston_mode *target_mode)
2561{
2562 struct drm_mode *tmp_mode = NULL, *mode;
2563
Hardeningff39efa2013-09-18 23:56:35 +02002564 if (output->base.current_mode->width == target_mode->width &&
2565 output->base.current_mode->height == target_mode->height &&
2566 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08002567 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02002568 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08002569
2570 wl_list_for_each(mode, &output->base.mode_list, base.link) {
2571 if (mode->mode_info.hdisplay == target_mode->width &&
2572 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02002573 if (mode->base.refresh == target_mode->refresh ||
2574 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08002575 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01002576 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08002577 tmp_mode = mode;
2578 }
2579 }
2580
2581 return tmp_mode;
2582}
2583
2584static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002585drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00002586static void
2587drm_output_fini_egl(struct drm_output *output);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002588static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002589drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00002590static void
2591drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02002592
2593static int
Alex Wub7b8bda2012-04-17 17:20:48 +08002594drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
2595{
2596 struct drm_output *output;
2597 struct drm_mode *drm_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002598 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08002599
2600 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002601 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08002602 return -1;
2603 }
2604
2605 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002606 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08002607 return -1;
2608 }
2609
Armin Krezović545dba62016-08-05 15:54:18 +02002610 b = to_drm_backend(output_base->compositor);
2611 output = to_drm_output(output_base);
Alex Wub7b8bda2012-04-17 17:20:48 +08002612 drm_mode = choose_mode (output, mode);
2613
2614 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02002615 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08002616 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02002617 }
2618
Hardeningff39efa2013-09-18 23:56:35 +02002619 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08002620 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08002621
Hardeningff39efa2013-09-18 23:56:35 +02002622 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08002623
Hardeningff39efa2013-09-18 23:56:35 +02002624 output->base.current_mode = &drm_mode->base;
2625 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08002626 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
2627
Daniel Stonef30a18c2017-04-04 17:54:31 +01002628 /* XXX: This drops our current buffer too early, before we've started
2629 * displaying it. Ideally this should be much more atomic and
2630 * integrated with a full repaint cycle, rather than doing a
2631 * sledgehammer modeswitch first, and only later showing new
2632 * content.
2633 */
Daniel Stonee2e80132018-01-16 15:37:33 +00002634 output->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +08002635
Giulio Camuffo954f1832014-10-11 18:27:30 +03002636 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002637 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002638 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002639 weston_log("failed to init output pixman state with "
2640 "new mode\n");
2641 return -1;
2642 }
2643 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +00002644 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002645 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002646 weston_log("failed to init output egl state with "
2647 "new mode");
2648 return -1;
2649 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02002650 }
2651
Alex Wub7b8bda2012-04-17 17:20:48 +08002652 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08002653}
2654
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002655static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002656on_drm_input(int fd, uint32_t mask, void *data)
2657{
2658 drmEventContext evctx;
2659
2660 memset(&evctx, 0, sizeof evctx);
Emil Velikov863e66b2017-04-04 18:07:34 +01002661 evctx.version = 2;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002662 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002663 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002664 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002665
2666 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002667}
2668
2669static int
Daniel Stoneefa504f2016-12-19 16:48:20 +00002670init_kms_caps(struct drm_backend *b)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002671{
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002672 uint64_t cap;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002673 int ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002674 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002675
Daniel Stoneefa504f2016-12-19 16:48:20 +00002676 weston_log("using %s\n", b->drm.filename);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04002677
Daniel Stoneefa504f2016-12-19 16:48:20 +00002678 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002679 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002680 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002681 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002682 clk_id = CLOCK_REALTIME;
2683
Giulio Camuffo954f1832014-10-11 18:27:30 +03002684 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04002685 weston_log("Error: failed to set presentation clock %d.\n",
2686 clk_id);
2687 return -1;
2688 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02002689
Daniel Stoneefa504f2016-12-19 16:48:20 +00002690 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03002691 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002692 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03002693 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03002694 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03002695
Daniel Stoneefa504f2016-12-19 16:48:20 +00002696 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03002697 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002698 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03002699 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03002700 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03002701
Daniel Stonebe1090b2017-09-06 17:29:57 +01002702 if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
2703 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
2704 b->universal_planes = (ret == 0);
2705 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01002706 weston_log("DRM: %s universal planes\n",
2707 b->universal_planes ? "supports" : "does not support");
2708
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002709 return 0;
2710}
2711
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002712static struct gbm_device *
2713create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002714{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002715 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01002716
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03002717 gl_renderer = weston_load_module("gl-renderer.so",
2718 "gl_renderer_interface");
2719 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002720 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03002721
2722 /* GBM will load a dri driver, but even though they need symbols from
2723 * libglapi, in some version of Mesa they are not linked to it. Since
2724 * only the gl-renderer module links to it, the call above won't make
2725 * these symbols globally available, and loading the DRI driver fails.
2726 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
2727 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
2728
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002729 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002730
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002731 return gbm;
2732}
2733
Bryce Harringtonc056a982015-05-19 15:25:18 -07002734/* When initializing EGL, if the preferred buffer format isn't available
Bryce Harringtonb9939982016-04-15 20:28:26 -07002735 * we may be able to substitute an ARGB format for an XRGB one.
Derek Foremanc4cfe852015-05-15 12:12:40 -05002736 *
2737 * This returns 0 if substitution isn't possible, but 0 might be a
2738 * legitimate format for other EGL platforms, so the caller is
2739 * responsible for checking for 0 before calling gl_renderer->create().
2740 *
2741 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
2742 * but it's entirely possible we'll see this again on other implementations.
2743 */
2744static int
2745fallback_format_for(uint32_t format)
2746{
2747 switch (format) {
2748 case GBM_FORMAT_XRGB8888:
2749 return GBM_FORMAT_ARGB8888;
2750 case GBM_FORMAT_XRGB2101010:
2751 return GBM_FORMAT_ARGB2101010;
2752 default:
2753 return 0;
2754 }
2755}
2756
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002757static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002758drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002759{
Derek Foreman6d556372015-11-04 14:47:33 -06002760 EGLint format[3] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01002761 b->gbm_format,
2762 fallback_format_for(b->gbm_format),
Derek Foreman6d556372015-11-04 14:47:33 -06002763 0,
Derek Foremanc4cfe852015-05-15 12:12:40 -05002764 };
Derek Foreman6d556372015-11-04 14:47:33 -06002765 int n_formats = 2;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01002766
Derek Foremanc4cfe852015-05-15 12:12:40 -05002767 if (format[1])
Derek Foreman6d556372015-11-04 14:47:33 -06002768 n_formats = 3;
Miguel A. Vicodddc6702016-05-18 17:41:07 +02002769 if (gl_renderer->display_create(b->compositor,
2770 EGL_PLATFORM_GBM_KHR,
2771 (void *)b->gbm,
Miguel A. Vico41700e32016-05-18 17:47:59 +02002772 NULL,
Miguel A. Vicodddc6702016-05-18 17:41:07 +02002773 gl_renderer->opaque_attribs,
2774 format,
2775 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002776 return -1;
2777 }
2778
2779 return 0;
2780}
2781
2782static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002783init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002784{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002785 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002786
Giulio Camuffo954f1832014-10-11 18:27:30 +03002787 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002788 return -1;
2789
Giulio Camuffo954f1832014-10-11 18:27:30 +03002790 if (drm_backend_create_gl_renderer(b) < 0) {
2791 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002792 return -1;
2793 }
2794
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002795 return 0;
2796}
2797
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002798static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002799init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002800{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002801 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002802}
2803
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002804/**
Pekka Paalanenec272712014-06-05 11:22:25 +03002805 * Create a drm_plane for a hardware plane
2806 *
2807 * Creates one drm_plane structure for a hardware plane, and initialises its
2808 * properties and formats.
2809 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01002810 * In the absence of universal plane support, where KMS does not explicitly
2811 * expose the primary and cursor planes to userspace, this may also create
2812 * an 'internal' plane for internal management.
2813 *
Pekka Paalanenec272712014-06-05 11:22:25 +03002814 * This function does not add the plane to the list of usable planes in Weston
2815 * itself; the caller is responsible for this.
2816 *
2817 * Call drm_plane_destroy to clean up the plane.
2818 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01002819 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +03002820 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +01002821 * @param kplane DRM plane to create, or NULL if creating internal plane
2822 * @param output Output to create internal plane for, or NULL
2823 * @param type Type to use when creating internal plane, or invalid
2824 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +03002825 */
2826static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +01002827drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
2828 struct drm_output *output, enum wdrm_plane_type type,
2829 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +03002830{
2831 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01002832 drmModeObjectProperties *props;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002833 int num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01002834
2835 static struct drm_property_enum_info plane_type_enums[] = {
2836 [WDRM_PLANE_TYPE_PRIMARY] = {
2837 .name = "Primary",
2838 },
2839 [WDRM_PLANE_TYPE_OVERLAY] = {
2840 .name = "Overlay",
2841 },
2842 [WDRM_PLANE_TYPE_CURSOR] = {
2843 .name = "Cursor",
2844 },
2845 };
2846 static const struct drm_property_info plane_props[] = {
2847 [WDRM_PLANE_TYPE] = {
2848 .name = "type",
2849 .enum_values = plane_type_enums,
2850 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
2851 },
2852 };
Pekka Paalanenec272712014-06-05 11:22:25 +03002853
Daniel Stone2ba17f42015-05-19 20:02:41 +01002854 plane = zalloc(sizeof(*plane) +
2855 (sizeof(uint32_t) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +03002856 if (!plane) {
2857 weston_log("%s: out of memory\n", __func__);
2858 return NULL;
2859 }
2860
2861 plane->backend = b;
Daniel Stonebc15f682016-11-14 16:57:01 +00002862 plane->state_cur = drm_plane_state_alloc(NULL, plane);
2863 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +03002864
Daniel Stone2ba17f42015-05-19 20:02:41 +01002865 if (kplane) {
2866 plane->possible_crtcs = kplane->possible_crtcs;
2867 plane->plane_id = kplane->plane_id;
2868 plane->count_formats = kplane->count_formats;
2869 memcpy(plane->formats, kplane->formats,
2870 kplane->count_formats * sizeof(kplane->formats[0]));
2871
2872 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
2873 DRM_MODE_OBJECT_PLANE);
2874 if (!props) {
2875 weston_log("couldn't get plane properties\n");
2876 goto err;
2877 }
2878 drm_property_info_populate(b, plane_props, plane->props,
2879 WDRM_PLANE__COUNT, props);
2880 plane->type =
2881 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
2882 props,
2883 WDRM_PLANE_TYPE__COUNT);
2884 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01002885 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01002886 else {
2887 plane->possible_crtcs = (1 << output->pipe);
2888 plane->plane_id = 0;
2889 plane->count_formats = 1;
2890 plane->formats[0] = format;
2891 plane->type = type;
2892 }
2893
2894 if (plane->type == WDRM_PLANE_TYPE__COUNT)
2895 goto err_props;
2896
2897 /* With universal planes, everything is a DRM plane; without
2898 * universal planes, the only DRM planes are overlay planes.
2899 * Everything else is a fake plane. */
2900 if (b->universal_planes) {
2901 assert(kplane);
2902 } else {
2903 if (kplane)
2904 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
2905 else
2906 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
2907 output);
2908 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01002909
Pekka Paalanenec272712014-06-05 11:22:25 +03002910 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01002911 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +03002912
2913 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002914
2915err_props:
2916 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
2917err:
2918 drm_plane_state_free(plane->state_cur, true);
2919 free(plane);
2920 return NULL;
2921}
2922
2923/**
2924 * Find, or create, a special-purpose plane
2925 *
2926 * Primary and cursor planes are a special case, in that before universal
2927 * planes, they are driven by non-plane API calls. Without universal plane
2928 * support, the only way to configure a primary plane is via drmModeSetCrtc,
2929 * and the only way to configure a cursor plane is drmModeSetCursor2.
2930 *
2931 * Although they may actually be regular planes in the hardware, without
2932 * universal plane support, these planes are not actually exposed to
2933 * userspace in the regular plane list.
2934 *
2935 * However, for ease of internal tracking, we want to manage all planes
2936 * through the same drm_plane structures. Therefore, when we are running
2937 * without universal plane support, we create fake drm_plane structures
2938 * to track these planes.
2939 *
2940 * @param b DRM backend
2941 * @param output Output to use for plane
2942 * @param type Type of plane
2943 */
2944static struct drm_plane *
2945drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
2946 enum wdrm_plane_type type)
2947{
2948 struct drm_plane *plane;
2949
2950 if (!b->universal_planes) {
2951 uint32_t format;
2952
2953 switch (type) {
2954 case WDRM_PLANE_TYPE_CURSOR:
2955 format = GBM_FORMAT_ARGB8888;
2956 break;
Daniel Stonee2e80132018-01-16 15:37:33 +00002957 case WDRM_PLANE_TYPE_PRIMARY:
2958 /* We don't know what formats the primary plane supports
2959 * before universal planes, so we just assume that the
2960 * GBM format works; however, this isn't set until after
2961 * the output is created. */
2962 format = 0;
2963 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002964 default:
2965 assert(!"invalid type in drm_output_find_special_plane");
2966 break;
2967 }
2968
2969 return drm_plane_create(b, NULL, output, type, format);
2970 }
2971
2972 wl_list_for_each(plane, &b->plane_list, link) {
2973 struct drm_output *tmp;
2974 bool found_elsewhere = false;
2975
2976 if (plane->type != type)
2977 continue;
2978 if (!drm_plane_is_available(plane, output))
2979 continue;
2980
2981 /* On some platforms, primary/cursor planes can roam
2982 * between different CRTCs, so make sure we don't claim the
2983 * same plane for two outputs. */
2984 wl_list_for_each(tmp, &b->compositor->pending_output_list,
2985 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +00002986 if (tmp->cursor_plane == plane ||
2987 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +01002988 found_elsewhere = true;
2989 break;
2990 }
2991 }
2992 wl_list_for_each(tmp, &b->compositor->output_list,
2993 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +00002994 if (tmp->cursor_plane == plane ||
2995 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +01002996 found_elsewhere = true;
2997 break;
2998 }
2999 }
3000
3001 if (found_elsewhere)
3002 continue;
3003
3004 plane->possible_crtcs = (1 << output->pipe);
3005 return plane;
3006 }
3007
3008 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +03003009}
3010
3011/**
3012 * Destroy one DRM plane
3013 *
3014 * Destroy a DRM plane, removing it from screen and releasing its retained
3015 * buffers in the process. The counterpart to drm_plane_create.
3016 *
3017 * @param plane Plane to deallocate (will be freed)
3018 */
3019static void
3020drm_plane_destroy(struct drm_plane *plane)
3021{
Daniel Stone2ba17f42015-05-19 20:02:41 +01003022 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
3023 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
3024 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +00003025 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003026 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +03003027 weston_plane_release(&plane->base);
3028 wl_list_remove(&plane->link);
3029 free(plane);
3030}
3031
3032/**
3033 * Initialise sprites (overlay planes)
3034 *
3035 * Walk the list of provided DRM planes, and add overlay planes.
3036 *
3037 * Call destroy_sprites to free these planes.
3038 *
3039 * @param b DRM compositor backend
3040 */
3041static void
3042create_sprites(struct drm_backend *b)
3043{
3044 drmModePlaneRes *kplane_res;
3045 drmModePlane *kplane;
3046 struct drm_plane *drm_plane;
3047 uint32_t i;
3048
3049 kplane_res = drmModeGetPlaneResources(b->drm.fd);
3050 if (!kplane_res) {
3051 weston_log("failed to get plane resources: %s\n",
3052 strerror(errno));
3053 return;
3054 }
3055
3056 for (i = 0; i < kplane_res->count_planes; i++) {
3057 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
3058 if (!kplane)
3059 continue;
3060
Daniel Stone2ba17f42015-05-19 20:02:41 +01003061 drm_plane = drm_plane_create(b, kplane, NULL,
3062 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +03003063 drmModeFreePlane(kplane);
3064 if (!drm_plane)
3065 continue;
3066
Daniel Stone085d2b92015-05-21 00:00:57 +01003067 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
3068 weston_compositor_stack_plane(b->compositor,
3069 &drm_plane->base,
3070 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +03003071 }
3072
3073 drmModeFreePlaneResources(kplane_res);
3074}
3075
3076/**
3077 * Clean up sprites (overlay planes)
3078 *
3079 * The counterpart to create_sprites.
3080 *
3081 * @param b DRM compositor backend
3082 */
3083static void
3084destroy_sprites(struct drm_backend *b)
3085{
3086 struct drm_plane *plane, *next;
3087
Daniel Stone085d2b92015-05-21 00:00:57 +01003088 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03003089 drm_plane_destroy(plane);
3090}
3091
3092/**
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003093 * Add a mode to output's mode list
3094 *
3095 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
3096 * output's mode list.
3097 *
3098 * @param output DRM output to add mode to
3099 * @param info DRM mode structure to add
3100 * @returns Newly-allocated Weston/DRM mode structure
3101 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003102static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003103drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003104{
3105 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04003106 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003107
3108 mode = malloc(sizeof *mode);
3109 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003110 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003111
3112 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02003113 mode->base.width = info->hdisplay;
3114 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04003115
3116 /* Calculate higher precision (mHz) refresh rate */
3117 refresh = (info->clock * 1000000LL / info->htotal +
3118 info->vtotal / 2) / info->vtotal;
3119
3120 if (info->flags & DRM_MODE_FLAG_INTERLACE)
3121 refresh *= 2;
3122 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
3123 refresh /= 2;
3124 if (info->vscan > 1)
3125 refresh /= info->vscan;
3126
3127 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003128 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003129
3130 if (info->type & DRM_MODE_TYPE_PREFERRED)
3131 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
3132
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003133 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
3134
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003135 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003136}
3137
3138static int
3139drm_subpixel_to_wayland(int drm_value)
3140{
3141 switch (drm_value) {
3142 default:
3143 case DRM_MODE_SUBPIXEL_UNKNOWN:
3144 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
3145 case DRM_MODE_SUBPIXEL_NONE:
3146 return WL_OUTPUT_SUBPIXEL_NONE;
3147 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
3148 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
3149 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
3150 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
3151 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
3152 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
3153 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
3154 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
3155 }
3156}
3157
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003158/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003159static uint32_t
3160drm_get_backlight(struct drm_output *output)
3161{
3162 long brightness, max_brightness, norm;
3163
3164 brightness = backlight_get_brightness(output->backlight);
3165 max_brightness = backlight_get_max_brightness(output->backlight);
3166
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003167 /* convert it on a scale of 0 to 255 */
3168 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003169
3170 return (uint32_t) norm;
3171}
3172
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003173/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003174static void
3175drm_set_backlight(struct weston_output *output_base, uint32_t value)
3176{
Armin Krezović545dba62016-08-05 15:54:18 +02003177 struct drm_output *output = to_drm_output(output_base);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003178 long max_brightness, new_brightness;
3179
3180 if (!output->backlight)
3181 return;
3182
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04003183 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003184 return;
3185
3186 max_brightness = backlight_get_max_brightness(output->backlight);
3187
3188 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003189 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003190
3191 backlight_set_brightness(output->backlight, new_brightness);
3192}
3193
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003194static void
3195drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
3196{
Armin Krezović545dba62016-08-05 15:54:18 +02003197 struct drm_output *output = to_drm_output(output_base);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003198 struct weston_compositor *ec = output_base->compositor;
Armin Krezović545dba62016-08-05 15:54:18 +02003199 struct drm_backend *b = to_drm_backend(ec);
Daniel Stone02cf4662017-03-03 16:19:39 +00003200 struct drm_property_info *prop =
3201 &output->props_conn[WDRM_CONNECTOR_DPMS];
Daniel Stone36609c72015-06-18 07:49:02 +01003202 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003203
Daniel Stone02cf4662017-03-03 16:19:39 +00003204 if (!prop->prop_id)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003205 return;
3206
Daniel Stone36609c72015-06-18 07:49:02 +01003207 ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
Daniel Stone02cf4662017-03-03 16:19:39 +00003208 prop->prop_id, level);
Daniel Stone36609c72015-06-18 07:49:02 +01003209 if (ret) {
3210 weston_log("DRM: DPMS: failed property set for %s\n",
3211 output->base.name);
3212 return;
3213 }
3214
3215 output->dpms = level;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003216}
3217
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003218static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03003219 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
3220 [DRM_MODE_CONNECTOR_VGA] = "VGA",
3221 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
3222 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
3223 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
3224 [DRM_MODE_CONNECTOR_Composite] = "Composite",
3225 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
3226 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
3227 [DRM_MODE_CONNECTOR_Component] = "Component",
3228 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
3229 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
3230 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
3231 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
3232 [DRM_MODE_CONNECTOR_TV] = "TV",
3233 [DRM_MODE_CONNECTOR_eDP] = "eDP",
Pekka Paalanenab81f152015-08-24 14:27:07 +03003234#ifdef DRM_MODE_CONNECTOR_DSI
Pekka Paalanen89c49b32015-08-19 15:25:57 +03003235 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
3236 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Pekka Paalanenab81f152015-08-24 14:27:07 +03003237#endif
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04003238};
3239
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003240/** Create a name given a DRM connector
3241 *
3242 * \param con The DRM connector whose type and id form the name.
3243 * \return A newly allocate string, or NULL on error. Must be free()'d
3244 * after use.
3245 *
3246 * The name does not identify the DRM display device.
3247 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003248static char *
3249make_connector_name(const drmModeConnector *con)
3250{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003251 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03003252 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003253 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003254
3255 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
3256 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03003257
3258 if (!type_name)
3259 type_name = "UNNAMED";
3260
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003261 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
3262 if (ret < 0)
3263 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003264
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003265 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003266}
3267
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003268static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003269find_crtc_for_connector(struct drm_backend *b,
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003270 drmModeRes *resources, drmModeConnector *connector)
3271{
3272 drmModeEncoder *encoder;
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003273 int i, j;
Daniel Stone75487c22017-01-16 14:33:38 +00003274 int ret = -1;
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003275
3276 for (j = 0; j < connector->count_encoders; j++) {
Daniel Stone75487c22017-01-16 14:33:38 +00003277 uint32_t possible_crtcs, encoder_id, crtc_id;
3278
Giulio Camuffo954f1832014-10-11 18:27:30 +03003279 encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003280 if (encoder == NULL) {
3281 weston_log("Failed to get encoder.\n");
Daniel Stone75487c22017-01-16 14:33:38 +00003282 continue;
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003283 }
Daniel Stone75487c22017-01-16 14:33:38 +00003284 encoder_id = encoder->encoder_id;
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003285 possible_crtcs = encoder->possible_crtcs;
Daniel Stone75487c22017-01-16 14:33:38 +00003286 crtc_id = encoder->crtc_id;
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003287 drmModeFreeEncoder(encoder);
3288
3289 for (i = 0; i < resources->count_crtcs; i++) {
Daniel Stone72c0e1b2017-02-09 13:49:15 +00003290 if (!(possible_crtcs & (1 << i)))
3291 continue;
3292
3293 if (drm_output_find_by_crtc(b, resources->crtcs[i]))
3294 continue;
3295
Daniel Stone75487c22017-01-16 14:33:38 +00003296 /* Try to preserve the existing
3297 * CRTC -> encoder -> connector routing; it makes
3298 * initialisation faster, and also since we have a
3299 * very dumb picking algorithm, may preserve a better
3300 * choice. */
3301 if (!connector->encoder_id ||
3302 (encoder_id == connector->encoder_id &&
3303 crtc_id == resources->crtcs[i]))
3304 return i;
3305
3306 ret = i;
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003307 }
3308 }
3309
Daniel Stone75487c22017-01-16 14:33:38 +00003310 return ret;
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003311}
3312
Daniel Stonee4256832017-04-04 17:54:27 +01003313static void drm_output_fini_cursor_egl(struct drm_output *output)
3314{
3315 unsigned int i;
3316
3317 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
3318 drm_fb_unref(output->gbm_cursor_fb[i]);
3319 output->gbm_cursor_fb[i] = NULL;
3320 }
3321}
3322
3323static int
3324drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
3325{
3326 unsigned int i;
3327
Daniel Stone2ba17f42015-05-19 20:02:41 +01003328 /* No point creating cursors if we don't have a plane for them. */
3329 if (!output->cursor_plane)
3330 return 0;
3331
Daniel Stonee4256832017-04-04 17:54:27 +01003332 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
3333 struct gbm_bo *bo;
3334
3335 bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
3336 GBM_FORMAT_ARGB8888,
3337 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
3338 if (!bo)
3339 goto err;
3340
3341 output->gbm_cursor_fb[i] =
3342 drm_fb_get_from_bo(bo, b, GBM_FORMAT_ARGB8888,
3343 BUFFER_CURSOR);
3344 if (!output->gbm_cursor_fb[i]) {
3345 gbm_bo_destroy(bo);
3346 goto err;
3347 }
3348 }
3349
3350 return 0;
3351
3352err:
3353 weston_log("cursor buffers unavailable, using gl cursors\n");
3354 b->cursors_are_broken = 1;
3355 drm_output_fini_cursor_egl(output);
3356 return -1;
3357}
3358
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02003359/* Init output state that depends on gl or gbm */
3360static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003361drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02003362{
Derek Foremanc4cfe852015-05-15 12:12:40 -05003363 EGLint format[2] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01003364 output->gbm_format,
3365 fallback_format_for(output->gbm_format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05003366 };
Daniel Stonee4256832017-04-04 17:54:27 +01003367 int n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003368
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01003369 output->gbm_surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02003370 output->base.current_mode->width,
3371 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05003372 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02003373 GBM_BO_USE_SCANOUT |
3374 GBM_BO_USE_RENDERING);
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01003375 if (!output->gbm_surface) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02003376 weston_log("failed to create gbm surface\n");
3377 return -1;
3378 }
3379
Derek Foremanc4cfe852015-05-15 12:12:40 -05003380 if (format[1])
3381 n_formats = 2;
Miguel A. Vicoc095cde2016-05-18 17:43:00 +02003382 if (gl_renderer->output_window_create(&output->base,
3383 (EGLNativeWindowType)output->gbm_surface,
3384 output->gbm_surface,
3385 gl_renderer->opaque_attribs,
3386 format,
3387 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003388 weston_log("failed to create gl renderer output state\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01003389 gbm_surface_destroy(output->gbm_surface);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02003390 return -1;
3391 }
3392
Daniel Stonee4256832017-04-04 17:54:27 +01003393 drm_output_init_cursor_egl(output, b);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02003394
3395 return 0;
3396}
3397
Daniel Stone3e661f72016-11-04 17:24:06 +00003398static void
3399drm_output_fini_egl(struct drm_output *output)
3400{
Daniel Stonee2e80132018-01-16 15:37:33 +00003401 struct drm_backend *b = to_drm_backend(output->base.compositor);
3402
3403 /* Destroying the GBM surface will destroy all our GBM buffers,
3404 * regardless of refcount. Ensure we destroy them here. */
3405 if (!b->shutting_down &&
3406 output->scanout_plane->state_cur->fb &&
3407 output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
3408 drm_plane_state_free(output->scanout_plane->state_cur, true);
3409 output->scanout_plane->state_cur =
3410 drm_plane_state_alloc(NULL, output->scanout_plane);
3411 output->scanout_plane->state_cur->complete = true;
3412 }
3413
Daniel Stone3e661f72016-11-04 17:24:06 +00003414 gl_renderer->output_destroy(&output->base);
3415 gbm_surface_destroy(output->gbm_surface);
Daniel Stonee4256832017-04-04 17:54:27 +01003416 drm_output_fini_cursor_egl(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00003417}
3418
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04003419static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003420drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003421{
Hardeningff39efa2013-09-18 23:56:35 +02003422 int w = output->base.current_mode->width;
3423 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03003424 uint32_t format = output->gbm_format;
3425 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003426 unsigned int i;
3427
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03003428 switch (format) {
3429 case GBM_FORMAT_XRGB8888:
3430 pixman_format = PIXMAN_x8r8g8b8;
3431 break;
3432 case GBM_FORMAT_RGB565:
3433 pixman_format = PIXMAN_r5g6b5;
3434 break;
3435 default:
3436 weston_log("Unsupported pixman format 0x%x\n", format);
3437 return -1;
3438 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003439
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03003440 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003441 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03003442 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003443 if (!output->dumb[i])
3444 goto err;
3445
3446 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03003447 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003448 output->dumb[i]->map,
3449 output->dumb[i]->stride);
3450 if (!output->image[i])
3451 goto err;
3452 }
3453
3454 if (pixman_renderer_output_create(&output->base) < 0)
3455 goto err;
3456
3457 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02003458 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003459
3460 return 0;
3461
3462err:
3463 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
3464 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01003465 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003466 if (output->image[i])
3467 pixman_image_unref(output->image[i]);
3468
3469 output->dumb[i] = NULL;
3470 output->image[i] = NULL;
3471 }
3472
3473 return -1;
3474}
3475
3476static void
3477drm_output_fini_pixman(struct drm_output *output)
3478{
Daniel Stonee2e80132018-01-16 15:37:33 +00003479 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003480 unsigned int i;
3481
Daniel Stonee2e80132018-01-16 15:37:33 +00003482 /* Destroying the Pixman surface will destroy all our buffers,
3483 * regardless of refcount. Ensure we destroy them here. */
3484 if (!b->shutting_down &&
3485 output->scanout_plane->state_cur->fb &&
3486 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
3487 drm_plane_state_free(output->scanout_plane->state_cur, true);
3488 output->scanout_plane->state_cur =
3489 drm_plane_state_alloc(NULL, output->scanout_plane);
3490 output->scanout_plane->state_cur->complete = true;
3491 }
3492
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003493 pixman_renderer_output_destroy(&output->base);
3494 pixman_region32_fini(&output->previous_damage);
3495
3496 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003497 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01003498 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003499 output->dumb[i] = NULL;
3500 output->image[i] = NULL;
3501 }
3502}
3503
Richard Hughes2b2092a2013-04-24 14:58:02 +01003504static void
3505edid_parse_string(const uint8_t *data, char text[])
3506{
3507 int i;
3508 int replaced = 0;
3509
3510 /* this is always 12 bytes, but we can't guarantee it's null
3511 * terminated or not junk. */
3512 strncpy(text, (const char *) data, 12);
3513
Bryce Harrington9c7de162015-08-28 13:04:26 -07003514 /* guarantee our new string is null-terminated */
3515 text[12] = '\0';
3516
Richard Hughes2b2092a2013-04-24 14:58:02 +01003517 /* remove insane chars */
3518 for (i = 0; text[i] != '\0'; i++) {
3519 if (text[i] == '\n' ||
3520 text[i] == '\r') {
3521 text[i] = '\0';
3522 break;
3523 }
3524 }
3525
3526 /* ensure string is printable */
3527 for (i = 0; text[i] != '\0'; i++) {
3528 if (!isprint(text[i])) {
3529 text[i] = '-';
3530 replaced++;
3531 }
3532 }
3533
3534 /* if the string is random junk, ignore the string */
3535 if (replaced > 4)
3536 text[0] = '\0';
3537}
3538
3539#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
3540#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
3541#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
3542#define EDID_OFFSET_DATA_BLOCKS 0x36
3543#define EDID_OFFSET_LAST_BLOCK 0x6c
3544#define EDID_OFFSET_PNPID 0x08
3545#define EDID_OFFSET_SERIAL 0x0c
3546
3547static int
3548edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
3549{
3550 int i;
3551 uint32_t serial_number;
3552
3553 /* check header */
3554 if (length < 128)
3555 return -1;
3556 if (data[0] != 0x00 || data[1] != 0xff)
3557 return -1;
3558
3559 /* decode the PNP ID from three 5 bit words packed into 2 bytes
3560 * /--08--\/--09--\
3561 * 7654321076543210
3562 * |\---/\---/\---/
3563 * R C1 C2 C3 */
3564 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
3565 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
3566 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
3567 edid->pnp_id[3] = '\0';
3568
3569 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
3570 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
3571 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
3572 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
3573 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
3574 if (serial_number > 0)
3575 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
3576
3577 /* parse EDID data */
3578 for (i = EDID_OFFSET_DATA_BLOCKS;
3579 i <= EDID_OFFSET_LAST_BLOCK;
3580 i += 18) {
3581 /* ignore pixel clock data */
3582 if (data[i] != 0)
3583 continue;
3584 if (data[i+2] != 0)
3585 continue;
3586
3587 /* any useful blocks? */
3588 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
3589 edid_parse_string(&data[i+5],
3590 edid->monitor_name);
3591 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
3592 edid_parse_string(&data[i+5],
3593 edid->serial_number);
3594 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
3595 edid_parse_string(&data[i+5],
3596 edid->eisa_id);
3597 }
3598 }
3599 return 0;
3600}
3601
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03003602/** Parse monitor make, model and serial from EDID
3603 *
3604 * \param b The backend instance.
3605 * \param output The output whose \c drm_edid to fill in.
3606 * \param props The DRM connector properties to get the EDID from.
3607 * \param make[out] The monitor make (PNP ID).
3608 * \param model[out] The monitor model (name).
3609 * \param serial_number[out] The monitor serial number.
3610 *
3611 * Each of \c *make, \c *model and \c *serial_number are set only if the
3612 * information is found in the EDID. The pointers they are set to must not
3613 * be free()'d explicitly, instead they get implicitly freed when the
3614 * \c drm_output is destroyed.
3615 */
Richard Hughes2b2092a2013-04-24 14:58:02 +01003616static void
Daniel Stone02cf4662017-03-03 16:19:39 +00003617find_and_parse_output_edid(struct drm_backend *b, struct drm_output *output,
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03003618 drmModeObjectPropertiesPtr props,
3619 const char **make,
3620 const char **model,
3621 const char **serial_number)
Richard Hughes2b2092a2013-04-24 14:58:02 +01003622{
3623 drmModePropertyBlobPtr edid_blob = NULL;
Daniel Stone02cf4662017-03-03 16:19:39 +00003624 uint32_t blob_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +01003625 int rc;
3626
Daniel Stone02cf4662017-03-03 16:19:39 +00003627 blob_id =
3628 drm_property_get_value(&output->props_conn[WDRM_CONNECTOR_EDID],
3629 props, 0);
3630 if (!blob_id)
3631 return;
3632
3633 edid_blob = drmModeGetPropertyBlob(b->drm.fd, blob_id);
Richard Hughes2b2092a2013-04-24 14:58:02 +01003634 if (!edid_blob)
3635 return;
3636
3637 rc = edid_parse(&output->edid,
3638 edid_blob->data,
3639 edid_blob->length);
3640 if (!rc) {
3641 weston_log("EDID data '%s', '%s', '%s'\n",
3642 output->edid.pnp_id,
3643 output->edid.monitor_name,
3644 output->edid.serial_number);
3645 if (output->edid.pnp_id[0] != '\0')
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03003646 *make = output->edid.pnp_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +01003647 if (output->edid.monitor_name[0] != '\0')
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03003648 *model = output->edid.monitor_name;
Richard Hughes2b2092a2013-04-24 14:58:02 +01003649 if (output->edid.serial_number[0] != '\0')
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03003650 *serial_number = output->edid.serial_number;
Richard Hughes2b2092a2013-04-24 14:58:02 +01003651 }
3652 drmModeFreePropertyBlob(edid_blob);
3653}
3654
Kristian Høgsberga30989a2013-05-23 17:23:15 -04003655static int
3656parse_modeline(const char *s, drmModeModeInfo *mode)
3657{
3658 char hsync[16];
3659 char vsync[16];
3660 float fclock;
3661
3662 mode->type = DRM_MODE_TYPE_USERDEF;
3663 mode->hskew = 0;
3664 mode->vscan = 0;
3665 mode->vrefresh = 0;
3666 mode->flags = 0;
3667
Rob Bradford307e09e2013-07-26 16:29:40 +01003668 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04003669 &fclock,
3670 &mode->hdisplay,
3671 &mode->hsync_start,
3672 &mode->hsync_end,
3673 &mode->htotal,
3674 &mode->vdisplay,
3675 &mode->vsync_start,
3676 &mode->vsync_end,
3677 &mode->vtotal, hsync, vsync) != 11)
3678 return -1;
3679
3680 mode->clock = fclock * 1000;
3681 if (strcmp(hsync, "+hsync") == 0)
3682 mode->flags |= DRM_MODE_FLAG_PHSYNC;
3683 else if (strcmp(hsync, "-hsync") == 0)
3684 mode->flags |= DRM_MODE_FLAG_NHSYNC;
3685 else
3686 return -1;
3687
3688 if (strcmp(vsync, "+vsync") == 0)
3689 mode->flags |= DRM_MODE_FLAG_PVSYNC;
3690 else if (strcmp(vsync, "-vsync") == 0)
3691 mode->flags |= DRM_MODE_FLAG_NVSYNC;
3692 else
3693 return -1;
3694
Emmanuel Gil Peyrota62138b2016-05-02 22:40:11 +01003695 snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
3696 mode->hdisplay, mode->vdisplay, fclock);
3697
Kristian Høgsberga30989a2013-05-23 17:23:15 -04003698 return 0;
3699}
3700
Rob Bradford66bd9f52013-06-25 18:56:42 +01003701static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03003702setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01003703 struct weston_output *output,
3704 const char *s)
3705{
3706 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05003707 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01003708 struct udev_seat *seat;
3709
Giulio Camuffo954f1832014-10-11 18:27:30 +03003710 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05003711 if (!seat)
3712 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01003713
Derek Foreman0720ea32015-07-15 13:00:35 -05003714 seat->base.output = output;
3715
Derek Foreman1281a362015-07-31 16:55:32 -05003716 pointer = weston_seat_get_pointer(&seat->base);
3717 if (pointer)
3718 weston_pointer_clamp(pointer,
3719 &pointer->x,
3720 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01003721 }
3722}
3723
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003724static int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003725parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003726{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003727 int ret = 0;
3728
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003729 if (s == NULL)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003730 *gbm_format = default_value;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003731 else if (strcmp(s, "xrgb8888") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003732 *gbm_format = GBM_FORMAT_XRGB8888;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003733 else if (strcmp(s, "rgb565") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003734 *gbm_format = GBM_FORMAT_RGB565;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003735 else if (strcmp(s, "xrgb2101010") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003736 *gbm_format = GBM_FORMAT_XRGB2101010;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003737 else {
3738 weston_log("fatal: unrecognized pixel format: %s\n", s);
3739 ret = -1;
3740 }
3741
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003742 return ret;
3743}
3744
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003745/**
3746 * Choose suitable mode for an output
3747 *
3748 * Find the most suitable mode to use for initial setup (or reconfiguration on
3749 * hotplug etc) for a DRM output.
3750 *
3751 * @param output DRM output to choose mode for
3752 * @param kind Strategy and preference to use when choosing mode
3753 * @param width Desired width for this output
3754 * @param height Desired height for this output
3755 * @param current_mode Mode currently being displayed on this output
3756 * @param modeline Manually-entered mode (may be NULL)
3757 * @returns A mode from the output's mode list, or NULL if none available
3758 */
3759static struct drm_mode *
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003760drm_output_choose_initial_mode(struct drm_backend *backend,
3761 struct drm_output *output,
3762 enum weston_drm_backend_output_mode mode,
Armin Krezović08368132016-09-30 14:11:05 +02003763 const char *modeline,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003764 const drmModeModeInfo *current_mode)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003765{
3766 struct drm_mode *preferred = NULL;
3767 struct drm_mode *current = NULL;
3768 struct drm_mode *configured = NULL;
3769 struct drm_mode *best = NULL;
3770 struct drm_mode *drm_mode;
Armin Krezović08368132016-09-30 14:11:05 +02003771 drmModeModeInfo drm_modeline;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003772 int32_t width = 0;
3773 int32_t height = 0;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01003774 uint32_t refresh = 0;
3775 int n;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003776
Armin Krezović08368132016-09-30 14:11:05 +02003777 if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01003778 n = sscanf(modeline, "%dx%d@%d", &width, &height, &refresh);
3779 if (n != 2 && n != 3) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003780 width = -1;
3781
Armin Krezović08368132016-09-30 14:11:05 +02003782 if (parse_modeline(modeline, &drm_modeline) == 0) {
3783 configured = drm_output_add_mode(output, &drm_modeline);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003784 if (!configured)
3785 return NULL;
3786 } else {
3787 weston_log("Invalid modeline \"%s\" for output %s\n",
Armin Krezović08368132016-09-30 14:11:05 +02003788 modeline, output->base.name);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003789 }
3790 }
3791 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003792
3793 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003794 if (width == drm_mode->base.width &&
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01003795 height == drm_mode->base.height &&
3796 (refresh == 0 || refresh == drm_mode->mode_info.vrefresh))
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003797 configured = drm_mode;
3798
comic fans7a5c5622016-03-17 14:29:27 +02003799 if (memcmp(current_mode, &drm_mode->mode_info,
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003800 sizeof *current_mode) == 0)
3801 current = drm_mode;
3802
3803 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
3804 preferred = drm_mode;
3805
3806 best = drm_mode;
3807 }
3808
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003809 if (current == NULL && current_mode->clock != 0) {
3810 current = drm_output_add_mode(output, current_mode);
3811 if (!current)
3812 return NULL;
3813 }
3814
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003815 if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003816 configured = current;
3817
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003818 if (configured)
3819 return configured;
3820
3821 if (preferred)
3822 return preferred;
3823
3824 if (current)
3825 return current;
3826
3827 if (best)
3828 return best;
3829
3830 weston_log("no available modes for %s\n", output->base.name);
3831 return NULL;
3832}
3833
Pekka Paalaneneee580b2014-06-04 16:43:06 +03003834static int
3835connector_get_current_mode(drmModeConnector *connector, int drm_fd,
3836 drmModeModeInfo *mode)
3837{
3838 drmModeEncoder *encoder;
3839 drmModeCrtc *crtc;
3840
3841 /* Get the current mode on the crtc that's currently driving
3842 * this connector. */
3843 encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
3844 memset(mode, 0, sizeof *mode);
3845 if (encoder != NULL) {
3846 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
3847 drmModeFreeEncoder(encoder);
3848 if (crtc == NULL)
3849 return -1;
3850 if (crtc->mode_valid)
3851 *mode = crtc->mode;
3852 drmModeFreeCrtc(crtc);
3853 }
3854
3855 return 0;
3856}
3857
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003858static int
Armin Krezović08368132016-09-30 14:11:05 +02003859drm_output_set_mode(struct weston_output *base,
3860 enum weston_drm_backend_output_mode mode,
3861 const char *modeline)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003862{
Armin Krezović08368132016-09-30 14:11:05 +02003863 struct drm_output *output = to_drm_output(base);
3864 struct drm_backend *b = to_drm_backend(base->compositor);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003865
Armin Krezović445b41b2016-10-09 23:48:16 +02003866 struct drm_mode *current;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003867 drmModeModeInfo crtc_mode;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003868
Armin Krezović08368132016-09-30 14:11:05 +02003869 if (connector_get_current_mode(output->connector, b->drm.fd, &crtc_mode) < 0)
Armin Krezović445b41b2016-10-09 23:48:16 +02003870 return -1;
David Herrmann0f0d54e2011-12-08 17:05:45 +01003871
Armin Krezović08368132016-09-30 14:11:05 +02003872 current = drm_output_choose_initial_mode(b, output, mode, modeline, &crtc_mode);
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003873 if (!current)
Armin Krezović445b41b2016-10-09 23:48:16 +02003874 return -1;
Armin Krezović08368132016-09-30 14:11:05 +02003875
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003876 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02003877 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04003878
Armin Krezović08368132016-09-30 14:11:05 +02003879 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
3880 output->base.native_mode = output->base.current_mode;
3881 output->base.native_scale = output->base.current_scale;
3882
Armin Krezović08368132016-09-30 14:11:05 +02003883 return 0;
Armin Krezović08368132016-09-30 14:11:05 +02003884}
3885
3886static void
3887drm_output_set_gbm_format(struct weston_output *base,
3888 const char *gbm_format)
3889{
3890 struct drm_output *output = to_drm_output(base);
3891 struct drm_backend *b = to_drm_backend(base->compositor);
3892
3893 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
3894 output->gbm_format = b->gbm_format;
Daniel Stonee2e80132018-01-16 15:37:33 +00003895
3896 /* Without universal planes, we can't discover which formats are
3897 * supported by the primary plane; we just hope that the GBM format
3898 * works. */
3899 if (!b->universal_planes)
3900 output->scanout_plane->formats[0] = output->gbm_format;
Armin Krezović08368132016-09-30 14:11:05 +02003901}
3902
3903static void
3904drm_output_set_seat(struct weston_output *base,
3905 const char *seat)
3906{
3907 struct drm_output *output = to_drm_output(base);
3908 struct drm_backend *b = to_drm_backend(base->compositor);
3909
3910 setup_output_seat_constraint(b, &output->base,
3911 seat ? seat : "");
3912}
3913
3914static int
3915drm_output_enable(struct weston_output *base)
3916{
3917 struct drm_output *output = to_drm_output(base);
3918 struct drm_backend *b = to_drm_backend(base->compositor);
3919 struct weston_mode *m;
3920
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00003921 if (b->pageflip_timeout)
3922 drm_output_pageflip_timer_create(output);
3923
Giulio Camuffo954f1832014-10-11 18:27:30 +03003924 if (b->use_pixman) {
3925 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003926 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00003927 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003928 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003929 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02003930 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00003931 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04003932 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04003933
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003934 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04003935 weston_log("Initialized backlight, device %s\n",
3936 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003937 output->base.set_backlight = drm_set_backlight;
3938 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04003939 } else {
3940 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003941 }
3942
Jonas Ådahle5a12252013-04-05 23:07:11 +02003943 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05003944 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003945 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003946 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08003947 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01003948
Richard Hughese7299962013-05-01 21:52:12 +01003949 output->base.gamma_size = output->original_crtc->gamma_size;
3950 output->base.set_gamma = drm_output_set_gamma;
3951
Daniel Stone2ba17f42015-05-19 20:02:41 +01003952 if (output->cursor_plane)
3953 weston_compositor_stack_plane(b->compositor,
3954 &output->cursor_plane->base,
3955 NULL);
3956 else
3957 b->cursors_are_broken = 1;
3958
Daniel Stonee2e80132018-01-16 15:37:33 +00003959 weston_compositor_stack_plane(b->compositor,
3960 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003961 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02003962
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04003963 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01003964 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003965 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08003966 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003967 m->width, m->height, m->refresh / 1000.0,
3968 m->flags & WL_OUTPUT_MODE_PREFERRED ?
3969 ", preferred" : "",
3970 m->flags & WL_OUTPUT_MODE_CURRENT ?
3971 ", current" : "",
Armin Krezović08368132016-09-30 14:11:05 +02003972 output->connector->count_modes == 0 ?
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003973 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04003974
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03003975 output->state_invalid = true;
3976
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003977 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01003978
Daniel Stone02cf4662017-03-03 16:19:39 +00003979err:
David Herrmann0f0d54e2011-12-08 17:05:45 +01003980 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003981}
3982
Jesse Barnes58ef3792012-02-23 09:45:49 -05003983static void
Armin Krezović08368132016-09-30 14:11:05 +02003984drm_output_deinit(struct weston_output *base)
3985{
3986 struct drm_output *output = to_drm_output(base);
3987 struct drm_backend *b = to_drm_backend(base->compositor);
3988
Daniel Stone3e661f72016-11-04 17:24:06 +00003989 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02003990 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00003991 else
3992 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02003993
Daniel Stone2ba17f42015-05-19 20:02:41 +01003994 /* Since our planes are no longer in use anywhere, remove their base
3995 * weston_plane's link from the plane stacking list, unless we're
3996 * shutting down, in which case the plane has already been
3997 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00003998 if (!b->shutting_down) {
3999 wl_list_remove(&output->scanout_plane->base.link);
4000 wl_list_init(&output->scanout_plane->base.link);
4001
4002 if (output->cursor_plane) {
4003 wl_list_remove(&output->cursor_plane->base.link);
4004 wl_list_init(&output->cursor_plane->base.link);
4005 /* Turn off hardware cursor */
4006 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
4007 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01004008 }
Armin Krezović08368132016-09-30 14:11:05 +02004009}
4010
4011static void
4012drm_output_destroy(struct weston_output *base)
4013{
4014 struct drm_output *output = to_drm_output(base);
4015 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović445b41b2016-10-09 23:48:16 +02004016 struct drm_mode *drm_mode, *next;
Armin Krezović08368132016-09-30 14:11:05 +02004017 drmModeCrtcPtr origcrtc = output->original_crtc;
4018
Daniel Stone7b2ddac2016-11-11 19:11:49 +00004019 if (output->page_flip_pending || output->vblank_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02004020 output->destroy_pending = 1;
4021 weston_log("destroy output while page flip pending\n");
4022 return;
4023 }
4024
4025 if (output->base.enabled)
4026 drm_output_deinit(&output->base);
4027
Daniel Stone2ba17f42015-05-19 20:02:41 +01004028 if (!b->universal_planes && !b->shutting_down) {
4029 /* With universal planes, the 'special' planes are allocated at
4030 * startup, freed at shutdown, and live on the plane list in
4031 * between. We want the planes to continue to exist and be freed
4032 * up for other outputs.
4033 *
4034 * Without universal planes, our special planes are
4035 * pseudo-planes allocated at output creation, freed at output
4036 * destruction, and not usable by other outputs.
4037 *
4038 * On the other hand, if the compositor is already shutting down,
4039 * the plane has already been destroyed.
4040 */
4041 if (output->cursor_plane)
4042 drm_plane_destroy(output->cursor_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +00004043 drm_plane_destroy(output->scanout_plane);
Daniel Stone2ba17f42015-05-19 20:02:41 +01004044 }
4045
Armin Krezović445b41b2016-10-09 23:48:16 +02004046 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
4047 base.link) {
4048 wl_list_remove(&drm_mode->base.link);
4049 free(drm_mode);
4050 }
4051
Armin Krezović08368132016-09-30 14:11:05 +02004052 if (origcrtc) {
4053 /* Restore original CRTC state */
4054 drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
4055 origcrtc->x, origcrtc->y,
4056 &output->connector_id, 1, &origcrtc->mode);
4057 drmModeFreeCrtc(origcrtc);
4058 }
4059
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00004060 if (output->pageflip_timer)
4061 wl_event_source_remove(output->pageflip_timer);
4062
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03004063 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02004064
Daniel Stone02cf4662017-03-03 16:19:39 +00004065 drm_property_info_free(output->props_conn, WDRM_CONNECTOR__COUNT);
4066
Armin Krezović08368132016-09-30 14:11:05 +02004067 drmModeFreeConnector(output->connector);
4068
4069 if (output->backlight)
4070 backlight_destroy(output->backlight);
4071
Daniel Stone7b2ddac2016-11-11 19:11:49 +00004072 assert(!output->state_last);
4073 drm_output_state_free(output->state_cur);
4074
Armin Krezović08368132016-09-30 14:11:05 +02004075 free(output);
4076}
4077
4078static int
4079drm_output_disable(struct weston_output *base)
4080{
4081 struct drm_output *output = to_drm_output(base);
4082 struct drm_backend *b = to_drm_backend(base->compositor);
4083
Daniel Stone7b2ddac2016-11-11 19:11:49 +00004084 if (output->page_flip_pending || output->vblank_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02004085 output->disable_pending = 1;
4086 return -1;
4087 }
4088
4089 if (output->base.enabled)
4090 drm_output_deinit(&output->base);
4091
4092 output->disable_pending = 0;
4093
4094 weston_log("Disabling output %s\n", output->base.name);
4095 drmModeSetCrtc(b->drm.fd, output->crtc_id,
4096 0, 0, 0, 0, 0, NULL);
4097
Daniel Stone7b2ddac2016-11-11 19:11:49 +00004098 drm_output_state_free(output->state_cur);
4099 output->state_cur = drm_output_state_alloc(output, NULL);
4100
Armin Krezović08368132016-09-30 14:11:05 +02004101 return 0;
4102}
4103
4104/**
4105 * Create a Weston output structure
4106 *
4107 * Given a DRM connector, create a matching drm_output structure and add it
4108 * to Weston's output list. It also takes ownership of the connector, which
4109 * is released when output is destroyed.
4110 *
4111 * @param b Weston backend structure
4112 * @param resources DRM resources for this device
4113 * @param connector DRM connector to use for this new output
4114 * @param drm_device udev device pointer
4115 * @returns 0 on success, or -1 on failure
4116 */
4117static int
4118create_output_for_connector(struct drm_backend *b,
4119 drmModeRes *resources,
4120 drmModeConnector *connector,
4121 struct udev_device *drm_device)
4122{
4123 struct drm_output *output;
Daniel Stone02cf4662017-03-03 16:19:39 +00004124 drmModeObjectPropertiesPtr props;
Armin Krezović445b41b2016-10-09 23:48:16 +02004125 struct drm_mode *drm_mode;
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03004126 char *name;
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004127 const char *make = "unknown";
4128 const char *model = "unknown";
4129 const char *serial_number = "unknown";
Armin Krezović08368132016-09-30 14:11:05 +02004130 int i;
4131
Daniel Stone02cf4662017-03-03 16:19:39 +00004132 static const struct drm_property_info connector_props[] = {
4133 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
4134 [WDRM_CONNECTOR_DPMS] = { .name = "DPMS" },
4135 };
4136
Armin Krezović08368132016-09-30 14:11:05 +02004137 i = find_crtc_for_connector(b, resources, connector);
4138 if (i < 0) {
4139 weston_log("No usable crtc/encoder pair for connector.\n");
Armin Krezović445b41b2016-10-09 23:48:16 +02004140 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02004141 }
4142
4143 output = zalloc(sizeof *output);
4144 if (output == NULL)
Armin Krezović445b41b2016-10-09 23:48:16 +02004145 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02004146
4147 output->connector = connector;
4148 output->crtc_id = resources->crtcs[i];
4149 output->pipe = i;
4150 output->connector_id = connector->connector_id;
4151
4152 output->backlight = backlight_init(drm_device,
4153 connector->connector_type);
4154
Armin Krezović445b41b2016-10-09 23:48:16 +02004155 output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
4156
Pekka Paalanen26ac2e12017-04-03 13:18:13 +03004157 name = make_connector_name(connector);
4158 weston_output_init(&output->base, b->compositor, name);
4159 free(name);
4160
Armin Krezović08368132016-09-30 14:11:05 +02004161 output->base.enable = drm_output_enable;
4162 output->base.destroy = drm_output_destroy;
4163 output->base.disable = drm_output_disable;
Armin Krezović08368132016-09-30 14:11:05 +02004164
4165 output->destroy_pending = 0;
4166 output->disable_pending = 0;
Armin Krezović08368132016-09-30 14:11:05 +02004167
Daniel Stone02cf4662017-03-03 16:19:39 +00004168 props = drmModeObjectGetProperties(b->drm.fd, connector->connector_id,
4169 DRM_MODE_OBJECT_CONNECTOR);
4170 if (!props) {
4171 weston_log("failed to get connector properties\n");
4172 goto err;
4173 }
4174 drm_property_info_populate(b, connector_props, output->props_conn,
4175 WDRM_CONNECTOR__COUNT, props);
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004176 find_and_parse_output_edid(b, output, props,
4177 &make, &model, &serial_number);
4178 output->base.make = (char *)make;
4179 output->base.model = (char *)model;
4180 output->base.serial_number = (char *)serial_number;
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03004181 output->base.subpixel = drm_subpixel_to_wayland(output->connector->subpixel);
4182
4183 if (output->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
4184 output->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
4185 output->base.connection_internal = true;
4186
Daniel Stone7b2ddac2016-11-11 19:11:49 +00004187 output->state_cur = drm_output_state_alloc(output, NULL);
4188
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03004189 output->base.mm_width = output->connector->mmWidth;
4190 output->base.mm_height = output->connector->mmHeight;
4191
Daniel Stone02cf4662017-03-03 16:19:39 +00004192 drmModeFreeObjectProperties(props);
4193
Armin Krezović445b41b2016-10-09 23:48:16 +02004194 for (i = 0; i < output->connector->count_modes; i++) {
4195 drm_mode = drm_output_add_mode(output, &output->connector->modes[i]);
4196 if (!drm_mode) {
4197 drm_output_destroy(&output->base);
4198 return -1;
4199 }
4200 }
4201
Daniel Stonee2e80132018-01-16 15:37:33 +00004202 output->scanout_plane =
4203 drm_output_find_special_plane(b, output,
4204 WDRM_PLANE_TYPE_PRIMARY);
4205 if (!output->scanout_plane) {
4206 weston_log("Failed to find primary plane for output %s\n",
4207 output->base.name);
4208 drm_output_destroy(&output->base);
4209 return -1;
4210 }
4211
Daniel Stone2ba17f42015-05-19 20:02:41 +01004212 /* Failing to find a cursor plane is not fatal, as we'll fall back
4213 * to software cursor. */
4214 output->cursor_plane =
4215 drm_output_find_special_plane(b, output,
4216 WDRM_PLANE_TYPE_CURSOR);
4217
Armin Krezović08368132016-09-30 14:11:05 +02004218 weston_compositor_add_pending_output(&output->base, b->compositor);
4219
4220 return 0;
Armin Krezović445b41b2016-10-09 23:48:16 +02004221
4222err:
4223 drmModeFreeConnector(connector);
4224
4225 return -1;
Armin Krezović08368132016-09-30 14:11:05 +02004226}
4227
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004228static int
Ucan, Emre (ADITG/SW1)9a200d72017-02-02 14:06:56 +00004229create_outputs(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004230{
4231 drmModeConnector *connector;
4232 drmModeRes *resources;
4233 int i;
4234
Giulio Camuffo954f1832014-10-11 18:27:30 +03004235 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004236 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02004237 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004238 return -1;
4239 }
4240
Giulio Camuffo954f1832014-10-11 18:27:30 +03004241 b->min_width = resources->min_width;
4242 b->max_width = resources->max_width;
4243 b->min_height = resources->min_height;
4244 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05004245
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004246 for (i = 0; i < resources->count_connectors; i++) {
Daniel Stone02cf4662017-03-03 16:19:39 +00004247 int ret;
4248
Giulio Camuffo954f1832014-10-11 18:27:30 +03004249 connector = drmModeGetConnector(b->drm.fd,
Benjamin Franzke117483d2011-08-30 11:38:26 +02004250 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004251 if (connector == NULL)
4252 continue;
4253
Ucan, Emre (ADITG/SW1)38ea2d22017-03-08 15:43:18 +00004254 if (connector->connection == DRM_MODE_CONNECTED) {
Daniel Stone02cf4662017-03-03 16:19:39 +00004255 ret = create_output_for_connector(b, resources,
4256 connector, drm_device);
4257 if (ret < 0)
4258 weston_log("failed to create new connector\n");
Armin Krezović08368132016-09-30 14:11:05 +02004259 } else {
4260 drmModeFreeConnector(connector);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02004261 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004262 }
4263
Armin Krezović08368132016-09-30 14:11:05 +02004264 if (wl_list_empty(&b->compositor->output_list) &&
4265 wl_list_empty(&b->compositor->pending_output_list))
Martin Minarik6d118362012-06-07 18:01:59 +02004266 weston_log("No currently active connector found.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004267
4268 drmModeFreeResources(resources);
4269
4270 return 0;
4271}
4272
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004273static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03004274update_outputs(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004275{
4276 drmModeConnector *connector;
4277 drmModeRes *resources;
4278 struct drm_output *output, *next;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00004279 uint32_t *connected;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004280 int i;
4281
Giulio Camuffo954f1832014-10-11 18:27:30 +03004282 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004283 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02004284 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004285 return;
4286 }
4287
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00004288 connected = calloc(resources->count_connectors, sizeof(uint32_t));
4289 if (!connected) {
4290 drmModeFreeResources(resources);
4291 return;
4292 }
4293
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004294 /* collect new connects */
4295 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00004296 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02004297
Giulio Camuffo954f1832014-10-11 18:27:30 +03004298 connector = drmModeGetConnector(b->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01004299 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004300 continue;
4301
David Herrmann7551cff2011-12-08 17:05:43 +01004302 if (connector->connection != DRM_MODE_CONNECTED) {
4303 drmModeFreeConnector(connector);
4304 continue;
4305 }
4306
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00004307 connected[i] = connector_id;
Benjamin Franzke117483d2011-08-30 11:38:26 +02004308
Daniel Stonec0ec7592017-02-09 13:58:35 +00004309 if (drm_output_find_by_connector(b, connector_id)) {
Armin Krezović08368132016-09-30 14:11:05 +02004310 drmModeFreeConnector(connector);
Daniel Stonec0ec7592017-02-09 13:58:35 +00004311 continue;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004312 }
Daniel Stonec0ec7592017-02-09 13:58:35 +00004313
4314 create_output_for_connector(b, resources,
4315 connector, drm_device);
4316 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004317 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004318
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00004319 wl_list_for_each_safe(output, next, &b->compositor->output_list,
4320 base.link) {
4321 bool disconnected = true;
4322
4323 for (i = 0; i < resources->count_connectors; i++) {
4324 if (connected[i] == output->connector_id) {
4325 disconnected = false;
4326 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004327 }
4328 }
Armin Krezović08368132016-09-30 14:11:05 +02004329
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00004330 if (!disconnected)
4331 continue;
4332
4333 weston_log("connector %d disconnected\n", output->connector_id);
4334 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004335 }
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00004336
4337 wl_list_for_each_safe(output, next, &b->compositor->pending_output_list,
4338 base.link) {
4339 bool disconnected = true;
4340
4341 for (i = 0; i < resources->count_connectors; i++) {
4342 if (connected[i] == output->connector_id) {
4343 disconnected = false;
4344 break;
4345 }
4346 }
4347
4348 if (!disconnected)
4349 continue;
4350
4351 weston_log("connector %d disconnected\n", output->connector_id);
4352 drm_output_destroy(&output->base);
4353 }
4354
4355 free(connected);
4356 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004357}
4358
4359static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004360udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004361{
David Herrmannd7488c22012-03-11 20:05:21 +01004362 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01004363 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01004364
4365 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03004366 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01004367 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02004368
David Herrmann6ac52db2012-03-11 20:05:22 +01004369 val = udev_device_get_property_value(device, "HOTPLUG");
4370 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004371 return 0;
4372
David Herrmann6ac52db2012-03-11 20:05:22 +01004373 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004374}
4375
Kristian Høgsbergb1868472011-04-22 12:27:57 -04004376static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004377udev_drm_event(int fd, uint32_t mask, void *data)
4378{
Giulio Camuffo954f1832014-10-11 18:27:30 +03004379 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004380 struct udev_device *event;
4381
Giulio Camuffo954f1832014-10-11 18:27:30 +03004382 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02004383
Giulio Camuffo954f1832014-10-11 18:27:30 +03004384 if (udev_event_is_hotplug(b, event))
4385 update_outputs(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004386
4387 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04004388
4389 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004390}
4391
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05004392static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04004393drm_restore(struct weston_compositor *ec)
4394{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07004395 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04004396}
4397
4398static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004399drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05004400{
Armin Krezović545dba62016-08-05 15:54:18 +02004401 struct drm_backend *b = to_drm_backend(ec);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05004402
Giulio Camuffo954f1832014-10-11 18:27:30 +03004403 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02004404
Giulio Camuffo954f1832014-10-11 18:27:30 +03004405 wl_event_source_remove(b->udev_drm_source);
4406 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02004407
Daniel Stoneb57c6a02017-10-05 16:27:21 +01004408 b->shutting_down = true;
4409
Giulio Camuffo954f1832014-10-11 18:27:30 +03004410 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04004411
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03004412 weston_compositor_shutdown(ec);
4413
Giulio Camuffo954f1832014-10-11 18:27:30 +03004414 if (b->gbm)
4415 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004416
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03004417 udev_unref(b->udev);
4418
Giulio Camuffo954f1832014-10-11 18:27:30 +03004419 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05004420
Giulio Camuffo954f1832014-10-11 18:27:30 +03004421 close(b->drm.fd);
Giulio Camuffo954f1832014-10-11 18:27:30 +03004422 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05004423}
4424
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04004425static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07004426session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04004427{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07004428 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02004429 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01004430 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04004431 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04004432
Giulio Camuffo954f1832014-10-11 18:27:30 +03004433 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07004434 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00004435 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05004436 weston_compositor_damage_all(compositor);
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03004437
4438 wl_list_for_each(output, &compositor->output_list, base.link)
4439 output->state_invalid = true;
4440
Giulio Camuffo954f1832014-10-11 18:27:30 +03004441 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07004442 } else {
4443 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03004444 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04004445
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004446 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04004447
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05004448 /* If we have a repaint scheduled (either from a
4449 * pending pageflip or the idle handler), make sure we
4450 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01004451 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05004452 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05004453 * back, we schedule a repaint, which will process
4454 * pending frame callbacks. */
4455
Giulio Camuffo954f1832014-10-11 18:27:30 +03004456 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00004457 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01004458 if (output->cursor_plane)
4459 drmModeSetCursor(b->drm.fd, output->crtc_id,
4460 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05004461 }
4462
Giulio Camuffo954f1832014-10-11 18:27:30 +03004463 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04004464 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05004465
Daniel Stone085d2b92015-05-21 00:00:57 +01004466 wl_list_for_each(plane, &b->plane_list, link) {
4467 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
4468 continue;
4469
Giulio Camuffo954f1832014-10-11 18:27:30 +03004470 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01004471 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04004472 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05004473 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01004474 }
4475 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04004476}
4477
Daniel Stoneefa504f2016-12-19 16:48:20 +00004478/**
4479 * Determines whether or not a device is capable of modesetting. If successful,
4480 * sets b->drm.fd and b->drm.filename to the opened device.
4481 */
4482static bool
4483drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
4484{
4485 const char *filename = udev_device_get_devnode(device);
4486 const char *sysnum = udev_device_get_sysnum(device);
4487 drmModeRes *res;
4488 int id, fd;
4489
4490 if (!filename)
4491 return false;
4492
4493 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
4494 if (fd < 0)
4495 return false;
4496
4497 res = drmModeGetResources(fd);
4498 if (!res)
4499 goto out_fd;
4500
4501 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
4502 res->count_encoders <= 0)
4503 goto out_res;
4504
4505 if (sysnum)
4506 id = atoi(sysnum);
4507 if (!sysnum || id < 0) {
4508 weston_log("couldn't get sysnum for device %s\n", filename);
4509 goto out_res;
4510 }
4511
4512 /* We can be called successfully on multiple devices; if we have,
4513 * clean up old entries. */
4514 if (b->drm.fd >= 0)
4515 weston_launcher_close(b->compositor->launcher, b->drm.fd);
4516 free(b->drm.filename);
4517
4518 b->drm.fd = fd;
4519 b->drm.id = id;
4520 b->drm.filename = strdup(filename);
4521
Sergi Granellceb59812017-03-28 12:44:04 +02004522 drmModeFreeResources(res);
4523
Daniel Stoneefa504f2016-12-19 16:48:20 +00004524 return true;
4525
4526out_res:
4527 drmModeFreeResources(res);
4528out_fd:
4529 weston_launcher_close(b->compositor->launcher, fd);
4530 return false;
4531}
4532
David Herrmann0af066f2012-10-29 19:21:16 +01004533/*
4534 * Find primary GPU
4535 * Some systems may have multiple DRM devices attached to a single seat. This
4536 * function loops over all devices and tries to find a PCI device with the
4537 * boot_vga sysfs attribute set to 1.
4538 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00004539 * Devices are also vetted to make sure they are are capable of modesetting,
4540 * rather than pure render nodes (GPU with no display), or pure
4541 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01004542 */
4543static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03004544find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01004545{
4546 struct udev_enumerate *e;
4547 struct udev_list_entry *entry;
4548 const char *path, *device_seat, *id;
4549 struct udev_device *device, *drm_device, *pci;
4550
Giulio Camuffo954f1832014-10-11 18:27:30 +03004551 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01004552 udev_enumerate_add_match_subsystem(e, "drm");
4553 udev_enumerate_add_match_sysname(e, "card[0-9]*");
4554
4555 udev_enumerate_scan_devices(e);
4556 drm_device = NULL;
4557 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00004558 bool is_boot_vga = false;
4559
David Herrmann0af066f2012-10-29 19:21:16 +01004560 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03004561 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01004562 if (!device)
4563 continue;
4564 device_seat = udev_device_get_property_value(device, "ID_SEAT");
4565 if (!device_seat)
4566 device_seat = default_seat;
4567 if (strcmp(device_seat, seat)) {
4568 udev_device_unref(device);
4569 continue;
4570 }
4571
4572 pci = udev_device_get_parent_with_subsystem_devtype(device,
4573 "pci", NULL);
4574 if (pci) {
4575 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00004576 if (id && !strcmp(id, "1"))
4577 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01004578 }
4579
Daniel Stoneefa504f2016-12-19 16:48:20 +00004580 /* If we already have a modesetting-capable device, and this
4581 * device isn't our boot-VGA device, we aren't going to use
4582 * it. */
4583 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01004584 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00004585 continue;
4586 }
4587
4588 /* Make sure this device is actually capable of modesetting;
4589 * if this call succeeds, b->drm.{fd,filename} will be set,
4590 * and any old values freed. */
4591 if (!drm_device_is_kms(b, device)) {
4592 udev_device_unref(device);
4593 continue;
4594 }
4595
4596 /* There can only be one boot_vga device, and we try to use it
4597 * at all costs. */
4598 if (is_boot_vga) {
4599 if (drm_device)
4600 udev_device_unref(drm_device);
4601 drm_device = device;
4602 break;
4603 }
4604
4605 /* Per the (!is_boot_vga && drm_device) test above, we only
4606 * trump existing saved devices with boot-VGA devices, so if
4607 * we end up here, this must be the first device we've seen. */
4608 assert(!drm_device);
4609 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01004610 }
4611
Daniel Stoneefa504f2016-12-19 16:48:20 +00004612 /* If we're returning a device to use, we must have an open FD for
4613 * it. */
4614 assert(!!drm_device == (b->drm.fd >= 0));
4615
David Herrmann0af066f2012-10-29 19:21:16 +01004616 udev_enumerate_unref(e);
4617 return drm_device;
4618}
4619
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03004620static struct udev_device *
4621open_specific_drm_device(struct drm_backend *b, const char *name)
4622{
4623 struct udev_device *device;
4624
4625 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
4626 if (!device) {
4627 weston_log("ERROR: could not open DRM device '%s'\n", name);
4628 return NULL;
4629 }
4630
4631 if (!drm_device_is_kms(b, device)) {
4632 udev_device_unref(device);
4633 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
4634 return NULL;
4635 }
4636
4637 /* If we're returning a device to use, we must have an open FD for
4638 * it. */
4639 assert(b->drm.fd >= 0);
4640
4641 return device;
4642}
4643
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02004644static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02004645planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
4646 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02004647{
Giulio Camuffo954f1832014-10-11 18:27:30 +03004648 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02004649
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02004650 switch (key) {
4651 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03004652 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02004653 break;
4654 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03004655 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02004656 break;
4657 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03004658 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02004659 break;
4660 default:
4661 break;
4662 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02004663}
4664
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07004665#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004666static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03004667recorder_destroy(struct drm_output *output)
4668{
4669 vaapi_recorder_destroy(output->recorder);
4670 output->recorder = NULL;
4671
4672 output->base.disable_planes--;
4673
4674 wl_list_remove(&output->recorder_frame_listener.link);
4675 weston_log("[libva recorder] done\n");
4676}
4677
4678static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004679recorder_frame_notify(struct wl_listener *listener, void *data)
4680{
4681 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03004682 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004683 int fd, ret;
4684
4685 output = container_of(listener, struct drm_output,
4686 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02004687 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004688
4689 if (!output->recorder)
4690 return;
4691
Daniel Stonee2e80132018-01-16 15:37:33 +00004692 ret = drmPrimeHandleToFD(b->drm.fd,
4693 output->scanout_plane->state_cur->fb->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004694 DRM_CLOEXEC, &fd);
4695 if (ret) {
4696 weston_log("[libva recorder] "
4697 "failed to create prime fd for front buffer\n");
4698 return;
4699 }
4700
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03004701 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stonee2e80132018-01-16 15:37:33 +00004702 output->scanout_plane->state_cur->fb->stride);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03004703 if (ret < 0) {
4704 weston_log("[libva recorder] aborted: %m\n");
4705 recorder_destroy(output);
4706 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004707}
4708
4709static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03004710create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004711 const char *filename)
4712{
4713 int fd;
4714 drm_magic_t magic;
4715
Giulio Camuffo954f1832014-10-11 18:27:30 +03004716 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004717 if (fd < 0)
4718 return NULL;
4719
4720 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03004721 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004722
4723 return vaapi_recorder_create(fd, width, height, filename);
4724}
4725
4726static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02004727recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
4728 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004729{
Giulio Camuffo954f1832014-10-11 18:27:30 +03004730 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004731 struct drm_output *output;
4732 int width, height;
4733
Giulio Camuffo954f1832014-10-11 18:27:30 +03004734 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004735 struct drm_output, base.link);
4736
4737 if (!output->recorder) {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004738 if (output->gbm_format != GBM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03004739 weston_log("failed to start vaapi recorder: "
4740 "output format not supported\n");
4741 return;
4742 }
4743
Hardeningff39efa2013-09-18 23:56:35 +02004744 width = output->base.current_mode->width;
4745 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004746
4747 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03004748 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004749 if (!output->recorder) {
4750 weston_log("failed to create vaapi recorder\n");
4751 return;
4752 }
4753
4754 output->base.disable_planes++;
4755
4756 output->recorder_frame_listener.notify = recorder_frame_notify;
4757 wl_signal_add(&output->base.frame_signal,
4758 &output->recorder_frame_listener);
4759
4760 weston_output_schedule_repaint(&output->base);
4761
4762 weston_log("[libva recorder] initialized\n");
4763 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03004764 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004765 }
4766}
4767#else
4768static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02004769recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
4770 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03004771{
4772 weston_log("Compiled without libva support\n");
4773}
4774#endif
4775
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004776static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03004777switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004778{
4779 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03004780 bool dmabuf_support_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004781
Giulio Camuffo954f1832014-10-11 18:27:30 +03004782 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004783 return;
4784
Pekka Paalanene4d231e2014-06-12 15:12:48 +03004785 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
4786
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004787 weston_log("Switching to GL renderer\n");
4788
Giulio Camuffo954f1832014-10-11 18:27:30 +03004789 b->gbm = create_gbm_device(b->drm.fd);
4790 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004791 weston_log("Failed to create gbm device. "
4792 "Aborting renderer switch\n");
4793 return;
4794 }
4795
Giulio Camuffo954f1832014-10-11 18:27:30 +03004796 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004797 pixman_renderer_output_destroy(&output->base);
4798
Giulio Camuffo954f1832014-10-11 18:27:30 +03004799 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004800
Giulio Camuffo954f1832014-10-11 18:27:30 +03004801 if (drm_backend_create_gl_renderer(b) < 0) {
4802 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004803 weston_log("Failed to create GL renderer. Quitting.\n");
4804 /* FIXME: we need a function to shutdown cleanly */
4805 assert(0);
4806 }
4807
Giulio Camuffo954f1832014-10-11 18:27:30 +03004808 wl_list_for_each(output, &b->compositor->output_list, base.link)
4809 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004810
Giulio Camuffo954f1832014-10-11 18:27:30 +03004811 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03004812
4813 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
4814 if (linux_dmabuf_setup(b->compositor) < 0)
4815 weston_log("Error: initializing dmabuf "
4816 "support failed.\n");
4817 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004818}
4819
4820static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02004821renderer_switch_binding(struct weston_keyboard *keyboard,
4822 const struct timespec *time, uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004823{
Derek Foreman8ae2db52015-07-15 13:00:36 -05004824 struct drm_backend *b =
Armin Krezović545dba62016-08-05 15:54:18 +02004825 to_drm_backend(keyboard->seat->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004826
Giulio Camuffo954f1832014-10-11 18:27:30 +03004827 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004828}
4829
Armin Krezović08368132016-09-30 14:11:05 +02004830static const struct weston_drm_output_api api = {
4831 drm_output_set_mode,
4832 drm_output_set_gbm_format,
4833 drm_output_set_seat,
4834};
4835
Giulio Camuffo954f1832014-10-11 18:27:30 +03004836static struct drm_backend *
4837drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004838 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004839{
Giulio Camuffo954f1832014-10-11 18:27:30 +03004840 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01004841 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004842 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004843 const char *seat_id = default_seat;
Armin Krezović08368132016-09-30 14:11:05 +02004844 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004845
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04004846 weston_log("initializing drm backend\n");
4847
Giulio Camuffo954f1832014-10-11 18:27:30 +03004848 b = zalloc(sizeof *b);
4849 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004850 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01004851
Daniel Stoneefa504f2016-12-19 16:48:20 +00004852 b->drm.fd = -1;
4853
Pekka Paalanen68583832015-05-19 09:53:16 +03004854 /*
4855 * KMS support for hardware planes cannot properly synchronize
4856 * without nuclear page flip. Without nuclear/atomic, hw plane
4857 * and cursor plane updates would either tear or cause extra
4858 * waits for vblanks which means dropping the compositor framerate
Pekka Paalanen3f32a132015-09-07 15:38:43 +03004859 * to a fraction. For cursors, it's not so bad, so they are
4860 * enabled.
Pekka Paalanen68583832015-05-19 09:53:16 +03004861 *
4862 * These can be enabled again when nuclear/atomic support lands.
4863 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03004864 b->sprites_are_broken = 1;
Giulio Camuffo954f1832014-10-11 18:27:30 +03004865 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004866 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00004867 b->pageflip_timeout = config->pageflip_timeout;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07004868
Pekka Paalanen7da9a382017-08-30 11:29:49 +03004869 compositor->backend = &b->base;
4870
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004871 if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
4872 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07004873
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004874 if (config->seat_id)
4875 seat_id = config->seat_id;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004876
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01004877 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004878 compositor->launcher = weston_launcher_connect(compositor, config->tty,
4879 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03004880 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02004881 weston_log("fatal: drm backend should be run using "
4882 "weston-launch binary, or your system should "
4883 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01004884 goto err_compositor;
4885 }
4886
Giulio Camuffo954f1832014-10-11 18:27:30 +03004887 b->udev = udev_new();
4888 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02004889 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07004890 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004891 }
4892
Giulio Camuffo954f1832014-10-11 18:27:30 +03004893 b->session_listener.notify = session_notify;
4894 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05004895
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03004896 if (config->specific_device)
4897 drm_device = open_specific_drm_device(b, config->specific_device);
4898 else
4899 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04004900 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02004901 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07004902 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004903 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004904
Daniel Stoneefa504f2016-12-19 16:48:20 +00004905 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02004906 weston_log("failed to initialize kms\n");
4907 goto err_udev_dev;
4908 }
4909
Giulio Camuffo954f1832014-10-11 18:27:30 +03004910 if (b->use_pixman) {
4911 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004912 weston_log("failed to initialize pixman renderer\n");
4913 goto err_udev_dev;
4914 }
4915 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03004916 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004917 weston_log("failed to initialize egl\n");
4918 goto err_udev_dev;
4919 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004920 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05004921
Giulio Camuffo954f1832014-10-11 18:27:30 +03004922 b->base.destroy = drm_destroy;
4923 b->base.restore = drm_restore;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00004924 b->base.repaint_begin = drm_repaint_begin;
4925 b->base.repaint_flush = drm_repaint_flush;
4926 b->base.repaint_cancel = drm_repaint_cancel;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02004927
Bob Ham91880f12016-01-12 10:21:47 +00004928 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04004929
Daniel Stone085d2b92015-05-21 00:00:57 +01004930 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03004931 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05004932
Giulio Camuffo954f1832014-10-11 18:27:30 +03004933 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03004934 compositor, b->udev, seat_id,
4935 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03004936 weston_log("failed to create input devices\n");
4937 goto err_sprite;
4938 }
4939
Ucan, Emre (ADITG/SW1)9a200d72017-02-02 14:06:56 +00004940 if (create_outputs(b, drm_device) < 0) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00004941 weston_log("failed to create output for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03004942 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004943 }
4944
Jason Ekstrand9fc71512014-04-02 19:53:46 -05004945 /* A this point we have some idea of whether or not we have a working
4946 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03004947 if (!b->cursors_are_broken)
4948 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05004949
Giulio Camuffo954f1832014-10-11 18:27:30 +03004950 loop = wl_display_get_event_loop(compositor->wl_display);
4951 b->drm_source =
4952 wl_event_loop_add_fd(loop, b->drm.fd,
4953 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04004954
Giulio Camuffo954f1832014-10-11 18:27:30 +03004955 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
4956 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05004957 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01004958 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004959 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03004960 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004961 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03004962 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02004963 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03004964 udev_monitor_get_fd(b->udev_monitor),
4965 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004966
Giulio Camuffo954f1832014-10-11 18:27:30 +03004967 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02004968 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01004969 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01004970 }
4971
Daniel Stonea96b93c2012-06-22 14:04:37 +01004972 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01004973
Giulio Camuffo954f1832014-10-11 18:27:30 +03004974 weston_compositor_add_debug_binding(compositor, KEY_O,
4975 planes_binding, b);
4976 weston_compositor_add_debug_binding(compositor, KEY_C,
4977 planes_binding, b);
4978 weston_compositor_add_debug_binding(compositor, KEY_V,
4979 planes_binding, b);
4980 weston_compositor_add_debug_binding(compositor, KEY_Q,
4981 recorder_binding, b);
4982 weston_compositor_add_debug_binding(compositor, KEY_W,
4983 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02004984
Pekka Paalanene4d231e2014-06-12 15:12:48 +03004985 if (compositor->renderer->import_dmabuf) {
4986 if (linux_dmabuf_setup(compositor) < 0)
4987 weston_log("Error: initializing dmabuf "
4988 "support failed.\n");
4989 }
4990
Armin Krezović08368132016-09-30 14:11:05 +02004991 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
4992 &api, sizeof(api));
4993
4994 if (ret < 0) {
4995 weston_log("Failed to register output API.\n");
4996 goto err_udev_monitor;
4997 }
4998
Giulio Camuffo954f1832014-10-11 18:27:30 +03004999 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01005000
5001err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005002 wl_event_source_remove(b->udev_drm_source);
5003 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01005004err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005005 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03005006err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005007 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04005008err_sprite:
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01005009 if (b->gbm)
5010 gbm_device_destroy(b->gbm);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005011 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01005012err_udev_dev:
5013 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07005014err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005015 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01005016err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005017 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01005018err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005019 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005020 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01005021 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005022}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005023
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005024static void
5025config_init_to_defaults(struct weston_drm_backend_config *config)
5026{
5027}
5028
Giulio Camuffo954f1832014-10-11 18:27:30 +03005029WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01005030weston_backend_init(struct weston_compositor *compositor,
5031 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005032{
Giulio Camuffo954f1832014-10-11 18:27:30 +03005033 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005034 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005035
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005036 if (config_base == NULL ||
5037 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
5038 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
5039 weston_log("drm backend config structure is invalid\n");
5040 return -1;
5041 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02005042
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005043 config_init_to_defaults(&config);
5044 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07005045
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005046 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005047 if (b == NULL)
5048 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005049
Giulio Camuffo954f1832014-10-11 18:27:30 +03005050 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04005051}