blob: b879d161b4969d28bc25011733c44ee499950117 [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
Pekka Paalanen925788f2018-04-19 14:20:01 +03004 * Copyright © 2017, 2018 Collabora, Ltd.
5 * Copyright © 2017, 2018 General Electric Company
Pekka Paalanen62a94362018-09-26 14:33:36 +03006 * Copyright (c) 2018 DisplayLink (UK) Ltd.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07008 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040015 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070016 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial
18 * portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040028 */
29
Daniel Stonec228e232013-05-22 18:03:19 +030030#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040031
Jesse Barnes58ef3792012-02-23 09:45:49 -050032#include <errno.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030033#include <stdint.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040034#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010035#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040036#include <string.h>
37#include <fcntl.h>
38#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040039#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070040#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030041#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020042#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030043#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030044#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Benjamin Franzkec649a922011-03-02 11:56:04 +010046#include <xf86drm.h>
47#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050048#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010049
Benjamin Franzke060cf802011-04-30 09:32:11 +020050#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040051#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020052
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020053#include <libweston/libweston.h>
Pekka Paalanen75710272019-03-29 16:39:12 +020054#include <libweston/backend-drm.h>
Marius Vladf4f4c2b2019-04-29 13:27:47 +030055#include <libweston/weston-debug.h>
Jon Cruz35b2eaa2015-06-15 15:37:08 -070056#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020057#include "shared/timespec-util.h"
Pekka Paalanen81475a52019-04-04 17:29:27 +030058#include "renderer-gl/gl-renderer.h"
Vincent Abriouc9506672016-10-05 16:14:07 +020059#include "weston-egl-ext.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020060#include "pixman-renderer.h"
Daniel Stone0b70fa42017-04-04 17:54:23 +010061#include "pixel-formats.h"
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070062#include "libbacklight.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100063#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010064#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030065#include "vaapi-recorder.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020066#include "presentation-time-server-protocol.h"
Pekka Paalanene4d231e2014-06-12 15:12:48 +030067#include "linux-dmabuf.h"
Micah Fedkec8890122017-02-01 15:28:23 -050068#include "linux-dmabuf-unstable-v1-server-protocol.h"
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030069#include "linux-explicit-synchronization.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040070
Ankit Nautiyala21c3932097-03-19 00:24:57 +053071#ifndef DRM_CLIENT_CAP_ASPECT_RATIO
72#define DRM_CLIENT_CAP_ASPECT_RATIO 4
73#endif
74
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030075#ifndef GBM_BO_USE_CURSOR
76#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
77#endif
78
Tomohito Esakib1fb00d2018-01-31 17:50:48 +090079#ifndef GBM_BO_USE_LINEAR
80#define GBM_BO_USE_LINEAR (1 << 4)
81#endif
82
Daniel Stone1cbe1f92018-07-20 10:21:28 +010083/**
84 * A small wrapper to print information into the 'drm-backend' debug scope.
85 *
86 * The following conventions are used to print variables:
87 *
88 * - fixed uint32_t values, including Weston object IDs such as weston_output
89 * IDs, DRM object IDs such as CRTCs or properties, and GBM/DRM formats:
90 * "%lu (0x%lx)" (unsigned long) value, (unsigned long) value
91 *
92 * - fixed uint64_t values, such as DRM property values (including object IDs
93 * when used as a value):
94 * "%llu (0x%llx)" (unsigned long long) value, (unsigned long long) value
95 *
96 * - non-fixed-width signed int:
97 * "%d" value
98 *
99 * - non-fixed-width unsigned int:
100 * "%u (0x%x)" value, value
101 *
102 * - non-fixed-width unsigned long:
103 * "%lu (0x%lx)" value, value
104 *
105 * Either the integer or hexadecimal forms may be omitted if it is known that
106 * one representation is not useful (e.g. width/height in hex are rarely what
107 * you want).
108 *
109 * This is to avoid implicit widening or narrowing when we use fixed-size
110 * types: uint32_t can be resolved by either unsigned int or unsigned long
111 * on a 32-bit system but only unsigned int on a 64-bit system, with uint64_t
112 * being unsigned long long on a 32-bit system and unsigned long on a 64-bit
113 * system. To avoid confusing side effects, we explicitly cast to the widest
114 * possible type and use a matching format specifier.
115 */
116#define drm_debug(b, ...) \
Marius Vlad7e4db952019-04-17 13:47:06 +0300117 weston_log_scope_printf((b)->debug, __VA_ARGS__)
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100118
Pekka Paalanendfc06832017-11-20 14:04:38 +0200119#define MAX_CLONED_CONNECTORS 4
Pekka Paalanenc112f002017-08-28 16:27:20 +0300120
Daniel Stone02cf4662017-03-03 16:19:39 +0000121/**
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530122 * aspect ratio info taken from the drmModeModeInfo flag bits 19-22,
123 * which should be used to fill the aspect ratio field in weston_mode.
124 */
125#define DRM_MODE_FLAG_PIC_AR_BITS_POS 19
126#ifndef DRM_MODE_FLAG_PIC_AR_MASK
127#define DRM_MODE_FLAG_PIC_AR_MASK (0xF << DRM_MODE_FLAG_PIC_AR_BITS_POS)
128#endif
129
130/**
Daniel Stone02cf4662017-03-03 16:19:39 +0000131 * Represents the values of an enum-type KMS property
132 */
133struct drm_property_enum_info {
134 const char *name; /**< name as string (static, not freed) */
135 bool valid; /**< true if value is supported; ignore if false */
136 uint64_t value; /**< raw value */
137};
138
139/**
140 * Holds information on a DRM property, including its ID and the enum
141 * values it holds.
142 *
143 * DRM properties are allocated dynamically, and maintained as DRM objects
144 * within the normal object ID space; they thus do not have a stable ID
145 * to refer to. This includes enum values, which must be referred to by
146 * integer values, but these are not stable.
147 *
148 * drm_property_info allows a cache to be maintained where Weston can use
149 * enum values internally to refer to properties, with the mapping to DRM
150 * ID values being maintained internally.
151 */
152struct drm_property_info {
153 const char *name; /**< name as string (static, not freed) */
154 uint32_t prop_id; /**< KMS property object ID */
155 unsigned int num_enum_values; /**< number of enum values */
156 struct drm_property_enum_info *enum_values; /**< array of enum values */
157};
158
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000159/**
Daniel Stone598ee9d2016-11-16 11:55:20 +0000160 * List of properties attached to DRM planes
161 */
162enum wdrm_plane_property {
163 WDRM_PLANE_TYPE = 0,
164 WDRM_PLANE_SRC_X,
165 WDRM_PLANE_SRC_Y,
166 WDRM_PLANE_SRC_W,
167 WDRM_PLANE_SRC_H,
168 WDRM_PLANE_CRTC_X,
169 WDRM_PLANE_CRTC_Y,
170 WDRM_PLANE_CRTC_W,
171 WDRM_PLANE_CRTC_H,
172 WDRM_PLANE_FB_ID,
173 WDRM_PLANE_CRTC_ID,
Sergi Granellf4456222017-01-12 17:17:32 +0000174 WDRM_PLANE_IN_FORMATS,
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300175 WDRM_PLANE_IN_FENCE_FD,
Deepak Rawat009b3cf2018-07-24 14:05:37 -0700176 WDRM_PLANE_FB_DAMAGE_CLIPS,
Daniel Stone598ee9d2016-11-16 11:55:20 +0000177 WDRM_PLANE__COUNT
178};
179
180/**
181 * Possible values for the WDRM_PLANE_TYPE property.
182 */
183enum wdrm_plane_type {
184 WDRM_PLANE_TYPE_PRIMARY = 0,
185 WDRM_PLANE_TYPE_CURSOR,
186 WDRM_PLANE_TYPE_OVERLAY,
187 WDRM_PLANE_TYPE__COUNT
188};
189
190static struct drm_property_enum_info plane_type_enums[] = {
191 [WDRM_PLANE_TYPE_PRIMARY] = {
192 .name = "Primary",
193 },
194 [WDRM_PLANE_TYPE_OVERLAY] = {
195 .name = "Overlay",
196 },
197 [WDRM_PLANE_TYPE_CURSOR] = {
198 .name = "Cursor",
199 },
200};
201
202static const struct drm_property_info plane_props[] = {
203 [WDRM_PLANE_TYPE] = {
204 .name = "type",
205 .enum_values = plane_type_enums,
206 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
207 },
208 [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
209 [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
210 [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
211 [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
212 [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
213 [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
214 [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
215 [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
216 [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
217 [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
Sergi Granellf4456222017-01-12 17:17:32 +0000218 [WDRM_PLANE_IN_FORMATS] = { .name = "IN_FORMATS" },
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300219 [WDRM_PLANE_IN_FENCE_FD] = { .name = "IN_FENCE_FD" },
Deepak Rawat009b3cf2018-07-24 14:05:37 -0700220 [WDRM_PLANE_FB_DAMAGE_CLIPS] = { .name = "FB_DAMAGE_CLIPS" },
Daniel Stone598ee9d2016-11-16 11:55:20 +0000221};
222
223/**
224 * List of properties attached to a DRM connector
225 */
226enum wdrm_connector_property {
227 WDRM_CONNECTOR_EDID = 0,
228 WDRM_CONNECTOR_DPMS,
229 WDRM_CONNECTOR_CRTC_ID,
Philipp Zabel61dc4ca2018-08-30 17:39:51 +0200230 WDRM_CONNECTOR_NON_DESKTOP,
Daniel Stone598ee9d2016-11-16 11:55:20 +0000231 WDRM_CONNECTOR__COUNT
232};
233
Daniel Stone76255772018-07-06 11:36:49 +0100234enum wdrm_dpms_state {
235 WDRM_DPMS_STATE_OFF = 0,
236 WDRM_DPMS_STATE_ON,
237 WDRM_DPMS_STATE_STANDBY, /* unused */
238 WDRM_DPMS_STATE_SUSPEND, /* unused */
239 WDRM_DPMS_STATE__COUNT
240};
241
242static struct drm_property_enum_info dpms_state_enums[] = {
243 [WDRM_DPMS_STATE_OFF] = {
244 .name = "Off",
245 },
246 [WDRM_DPMS_STATE_ON] = {
247 .name = "On",
248 },
249 [WDRM_DPMS_STATE_STANDBY] = {
250 .name = "Standby",
251 },
252 [WDRM_DPMS_STATE_SUSPEND] = {
253 .name = "Suspend",
254 },
255};
256
Daniel Stone598ee9d2016-11-16 11:55:20 +0000257static const struct drm_property_info connector_props[] = {
258 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
Daniel Stone76255772018-07-06 11:36:49 +0100259 [WDRM_CONNECTOR_DPMS] = {
260 .name = "DPMS",
261 .enum_values = dpms_state_enums,
262 .num_enum_values = WDRM_DPMS_STATE__COUNT,
263 },
Daniel Stone598ee9d2016-11-16 11:55:20 +0000264 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
Philipp Zabel61dc4ca2018-08-30 17:39:51 +0200265 [WDRM_CONNECTOR_NON_DESKTOP] = { .name = "non-desktop", },
Daniel Stone598ee9d2016-11-16 11:55:20 +0000266};
267
268/**
Pekka Paalanencd011a62016-11-15 22:07:49 +0000269 * List of properties attached to DRM CRTCs
270 */
271enum wdrm_crtc_property {
272 WDRM_CRTC_MODE_ID = 0,
273 WDRM_CRTC_ACTIVE,
274 WDRM_CRTC__COUNT
275};
276
Daniel Stone598ee9d2016-11-16 11:55:20 +0000277static const struct drm_property_info crtc_props[] = {
278 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
279 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
280};
281
Pekka Paalanencd011a62016-11-15 22:07:49 +0000282/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000283 * Mode for drm_output_state_duplicate.
284 */
285enum drm_output_state_duplicate_mode {
286 DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
287 DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
288};
289
290/**
291 * Mode for drm_pending_state_apply and co.
292 */
293enum drm_state_apply_mode {
294 DRM_STATE_APPLY_SYNC, /**< state fully processed */
295 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
Daniel Stonebb6c19f2016-12-08 17:27:17 +0000296 DRM_STATE_TEST_ONLY, /**< test if the state can be applied */
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000297};
298
Giulio Camuffo954f1832014-10-11 18:27:30 +0300299struct drm_backend {
300 struct weston_backend base;
301 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400302
303 struct udev *udev;
304 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400305
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100306 struct udev_monitor *udev_monitor;
307 struct wl_event_source *udev_drm_source;
308
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100309 struct {
David Herrmannd7488c22012-03-11 20:05:21 +0100310 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100311 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300312 char *filename;
Robert Beckett8d23ab72019-06-13 16:55:44 +0100313 dev_t devnum;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100314 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200315 struct gbm_device *gbm;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700316 struct wl_listener session_listener;
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +0100317 uint32_t gbm_format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200318
Rob Clark4339add2012-08-09 14:18:28 -0500319 /* we need these parameters in order to not fail drmModeAddFB2()
320 * due to out of bounds dimensions, and then mistakenly set
321 * sprites_are_broken:
322 */
Daniel Stonef214fdc2016-11-14 17:43:57 +0000323 int min_width, max_width;
324 int min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -0500325
Daniel Stone085d2b92015-05-21 00:00:57 +0100326 struct wl_list plane_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500327 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200328 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500329
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000330 void *repaint_data;
331
Daniel Stone6020f472018-02-05 15:46:20 +0000332 bool state_invalid;
333
Pekka Paalaneneacec812017-09-12 13:43:51 +0300334 /* CRTC IDs not used by any enabled output. */
Daniel Stone087ddf02017-02-14 17:51:30 +0000335 struct wl_array unused_crtcs;
336
Rob Clarkab5b1e32012-08-09 13:24:45 -0500337 int cursors_are_broken;
338
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100339 bool universal_planes;
Pekka Paalanencd011a62016-11-15 22:07:49 +0000340 bool atomic_modeset;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100341
Thomas Zimmermannea54c2f2018-09-21 14:44:57 +0200342 bool use_pixman;
Pekka Paalanendee412d2018-04-23 11:44:58 +0200343 bool use_pixman_shadow;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200344
Rob Bradfordd355b802013-05-31 18:09:55 +0100345 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300346
Daniel Stone70d337d2015-06-16 18:42:23 +0100347 int32_t cursor_width;
348 int32_t cursor_height;
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +0000349
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000350 uint32_t pageflip_timeout;
Daniel Stoneb57c6a02017-10-05 16:27:21 +0100351
352 bool shutting_down;
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530353
354 bool aspect_ratio_supported;
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100355
Deepak Rawata864f582018-08-24 13:16:03 -0700356 bool fb_modifiers;
357
Marius Vlad5d5e3352019-04-17 13:05:38 +0300358 struct weston_log_scope *debug;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400359};
360
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400361struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500362 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400363 drmModeModeInfo mode_info;
Daniel Stoned5526cb2016-11-16 10:54:10 +0000364 uint32_t blob_id;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400365};
366
Daniel Stonefc175a72017-04-04 17:54:22 +0100367enum drm_fb_type {
368 BUFFER_INVALID = 0, /**< never used */
369 BUFFER_CLIENT, /**< directly sourced from client */
Daniel Stonef522e222016-11-18 12:31:26 +0000370 BUFFER_DMABUF, /**< imported from linux_dmabuf client */
Daniel Stonefc175a72017-04-04 17:54:22 +0100371 BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
372 BUFFER_GBM_SURFACE, /**< internal EGL rendering */
Daniel Stonee4256832017-04-04 17:54:27 +0100373 BUFFER_CURSOR, /**< internal cursor buffer */
Daniel Stonefc175a72017-04-04 17:54:22 +0100374};
375
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300376struct drm_fb {
Daniel Stonefc175a72017-04-04 17:54:22 +0100377 enum drm_fb_type type;
378
Daniel Stone6e7a9612017-04-04 17:54:26 +0100379 int refcnt;
380
Daniel Stone8eece0c2016-11-17 17:54:00 +0000381 uint32_t fb_id, size;
382 uint32_t handles[4];
383 uint32_t strides[4];
384 uint32_t offsets[4];
Tomohito Esaki4976b092018-09-10 11:44:17 +0900385 int num_planes;
Daniel Stone0b70fa42017-04-04 17:54:23 +0100386 const struct pixel_format_info *format;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000387 uint64_t modifier;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000388 int width, height;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200389 int fd;
Pekka Paalanende685b82012-12-04 15:58:12 +0200390 struct weston_buffer_reference buffer_ref;
Alexandros Frantzis67629672018-10-19 12:14:11 +0300391 struct weston_buffer_release_reference buffer_release_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200392
393 /* Used by gbm fbs */
394 struct gbm_bo *bo;
Daniel Stone05a5ac22017-04-04 17:54:25 +0100395 struct gbm_surface *gbm_surface;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200396
397 /* Used by dumb fbs */
398 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300399};
400
Richard Hughes2b2092a2013-04-24 14:58:02 +0100401struct drm_edid {
402 char eisa_id[13];
403 char monitor_name[13];
404 char pnp_id[5];
405 char serial_number[13];
406};
407
Daniel Stone08d4edf2017-04-04 17:54:34 +0100408/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000409 * Pending state holds one or more drm_output_state structures, collected from
410 * performing repaint. This pending state is transient, and only lives between
411 * beginning a repaint group and flushing the results: after flush, each
412 * output state will complete and be retired separately.
413 */
414struct drm_pending_state {
415 struct drm_backend *backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000416 struct wl_list output_list;
417};
418
Marius Vlad5d767412018-12-14 11:56:10 +0200419enum drm_output_propose_state_mode {
420 DRM_OUTPUT_PROPOSE_STATE_MIXED, /**< mix renderer & planes */
421 DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY, /**< only assign to renderer & cursor */
422 DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY, /**< no renderer use, only planes */
423};
424
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000425/*
426 * Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
427 * plus >= 1 each of encoder/connector/plane. Since everything but the planes
428 * is currently statically assigned per-output, we mainly use this to track
429 * plane state.
430 *
431 * pending_state is set when the output state is owned by a pending_state,
432 * i.e. when it is being constructed and has not yet been applied. When the
433 * output state has been applied, the owning pending_state is freed.
434 */
435struct drm_output_state {
436 struct drm_pending_state *pending_state;
437 struct drm_output *output;
438 struct wl_list link;
Daniel Stonea08512f2016-11-08 17:46:10 +0000439 enum dpms_enum dpms;
Daniel Stonebc15f682016-11-14 16:57:01 +0000440 struct wl_list plane_list;
441};
442
443/**
444 * Plane state holds the dynamic state for a plane: where it is positioned,
445 * and which buffer it is currently displaying.
446 *
447 * The plane state is owned by an output state, except when setting an initial
448 * state. See drm_output_state for notes on state object lifetime.
449 */
450struct drm_plane_state {
451 struct drm_plane *plane;
452 struct drm_output *output;
453 struct drm_output_state *output_state;
454
455 struct drm_fb *fb;
456
Daniel Stoneee1aea72017-12-18 13:41:09 +0000457 struct weston_view *ev; /**< maintained for drm_assign_planes only */
458
Daniel Stonebc15f682016-11-14 16:57:01 +0000459 int32_t src_x, src_y;
460 uint32_t src_w, src_h;
461 int32_t dest_x, dest_y;
462 uint32_t dest_w, dest_h;
463
464 bool complete;
465
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300466 /* We don't own the fd, so we shouldn't close it */
467 int in_fence_fd;
468
Deepak Rawat009b3cf2018-07-24 14:05:37 -0700469 pixman_region32_t damage; /* damage to kernel */
470
Daniel Stonebc15f682016-11-14 16:57:01 +0000471 struct wl_list link; /* drm_output_state::plane_list */
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000472};
473
474/**
Daniel Stone08d4edf2017-04-04 17:54:34 +0100475 * A plane represents one buffer, positioned within a CRTC, and stacked
476 * relative to other planes on the same CRTC.
477 *
478 * Each CRTC has a 'primary plane', which use used to display the classic
479 * framebuffer contents, as accessed through the legacy drmModeSetCrtc
480 * call (which combines setting the CRTC's actual physical mode, and the
481 * properties of the primary plane).
482 *
483 * The cursor plane also has its own alternate legacy API.
484 *
485 * Other planes are used opportunistically to display content we do not
486 * wish to blit into the primary plane. These non-primary/cursor planes
487 * are referred to as 'sprites'.
488 */
489struct drm_plane {
Daniel Stone08d4edf2017-04-04 17:54:34 +0100490 struct weston_plane base;
491
Daniel Stone08d4edf2017-04-04 17:54:34 +0100492 struct drm_backend *backend;
493
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100494 enum wdrm_plane_type type;
495
Daniel Stone08d4edf2017-04-04 17:54:34 +0100496 uint32_t possible_crtcs;
497 uint32_t plane_id;
498 uint32_t count_formats;
499
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100500 struct drm_property_info props[WDRM_PLANE__COUNT];
501
Daniel Stonebc15f682016-11-14 16:57:01 +0000502 /* The last state submitted to the kernel for this plane. */
503 struct drm_plane_state *state_cur;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100504
Daniel Stonebc15f682016-11-14 16:57:01 +0000505 struct wl_list link;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100506
Sergi Granellf4456222017-01-12 17:17:32 +0000507 struct {
508 uint32_t format;
509 uint32_t count_modifiers;
510 uint64_t *modifiers;
511 } formats[];
Daniel Stone08d4edf2017-04-04 17:54:34 +0100512};
513
Pekka Paalanenc112f002017-08-28 16:27:20 +0300514struct drm_head {
515 struct weston_head base;
516 struct drm_backend *backend;
517
Armin Krezović08368132016-09-30 14:11:05 +0200518 drmModeConnector *connector;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400519 uint32_t connector_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100520 struct drm_edid edid;
Daniel Stone02cf4662017-03-03 16:19:39 +0000521
522 /* Holds the properties for the connector */
523 struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300524
525 struct backlight *backlight;
Pekka Paalanen13d233e2017-09-11 14:06:11 +0300526
527 drmModeModeInfo inherited_mode; /**< Original mode on the connector */
Pekka Paalanen27cc4812017-11-20 13:31:06 +0200528 uint32_t inherited_crtc_id; /**< Original CRTC assignment */
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300529};
530
531struct drm_output {
532 struct weston_output base;
Daniel Stone64dbbee2018-07-20 19:00:06 +0100533 struct drm_backend *backend;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300534
535 uint32_t crtc_id; /* object ID to pass to DRM functions */
536 int pipe; /* index of CRTC in resource array / bitmasks */
537
Pekka Paalanencd011a62016-11-15 22:07:49 +0000538 /* Holds the properties for the CRTC */
539 struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200540
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300541 int vblank_pending;
542 int page_flip_pending;
Daniel Stone598ee9d2016-11-16 11:55:20 +0000543 int atomic_complete_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800544 int destroy_pending;
Armin Krezović08368132016-09-30 14:11:05 +0200545 int disable_pending;
Daniel Stonea08512f2016-11-08 17:46:10 +0000546 int dpms_off_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300547
Daniel Stonee4256832017-04-04 17:54:27 +0100548 struct drm_fb *gbm_cursor_fb[2];
Daniel Stone2ba17f42015-05-19 20:02:41 +0100549 struct drm_plane *cursor_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500550 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400551 int current_cursor;
Daniel Stone5bb8f582017-04-04 17:54:28 +0100552
553 struct gbm_surface *gbm_surface;
554 uint32_t gbm_format;
Tomohito Esaki718a40b2018-01-31 17:50:15 +0900555 uint32_t gbm_bo_flags;
Daniel Stone5bb8f582017-04-04 17:54:28 +0100556
Daniel Stonee2e80132018-01-16 15:37:33 +0000557 /* Plane being displayed directly on the CRTC */
558 struct drm_plane *scanout_plane;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200559
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000560 /* The last state submitted to the kernel for this CRTC. */
561 struct drm_output_state *state_cur;
562 /* The previously-submitted state, where the hardware has not
563 * yet acknowledged completion of state_cur. */
564 struct drm_output_state *state_last;
565
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200566 struct drm_fb *dumb[2];
567 pixman_image_t *image[2];
568 int current_image;
569 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300570
571 struct vaapi_recorder *recorder;
572 struct wl_listener recorder_frame_listener;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000573
574 struct wl_event_source *pageflip_timer;
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900575
576 bool virtual;
577
578 submit_frame_cb virtual_submit_frame;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400579};
580
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530581static const char *const aspect_ratio_as_string[] = {
582 [WESTON_MODE_PIC_AR_NONE] = "",
583 [WESTON_MODE_PIC_AR_4_3] = " 4:3",
584 [WESTON_MODE_PIC_AR_16_9] = " 16:9",
585 [WESTON_MODE_PIC_AR_64_27] = " 64:27",
586 [WESTON_MODE_PIC_AR_256_135] = " 256:135",
587};
588
Marius Vlad5d767412018-12-14 11:56:10 +0200589static const char *const drm_output_propose_state_mode_as_string[] = {
590 [DRM_OUTPUT_PROPOSE_STATE_MIXED] = "mixed state",
591 [DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY] = "render-only state",
592 [DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY] = "plane-only state"
593};
594
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300595static struct gl_renderer_interface *gl_renderer;
596
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500597static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400598
Daniel Stone087ddf02017-02-14 17:51:30 +0000599static void
600wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
601{
602 uint32_t *pos, *end;
603
604 end = (uint32_t *) ((char *) array->data + array->size);
605
606 wl_array_for_each(pos, array) {
607 if (*pos != elm)
608 continue;
609
610 array->size -= sizeof(*pos);
611 if (pos + 1 == end)
612 break;
613
614 memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
615 break;
616 }
617}
618
Pekka Paalanenc112f002017-08-28 16:27:20 +0300619static inline struct drm_head *
620to_drm_head(struct weston_head *base)
621{
622 return container_of(base, struct drm_head, base);
623}
624
Armin Krezović545dba62016-08-05 15:54:18 +0200625static inline struct drm_output *
626to_drm_output(struct weston_output *base)
627{
628 return container_of(base, struct drm_output, base);
629}
630
631static inline struct drm_backend *
632to_drm_backend(struct weston_compositor *base)
633{
634 return container_of(base->backend, struct drm_backend, base);
635}
636
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000637static int
638pageflip_timeout(void *data) {
639 /*
640 * Our timer just went off, that means we're not receiving drm
641 * page flip events anymore for that output. Let's gracefully exit
642 * weston with a return value so devs can debug what's going on.
643 */
644 struct drm_output *output = data;
645 struct weston_compositor *compositor = output->base.compositor;
646
647 weston_log("Pageflip timeout reached on output %s, your "
648 "driver is probably buggy! Exiting.\n",
649 output->base.name);
650 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
651
652 return 0;
653}
654
655/* Creates the pageflip timer. Note that it isn't armed by default */
656static int
657drm_output_pageflip_timer_create(struct drm_output *output)
658{
659 struct wl_event_loop *loop = NULL;
660 struct weston_compositor *ec = output->base.compositor;
661
662 loop = wl_display_get_event_loop(ec->wl_display);
663 assert(loop);
664 output->pageflip_timer = wl_event_loop_add_timer(loop,
665 pageflip_timeout,
666 output);
667
668 if (output->pageflip_timer == NULL) {
Antonio Borneo39578632019-04-26 23:57:31 +0200669 weston_log("creating drm pageflip timer failed: %s\n",
670 strerror(errno));
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000671 return -1;
672 }
673
674 return 0;
675}
676
Daniel Stonecb04cc42016-11-16 11:51:27 +0000677static inline struct drm_mode *
678to_drm_mode(struct weston_mode *base)
679{
680 return container_of(base, struct drm_mode, base);
681}
682
Daniel Stone02cf4662017-03-03 16:19:39 +0000683/**
684 * Get the current value of a KMS property
685 *
686 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
687 * for the target property, return the current value of that property,
688 * with an optional default. If the property is a KMS enum type, the return
689 * value will be translated into the appropriate internal enum.
690 *
691 * If the property is not present, the default value will be returned.
692 *
693 * @param info Internal structure for property to look up
694 * @param props Raw KMS properties for the target object
695 * @param def Value to return if property is not found
696 */
697static uint64_t
698drm_property_get_value(struct drm_property_info *info,
Daniel Stone85eebdf2018-07-05 17:55:43 +0100699 const drmModeObjectProperties *props,
Daniel Stone02cf4662017-03-03 16:19:39 +0000700 uint64_t def)
701{
702 unsigned int i;
703
704 if (info->prop_id == 0)
705 return def;
706
707 for (i = 0; i < props->count_props; i++) {
708 unsigned int j;
709
710 if (props->props[i] != info->prop_id)
711 continue;
712
713 /* Simple (non-enum) types can return the value directly */
714 if (info->num_enum_values == 0)
715 return props->prop_values[i];
716
717 /* Map from raw value to enum value */
718 for (j = 0; j < info->num_enum_values; j++) {
719 if (!info->enum_values[j].valid)
720 continue;
721 if (info->enum_values[j].value != props->prop_values[i])
722 continue;
723
724 return j;
725 }
726
727 /* We don't have a mapping for this enum; return default. */
728 break;
729 }
730
731 return def;
732}
733
734/**
735 * Cache DRM property values
736 *
737 * Update a per-object array of drm_property_info structures, given the
738 * DRM properties of the object.
739 *
740 * Call this every time an object newly appears (note that only connectors
741 * can be hotplugged), the first time it is seen, or when its status changes
742 * in a way which invalidates the potential property values (currently, the
743 * only case for this is connector hotplug).
744 *
745 * This updates the property IDs and enum values within the drm_property_info
746 * array.
747 *
748 * DRM property enum values are dynamic at runtime; the user must query the
749 * property to find out the desired runtime value for a requested string
750 * name. Using the 'type' field on planes as an example, there is no single
751 * hardcoded constant for primary plane types; instead, the property must be
752 * queried at runtime to find the value associated with the string "Primary".
753 *
754 * This helper queries and caches the enum values, to allow us to use a set
755 * of compile-time-constant enums portably across various implementations.
756 * The values given in enum_names are searched for, and stored in the
757 * same-indexed field of the map array.
758 *
759 * @param b DRM backend object
760 * @param src DRM property info array to source from
761 * @param info DRM property info array to copy into
762 * @param num_infos Number of entries in the source array
763 * @param props DRM object properties for the object
764 */
765static void
766drm_property_info_populate(struct drm_backend *b,
767 const struct drm_property_info *src,
768 struct drm_property_info *info,
769 unsigned int num_infos,
770 drmModeObjectProperties *props)
771{
772 drmModePropertyRes *prop;
773 unsigned i, j;
774
775 for (i = 0; i < num_infos; i++) {
776 unsigned int j;
777
778 info[i].name = src[i].name;
779 info[i].prop_id = 0;
780 info[i].num_enum_values = src[i].num_enum_values;
781
782 if (src[i].num_enum_values == 0)
783 continue;
784
785 info[i].enum_values =
786 malloc(src[i].num_enum_values *
787 sizeof(*info[i].enum_values));
788 assert(info[i].enum_values);
789 for (j = 0; j < info[i].num_enum_values; j++) {
790 info[i].enum_values[j].name = src[i].enum_values[j].name;
791 info[i].enum_values[j].valid = false;
792 }
793 }
794
795 for (i = 0; i < props->count_props; i++) {
796 unsigned int k;
797
798 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
799 if (!prop)
800 continue;
801
802 for (j = 0; j < num_infos; j++) {
803 if (!strcmp(prop->name, info[j].name))
804 break;
805 }
806
807 /* We don't know/care about this property. */
808 if (j == num_infos) {
809#ifdef DEBUG
810 weston_log("DRM debug: unrecognized property %u '%s'\n",
811 prop->prop_id, prop->name);
812#endif
813 drmModeFreeProperty(prop);
814 continue;
815 }
816
817 if (info[j].num_enum_values == 0 &&
818 (prop->flags & DRM_MODE_PROP_ENUM)) {
819 weston_log("DRM: expected property %s to not be an"
820 " enum, but it is; ignoring\n", prop->name);
821 drmModeFreeProperty(prop);
822 continue;
823 }
824
825 info[j].prop_id = props->props[i];
826
827 if (info[j].num_enum_values == 0) {
828 drmModeFreeProperty(prop);
829 continue;
830 }
831
832 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
833 weston_log("DRM: expected property %s to be an enum,"
834 " but it is not; ignoring\n", prop->name);
835 drmModeFreeProperty(prop);
836 info[j].prop_id = 0;
837 continue;
838 }
839
840 for (k = 0; k < info[j].num_enum_values; k++) {
841 int l;
842
843 for (l = 0; l < prop->count_enums; l++) {
844 if (!strcmp(prop->enums[l].name,
845 info[j].enum_values[k].name))
846 break;
847 }
848
849 if (l == prop->count_enums)
850 continue;
851
852 info[j].enum_values[k].valid = true;
853 info[j].enum_values[k].value = prop->enums[l].value;
854 }
855
856 drmModeFreeProperty(prop);
857 }
858
859#ifdef DEBUG
860 for (i = 0; i < num_infos; i++) {
861 if (info[i].prop_id == 0)
862 weston_log("DRM warning: property '%s' missing\n",
863 info[i].name);
864 }
865#endif
866}
867
868/**
869 * Free DRM property information
870 *
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300871 * Frees all memory associated with a DRM property info array and zeroes
872 * it out, leaving it usable for a further drm_property_info_update() or
873 * drm_property_info_free().
Daniel Stone02cf4662017-03-03 16:19:39 +0000874 *
875 * @param info DRM property info array
876 * @param num_props Number of entries in array to free
877 */
878static void
879drm_property_info_free(struct drm_property_info *info, int num_props)
880{
881 int i;
882
883 for (i = 0; i < num_props; i++)
884 free(info[i].enum_values);
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300885
886 memset(info, 0, sizeof(*info) * num_props);
Daniel Stone02cf4662017-03-03 16:19:39 +0000887}
888
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400889static void
Daniel Stone2ba17f42015-05-19 20:02:41 +0100890drm_output_set_cursor(struct drm_output_state *output_state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400891
Mario Kleinerf507ec32015-06-21 21:25:14 +0200892static void
893drm_output_update_msc(struct drm_output *output, unsigned int seq);
894
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000895static void
896drm_output_destroy(struct weston_output *output_base);
897
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900898static void
899drm_virtual_output_destroy(struct weston_output *output_base);
900
Daniel Stone5ff289a2017-10-07 12:59:02 +0100901/**
902 * Returns true if the plane can be used on the given output for its current
903 * repaint cycle.
904 */
905static bool
906drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500907{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100908 assert(plane->state_cur);
909
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900910 if (output->virtual)
911 return false;
912
Daniel Stone5ff289a2017-10-07 12:59:02 +0100913 /* The plane still has a request not yet completed by the kernel. */
914 if (!plane->state_cur->complete)
915 return false;
916
917 /* The plane is still active on another output. */
918 if (plane->state_cur->output && plane->state_cur->output != output)
919 return false;
920
921 /* Check whether the plane can be used with this CRTC; possible_crtcs
922 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Daniel Stone08d4edf2017-04-04 17:54:34 +0100923 return !!(plane->possible_crtcs & (1 << output->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500924}
925
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000926static struct drm_output *
927drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
928{
929 struct drm_output *output;
930
931 wl_list_for_each(output, &b->compositor->output_list, base.link) {
932 if (output->crtc_id == crtc_id)
933 return output;
934 }
935
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000936 return NULL;
937}
938
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300939static struct drm_head *
940drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
941{
942 struct weston_head *base;
943 struct drm_head *head;
944
945 wl_list_for_each(base,
946 &backend->compositor->head_list, compositor_link) {
947 head = to_drm_head(base);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300948 if (head->connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300949 return head;
950 }
951
952 return NULL;
953}
954
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300955static void
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100956drm_fb_destroy(struct drm_fb *fb)
957{
958 if (fb->fb_id != 0)
959 drmModeRmFB(fb->fd, fb->fb_id);
960 weston_buffer_reference(&fb->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300961 weston_buffer_release_reference(&fb->buffer_release_ref, NULL);
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100962 free(fb);
963}
964
965static void
966drm_fb_destroy_dumb(struct drm_fb *fb)
967{
968 struct drm_mode_destroy_dumb destroy_arg;
969
970 assert(fb->type == BUFFER_PIXMAN_DUMB);
971
972 if (fb->map && fb->size > 0)
973 munmap(fb->map, fb->size);
974
975 memset(&destroy_arg, 0, sizeof(destroy_arg));
Daniel Stone8eece0c2016-11-17 17:54:00 +0000976 destroy_arg.handle = fb->handles[0];
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100977 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
978
979 drm_fb_destroy(fb);
980}
981
982static void
983drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300984{
985 struct drm_fb *fb = data;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300986
Daniel Stonee4256832017-04-04 17:54:27 +0100987 assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
988 fb->type == BUFFER_CURSOR);
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100989 drm_fb_destroy(fb);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300990}
991
Daniel Stone8eece0c2016-11-17 17:54:00 +0000992static int
Deepak Rawata864f582018-08-24 13:16:03 -0700993drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
Daniel Stone8eece0c2016-11-17 17:54:00 +0000994{
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000995 int ret = -EINVAL;
996#ifdef HAVE_DRM_ADDFB2_MODIFIERS
997 uint64_t mods[4] = { };
Daniel Stonedc082cb2018-07-09 13:49:04 +0100998 size_t i;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000999#endif
1000
1001 /* If we have a modifier set, we must only use the WithModifiers
1002 * entrypoint; we cannot import it through legacy ioctls. */
Deepak Rawata864f582018-08-24 13:16:03 -07001003 if (b->fb_modifiers && fb->modifier != DRM_FORMAT_MOD_INVALID) {
Daniel Stone65a4dbc2016-12-08 16:36:18 +00001004 /* KMS demands that if a modifier is set, it must be the same
1005 * for all planes. */
1006#ifdef HAVE_DRM_ADDFB2_MODIFIERS
Daniel Stonedc082cb2018-07-09 13:49:04 +01001007 for (i = 0; i < ARRAY_LENGTH(mods) && fb->handles[i]; i++)
Daniel Stone65a4dbc2016-12-08 16:36:18 +00001008 mods[i] = fb->modifier;
1009 ret = drmModeAddFB2WithModifiers(fb->fd, fb->width, fb->height,
1010 fb->format->format,
1011 fb->handles, fb->strides,
1012 fb->offsets, mods, &fb->fb_id,
1013 DRM_MODE_FB_MODIFIERS);
1014#endif
1015 return ret;
1016 }
Daniel Stone8eece0c2016-11-17 17:54:00 +00001017
1018 ret = drmModeAddFB2(fb->fd, fb->width, fb->height, fb->format->format,
1019 fb->handles, fb->strides, fb->offsets, &fb->fb_id,
1020 0);
1021 if (ret == 0)
1022 return 0;
1023
1024 /* Legacy AddFB can't always infer the format from depth/bpp alone, so
1025 * check if our format is one of the lucky ones. */
1026 if (!fb->format->depth || !fb->format->bpp)
1027 return ret;
1028
1029 /* Cannot fall back to AddFB for multi-planar formats either. */
1030 if (fb->handles[1] || fb->handles[2] || fb->handles[3])
1031 return ret;
1032
1033 ret = drmModeAddFB(fb->fd, fb->width, fb->height,
1034 fb->format->depth, fb->format->bpp,
1035 fb->strides[0], fb->handles[0], &fb->fb_id);
1036 return ret;
1037}
1038
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001039static struct drm_fb *
Daniel Stonef214fdc2016-11-14 17:43:57 +00001040drm_fb_create_dumb(struct drm_backend *b, int width, int height,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001041 uint32_t format)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001042{
1043 struct drm_fb *fb;
1044 int ret;
1045
1046 struct drm_mode_create_dumb create_arg;
1047 struct drm_mode_destroy_dumb destroy_arg;
1048 struct drm_mode_map_dumb map_arg;
1049
Peter Huttererf3d62272013-08-08 11:57:05 +10001050 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001051 if (!fb)
1052 return NULL;
Daniel Stone6e7a9612017-04-04 17:54:26 +01001053 fb->refcnt = 1;
1054
Daniel Stone0b70fa42017-04-04 17:54:23 +01001055 fb->format = pixel_format_get_info(format);
1056 if (!fb->format) {
1057 weston_log("failed to look up format 0x%lx\n",
1058 (unsigned long) format);
1059 goto err_fb;
1060 }
1061
1062 if (!fb->format->depth || !fb->format->bpp) {
1063 weston_log("format 0x%lx is not compatible with dumb buffers\n",
1064 (unsigned long) format);
1065 goto err_fb;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001066 }
1067
Kristian Høgsbergac6104e2013-08-21 22:14:14 -07001068 memset(&create_arg, 0, sizeof create_arg);
Daniel Stone0b70fa42017-04-04 17:54:23 +01001069 create_arg.bpp = fb->format->bpp;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001070 create_arg.width = width;
1071 create_arg.height = height;
1072
Giulio Camuffo954f1832014-10-11 18:27:30 +03001073 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001074 if (ret)
1075 goto err_fb;
1076
Daniel Stonefc175a72017-04-04 17:54:22 +01001077 fb->type = BUFFER_PIXMAN_DUMB;
Daniel Stone65a4dbc2016-12-08 16:36:18 +00001078 fb->modifier = DRM_FORMAT_MOD_INVALID;
Daniel Stone8eece0c2016-11-17 17:54:00 +00001079 fb->handles[0] = create_arg.handle;
1080 fb->strides[0] = create_arg.pitch;
Tomohito Esaki4976b092018-09-10 11:44:17 +09001081 fb->num_planes = 1;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001082 fb->size = create_arg.size;
Daniel Stonec8c917c2016-11-14 17:45:58 +00001083 fb->width = width;
1084 fb->height = height;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001085 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001086
Deepak Rawata864f582018-08-24 13:16:03 -07001087 if (drm_fb_addfb(b, fb) != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02001088 weston_log("failed to create kms fb: %s\n", strerror(errno));
Daniel Stone8eece0c2016-11-17 17:54:00 +00001089 goto err_bo;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001090 }
1091
Kristian Høgsbergac6104e2013-08-21 22:14:14 -07001092 memset(&map_arg, 0, sizeof map_arg);
Daniel Stone8eece0c2016-11-17 17:54:00 +00001093 map_arg.handle = fb->handles[0];
Chris Michaeleb2074a2013-05-01 21:26:02 -04001094 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001095 if (ret)
1096 goto err_add_fb;
1097
Chris Michael4a7ce1f2015-11-10 10:40:37 -05001098 fb->map = mmap(NULL, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001099 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001100 if (fb->map == MAP_FAILED)
1101 goto err_add_fb;
1102
1103 return fb;
1104
1105err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +03001106 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001107err_bo:
1108 memset(&destroy_arg, 0, sizeof(destroy_arg));
1109 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001110 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001111err_fb:
1112 free(fb);
1113 return NULL;
1114}
1115
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001116static struct drm_fb *
Daniel Stone6e7a9612017-04-04 17:54:26 +01001117drm_fb_ref(struct drm_fb *fb)
1118{
1119 fb->refcnt++;
1120 return fb;
1121}
1122
Daniel Stonef522e222016-11-18 12:31:26 +00001123static void
1124drm_fb_destroy_dmabuf(struct drm_fb *fb)
1125{
1126 /* We deliberately do not close the GEM handles here; GBM manages
1127 * their lifetime through the BO. */
1128 if (fb->bo)
1129 gbm_bo_destroy(fb->bo);
1130 drm_fb_destroy(fb);
1131}
1132
1133static struct drm_fb *
1134drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
1135 struct drm_backend *backend, bool is_opaque)
1136{
1137#ifdef HAVE_GBM_FD_IMPORT
1138 struct drm_fb *fb;
1139 struct gbm_import_fd_data import_legacy = {
1140 .width = dmabuf->attributes.width,
1141 .height = dmabuf->attributes.height,
1142 .format = dmabuf->attributes.format,
1143 .stride = dmabuf->attributes.stride[0],
1144 .fd = dmabuf->attributes.fd[0],
1145 };
1146 struct gbm_import_fd_modifier_data import_mod = {
1147 .width = dmabuf->attributes.width,
1148 .height = dmabuf->attributes.height,
1149 .format = dmabuf->attributes.format,
1150 .num_fds = dmabuf->attributes.n_planes,
1151 .modifier = dmabuf->attributes.modifier[0],
1152 };
1153 int i;
1154
1155 /* XXX: TODO:
1156 *
1157 * Currently the buffer is rejected if any dmabuf attribute
1158 * flag is set. This keeps us from passing an inverted /
1159 * interlaced / bottom-first buffer (or any other type that may
1160 * be added in the future) through to an overlay. Ultimately,
1161 * these types of buffers should be handled through buffer
1162 * transforms and not as spot-checks requiring specific
1163 * knowledge. */
1164 if (dmabuf->attributes.flags)
1165 return NULL;
1166
1167 fb = zalloc(sizeof *fb);
1168 if (fb == NULL)
1169 return NULL;
1170
1171 fb->refcnt = 1;
1172 fb->type = BUFFER_DMABUF;
1173
1174 static_assert(ARRAY_LENGTH(import_mod.fds) ==
1175 ARRAY_LENGTH(dmabuf->attributes.fd),
1176 "GBM and linux_dmabuf FD size must match");
1177 static_assert(sizeof(import_mod.fds) == sizeof(dmabuf->attributes.fd),
1178 "GBM and linux_dmabuf FD size must match");
1179 memcpy(import_mod.fds, dmabuf->attributes.fd, sizeof(import_mod.fds));
1180
1181 static_assert(ARRAY_LENGTH(import_mod.strides) ==
1182 ARRAY_LENGTH(dmabuf->attributes.stride),
1183 "GBM and linux_dmabuf stride size must match");
1184 static_assert(sizeof(import_mod.strides) ==
1185 sizeof(dmabuf->attributes.stride),
1186 "GBM and linux_dmabuf stride size must match");
1187 memcpy(import_mod.strides, dmabuf->attributes.stride,
1188 sizeof(import_mod.strides));
1189
1190 static_assert(ARRAY_LENGTH(import_mod.offsets) ==
1191 ARRAY_LENGTH(dmabuf->attributes.offset),
1192 "GBM and linux_dmabuf offset size must match");
1193 static_assert(sizeof(import_mod.offsets) ==
1194 sizeof(dmabuf->attributes.offset),
1195 "GBM and linux_dmabuf offset size must match");
1196 memcpy(import_mod.offsets, dmabuf->attributes.offset,
1197 sizeof(import_mod.offsets));
1198
1199 /* The legacy FD-import path does not allow us to supply modifiers,
1200 * multiple planes, or buffer offsets. */
1201 if (dmabuf->attributes.modifier[0] != DRM_FORMAT_MOD_INVALID ||
1202 import_mod.num_fds > 1 ||
1203 import_mod.offsets[0] > 0) {
1204 fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
1205 &import_mod,
1206 GBM_BO_USE_SCANOUT);
1207 } else {
1208 fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD,
1209 &import_legacy,
1210 GBM_BO_USE_SCANOUT);
1211 }
1212
1213 if (!fb->bo)
1214 goto err_free;
1215
1216 fb->width = dmabuf->attributes.width;
1217 fb->height = dmabuf->attributes.height;
1218 fb->modifier = dmabuf->attributes.modifier[0];
1219 fb->size = 0;
1220 fb->fd = backend->drm.fd;
1221
1222 static_assert(ARRAY_LENGTH(fb->strides) ==
1223 ARRAY_LENGTH(dmabuf->attributes.stride),
1224 "drm_fb and dmabuf stride size must match");
1225 static_assert(sizeof(fb->strides) == sizeof(dmabuf->attributes.stride),
1226 "drm_fb and dmabuf stride size must match");
1227 memcpy(fb->strides, dmabuf->attributes.stride, sizeof(fb->strides));
1228 static_assert(ARRAY_LENGTH(fb->offsets) ==
1229 ARRAY_LENGTH(dmabuf->attributes.offset),
1230 "drm_fb and dmabuf offset size must match");
1231 static_assert(sizeof(fb->offsets) == sizeof(dmabuf->attributes.offset),
1232 "drm_fb and dmabuf offset size must match");
1233 memcpy(fb->offsets, dmabuf->attributes.offset, sizeof(fb->offsets));
1234
1235 fb->format = pixel_format_get_info(dmabuf->attributes.format);
1236 if (!fb->format) {
1237 weston_log("couldn't look up format info for 0x%lx\n",
1238 (unsigned long) dmabuf->attributes.format);
1239 goto err_free;
1240 }
1241
1242 if (is_opaque)
1243 fb->format = pixel_format_get_opaque_substitute(fb->format);
1244
1245 if (backend->min_width > fb->width ||
1246 fb->width > backend->max_width ||
1247 backend->min_height > fb->height ||
1248 fb->height > backend->max_height) {
1249 weston_log("bo geometry out of bounds\n");
1250 goto err_free;
1251 }
1252
Tomohito Esaki4976b092018-09-10 11:44:17 +09001253 fb->num_planes = dmabuf->attributes.n_planes;
Daniel Stonef522e222016-11-18 12:31:26 +00001254 for (i = 0; i < dmabuf->attributes.n_planes; i++) {
Philipp Zabel1c49b542019-02-15 14:52:00 +01001255 union gbm_bo_handle handle;
1256
1257 handle = gbm_bo_get_handle_for_plane(fb->bo, i);
1258 if (handle.s32 == -1)
Daniel Stonef522e222016-11-18 12:31:26 +00001259 goto err_free;
Philipp Zabel1c49b542019-02-15 14:52:00 +01001260 fb->handles[i] = handle.u32;
Daniel Stonef522e222016-11-18 12:31:26 +00001261 }
1262
Deepak Rawata864f582018-08-24 13:16:03 -07001263 if (drm_fb_addfb(backend, fb) != 0)
Daniel Stonef522e222016-11-18 12:31:26 +00001264 goto err_free;
Daniel Stonef522e222016-11-18 12:31:26 +00001265
1266 return fb;
1267
1268err_free:
1269 drm_fb_destroy_dmabuf(fb);
1270#endif
1271 return NULL;
1272}
1273
Daniel Stone6e7a9612017-04-04 17:54:26 +01001274static struct drm_fb *
Daniel Stonefc175a72017-04-04 17:54:22 +01001275drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
Daniel Stonedb10df12016-12-08 13:15:58 +00001276 bool is_opaque, enum drm_fb_type type)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001277{
1278 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Daniel Stone244244d2016-11-18 18:02:08 +00001279#ifdef HAVE_GBM_MODIFIERS
1280 int i;
1281#endif
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001282
Daniel Stonefc175a72017-04-04 17:54:22 +01001283 if (fb) {
1284 assert(fb->type == type);
Daniel Stone6e7a9612017-04-04 17:54:26 +01001285 return drm_fb_ref(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +01001286 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001287
Bryce Harringtonde16d892014-11-20 22:21:57 -08001288 fb = zalloc(sizeof *fb);
1289 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001290 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001291
Daniel Stonefc175a72017-04-04 17:54:22 +01001292 fb->type = type;
Daniel Stone6e7a9612017-04-04 17:54:26 +01001293 fb->refcnt = 1;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001294 fb->bo = bo;
Daniel Stone244244d2016-11-18 18:02:08 +00001295 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001296
Daniel Stonec8c917c2016-11-14 17:45:58 +00001297 fb->width = gbm_bo_get_width(bo);
1298 fb->height = gbm_bo_get_height(bo);
Daniel Stone244244d2016-11-18 18:02:08 +00001299 fb->format = pixel_format_get_info(gbm_bo_get_format(bo));
1300 fb->size = 0;
1301
1302#ifdef HAVE_GBM_MODIFIERS
1303 fb->modifier = gbm_bo_get_modifier(bo);
Tomohito Esaki4976b092018-09-10 11:44:17 +09001304 fb->num_planes = gbm_bo_get_plane_count(bo);
1305 for (i = 0; i < fb->num_planes; i++) {
Daniel Stone244244d2016-11-18 18:02:08 +00001306 fb->strides[i] = gbm_bo_get_stride_for_plane(bo, i);
1307 fb->handles[i] = gbm_bo_get_handle_for_plane(bo, i).u32;
1308 fb->offsets[i] = gbm_bo_get_offset(bo, i);
1309 }
1310#else
Tomohito Esaki4976b092018-09-10 11:44:17 +09001311 fb->num_planes = 1;
Daniel Stone8eece0c2016-11-17 17:54:00 +00001312 fb->strides[0] = gbm_bo_get_stride(bo);
1313 fb->handles[0] = gbm_bo_get_handle(bo).u32;
Daniel Stone65a4dbc2016-12-08 16:36:18 +00001314 fb->modifier = DRM_FORMAT_MOD_INVALID;
Daniel Stone244244d2016-11-18 18:02:08 +00001315#endif
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001316
Daniel Stone0b70fa42017-04-04 17:54:23 +01001317 if (!fb->format) {
1318 weston_log("couldn't look up format 0x%lx\n",
Daniel Stonedb10df12016-12-08 13:15:58 +00001319 (unsigned long) gbm_bo_get_format(bo));
Daniel Stone0b70fa42017-04-04 17:54:23 +01001320 goto err_free;
1321 }
1322
Daniel Stonedb10df12016-12-08 13:15:58 +00001323 /* We can scanout an ARGB buffer if the surface's opaque region covers
1324 * the whole output, but we have to use XRGB as the KMS format code. */
1325 if (is_opaque)
1326 fb->format = pixel_format_get_opaque_substitute(fb->format);
1327
Daniel Stonec8c917c2016-11-14 17:45:58 +00001328 if (backend->min_width > fb->width ||
1329 fb->width > backend->max_width ||
1330 backend->min_height > fb->height ||
1331 fb->height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001332 weston_log("bo geometry out of bounds\n");
1333 goto err_free;
1334 }
1335
Deepak Rawata864f582018-08-24 13:16:03 -07001336 if (drm_fb_addfb(backend, fb) != 0) {
Daniel Stone48687982018-07-12 12:16:47 +01001337 if (type == BUFFER_GBM_SURFACE)
Antonio Borneo39578632019-04-26 23:57:31 +02001338 weston_log("failed to create kms fb: %s\n",
1339 strerror(errno));
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001340 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001341 }
1342
Tomohito Esaki576f42e2017-04-04 17:54:24 +01001343 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001344
1345 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001346
1347err_free:
1348 free(fb);
1349 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001350}
1351
1352static void
Alexandros Frantzis67629672018-10-19 12:14:11 +03001353drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer,
1354 struct weston_buffer_release *buffer_release)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001355{
Pekka Paalanende685b82012-12-04 15:58:12 +02001356 assert(fb->buffer_ref.buffer == NULL);
Daniel Stonef522e222016-11-18 12:31:26 +00001357 assert(fb->type == BUFFER_CLIENT || fb->type == BUFFER_DMABUF);
Pekka Paalanende685b82012-12-04 15:58:12 +02001358 weston_buffer_reference(&fb->buffer_ref, buffer);
Alexandros Frantzis67629672018-10-19 12:14:11 +03001359 weston_buffer_release_reference(&fb->buffer_release_ref,
1360 buffer_release);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001361}
1362
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001363static void
Daniel Stone05a5ac22017-04-04 17:54:25 +01001364drm_fb_unref(struct drm_fb *fb)
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001365{
1366 if (!fb)
1367 return;
1368
Daniel Stone6e7a9612017-04-04 17:54:26 +01001369 assert(fb->refcnt > 0);
1370 if (--fb->refcnt > 0)
1371 return;
1372
Daniel Stonefc175a72017-04-04 17:54:22 +01001373 switch (fb->type) {
1374 case BUFFER_PIXMAN_DUMB:
Daniel Stone6e7a9612017-04-04 17:54:26 +01001375 drm_fb_destroy_dumb(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +01001376 break;
Daniel Stonee4256832017-04-04 17:54:27 +01001377 case BUFFER_CURSOR:
Daniel Stonefc175a72017-04-04 17:54:22 +01001378 case BUFFER_CLIENT:
1379 gbm_bo_destroy(fb->bo);
1380 break;
1381 case BUFFER_GBM_SURFACE:
Daniel Stone05a5ac22017-04-04 17:54:25 +01001382 gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
Daniel Stonefc175a72017-04-04 17:54:22 +01001383 break;
Daniel Stonef522e222016-11-18 12:31:26 +00001384 case BUFFER_DMABUF:
1385 drm_fb_destroy_dmabuf(fb);
1386 break;
Daniel Stonefc175a72017-04-04 17:54:22 +01001387 default:
1388 assert(NULL);
1389 break;
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001390 }
1391}
1392
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001393/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001394 * Allocate a new, empty, plane state.
1395 */
1396static struct drm_plane_state *
1397drm_plane_state_alloc(struct drm_output_state *state_output,
1398 struct drm_plane *plane)
1399{
1400 struct drm_plane_state *state = zalloc(sizeof(*state));
1401
1402 assert(state);
1403 state->output_state = state_output;
1404 state->plane = plane;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03001405 state->in_fence_fd = -1;
Deepak Rawat009b3cf2018-07-24 14:05:37 -07001406 pixman_region32_init(&state->damage);
Daniel Stonebc15f682016-11-14 16:57:01 +00001407
1408 /* Here we only add the plane state to the desired link, and not
1409 * set the member. Having an output pointer set means that the
1410 * plane will be displayed on the output; this won't be the case
1411 * when we go to disable a plane. In this case, it must be part of
1412 * the commit (and thus the output state), but the member must be
1413 * NULL, as it will not be on any output when the state takes
1414 * effect.
1415 */
1416 if (state_output)
1417 wl_list_insert(&state_output->plane_list, &state->link);
1418 else
1419 wl_list_init(&state->link);
1420
1421 return state;
1422}
1423
1424/**
1425 * Free an existing plane state. As a special case, the state will not
1426 * normally be freed if it is the current state; see drm_plane_set_state.
1427 */
1428static void
1429drm_plane_state_free(struct drm_plane_state *state, bool force)
1430{
1431 if (!state)
1432 return;
1433
1434 wl_list_remove(&state->link);
1435 wl_list_init(&state->link);
1436 state->output_state = NULL;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03001437 state->in_fence_fd = -1;
Deepak Rawat009b3cf2018-07-24 14:05:37 -07001438 pixman_region32_fini(&state->damage);
Daniel Stonebc15f682016-11-14 16:57:01 +00001439
1440 if (force || state != state->plane->state_cur) {
1441 drm_fb_unref(state->fb);
1442 free(state);
1443 }
1444}
1445
1446/**
1447 * Duplicate an existing plane state into a new plane state, storing it within
1448 * the given output state. If the output state already contains a plane state
1449 * for the drm_plane referenced by 'src', that plane state is freed first.
1450 */
1451static struct drm_plane_state *
1452drm_plane_state_duplicate(struct drm_output_state *state_output,
1453 struct drm_plane_state *src)
1454{
1455 struct drm_plane_state *dst = malloc(sizeof(*dst));
1456 struct drm_plane_state *old, *tmp;
1457
1458 assert(src);
1459 assert(dst);
1460 *dst = *src;
1461 wl_list_init(&dst->link);
1462
1463 wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
1464 /* Duplicating a plane state into the same output state, so
1465 * it can replace itself with an identical copy of itself,
1466 * makes no sense. */
1467 assert(old != src);
1468 if (old->plane == dst->plane)
1469 drm_plane_state_free(old, false);
1470 }
1471
1472 wl_list_insert(&state_output->plane_list, &dst->link);
1473 if (src->fb)
1474 dst->fb = drm_fb_ref(src->fb);
1475 dst->output_state = state_output;
Deepak Rawat009b3cf2018-07-24 14:05:37 -07001476 pixman_region32_init(&dst->damage);
Daniel Stonebc15f682016-11-14 16:57:01 +00001477 dst->complete = false;
1478
1479 return dst;
1480}
1481
1482/**
1483 * Remove a plane state from an output state; if the plane was previously
1484 * enabled, then replace it with a disabling state. This ensures that the
1485 * output state was untouched from it was before the plane state was
1486 * modified by the caller of this function.
1487 *
1488 * This is required as drm_output_state_get_plane may either allocate a
1489 * new plane state, in which case this function will just perform a matching
1490 * drm_plane_state_free, or it may instead repurpose an existing disabling
1491 * state (if the plane was previously active), in which case this function
1492 * will reset it.
1493 */
1494static void
1495drm_plane_state_put_back(struct drm_plane_state *state)
1496{
1497 struct drm_output_state *state_output;
1498 struct drm_plane *plane;
1499
1500 if (!state)
1501 return;
1502
1503 state_output = state->output_state;
1504 plane = state->plane;
1505 drm_plane_state_free(state, false);
1506
1507 /* Plane was previously disabled; no need to keep this temporary
1508 * state around. */
1509 if (!plane->state_cur->fb)
1510 return;
1511
1512 (void) drm_plane_state_alloc(state_output, plane);
1513}
1514
Daniel Stonece137472016-11-16 19:35:03 +00001515static bool
1516drm_view_transform_supported(struct weston_view *ev, struct weston_output *output)
1517{
1518 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
1519
1520 /* This will incorrectly disallow cases where the combination of
1521 * buffer and view transformations match the output transform.
1522 * Fixing this requires a full analysis of the transformation
1523 * chain. */
1524 if (ev->transform.enabled &&
1525 ev->transform.matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE)
1526 return false;
1527
1528 if (viewport->buffer.transform != output->transform)
1529 return false;
1530
1531 return true;
1532}
1533
Daniel Stonebc15f682016-11-14 16:57:01 +00001534/**
Daniel Stoned6e2a762016-11-16 19:33:20 +00001535 * Given a weston_view, fill the drm_plane_state's co-ordinates to display on
1536 * a given plane.
1537 */
Daniel Stonece137472016-11-16 19:35:03 +00001538static bool
Daniel Stoned6e2a762016-11-16 19:33:20 +00001539drm_plane_state_coords_for_view(struct drm_plane_state *state,
1540 struct weston_view *ev)
1541{
1542 struct drm_output *output = state->output;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001543 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001544 pixman_region32_t dest_rect, src_rect;
1545 pixman_box32_t *box, tbox;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001546 float sxf1, syf1, sxf2, syf2;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001547
Daniel Stonece137472016-11-16 19:35:03 +00001548 if (!drm_view_transform_supported(ev, &output->base))
1549 return false;
1550
Daniel Stoned6e2a762016-11-16 19:33:20 +00001551 /* Update the base weston_plane co-ordinates. */
1552 box = pixman_region32_extents(&ev->transform.boundingbox);
1553 state->plane->base.x = box->x1;
1554 state->plane->base.y = box->y1;
1555
1556 /* First calculate the destination co-ordinates by taking the
1557 * area of the view which is visible on this output, performing any
1558 * transforms to account for output rotation and scale as necessary. */
1559 pixman_region32_init(&dest_rect);
1560 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
1561 &output->base.region);
1562 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
1563 box = pixman_region32_extents(&dest_rect);
1564 tbox = weston_transformed_rect(output->base.width,
1565 output->base.height,
1566 output->base.transform,
1567 output->base.current_scale,
1568 *box);
1569 state->dest_x = tbox.x1;
1570 state->dest_y = tbox.y1;
1571 state->dest_w = tbox.x2 - tbox.x1;
1572 state->dest_h = tbox.y2 - tbox.y1;
1573 pixman_region32_fini(&dest_rect);
1574
1575 /* Now calculate the source rectangle, by finding the extents of the
1576 * view, and working backwards to source co-ordinates. */
1577 pixman_region32_init(&src_rect);
1578 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
1579 &output->base.region);
1580 box = pixman_region32_extents(&src_rect);
Daniel Stonedf2726a2017-02-07 18:48:19 +00001581 weston_view_from_global_float(ev, box->x1, box->y1, &sxf1, &syf1);
1582 weston_surface_to_buffer_float(ev->surface, sxf1, syf1, &sxf1, &syf1);
1583 weston_view_from_global_float(ev, box->x2, box->y2, &sxf2, &syf2);
1584 weston_surface_to_buffer_float(ev->surface, sxf2, syf2, &sxf2, &syf2);
1585 pixman_region32_fini(&src_rect);
Daniel Stoned6e2a762016-11-16 19:33:20 +00001586
Daniel Stonedf2726a2017-02-07 18:48:19 +00001587 /* Buffer transforms may mean that x2 is to the left of x1, and/or that
1588 * y2 is above y1. */
1589 if (sxf2 < sxf1) {
1590 double tmp = sxf1;
1591 sxf1 = sxf2;
1592 sxf2 = tmp;
1593 }
1594 if (syf2 < syf1) {
1595 double tmp = syf1;
1596 syf1 = syf2;
1597 syf2 = tmp;
1598 }
1599
1600 /* Shift from S23.8 wl_fixed to U16.16 KMS fixed-point encoding. */
1601 state->src_x = wl_fixed_from_double(sxf1) << 8;
1602 state->src_y = wl_fixed_from_double(syf1) << 8;
1603 state->src_w = wl_fixed_from_double(sxf2 - sxf1) << 8;
1604 state->src_h = wl_fixed_from_double(syf2 - syf1) << 8;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001605
1606 /* Clamp our source co-ordinates to surface bounds; it's possible
1607 * for intermediate translations to give us slightly incorrect
1608 * co-ordinates if we have, for example, multiple zooming
1609 * transformations. View bounding boxes are also explicitly rounded
1610 * greedily. */
Daniel Stonedf2726a2017-02-07 18:48:19 +00001611 if (state->src_x < 0)
1612 state->src_x = 0;
1613 if (state->src_y < 0)
1614 state->src_y = 0;
1615 if (state->src_w > (uint32_t) ((buffer->width << 16) - state->src_x))
1616 state->src_w = (buffer->width << 16) - state->src_x;
1617 if (state->src_h > (uint32_t) ((buffer->height << 16) - state->src_y))
1618 state->src_h = (buffer->height << 16) - state->src_y;
Daniel Stonece137472016-11-16 19:35:03 +00001619
1620 return true;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001621}
1622
Daniel Stonef11ec022016-11-17 17:32:42 +00001623static struct drm_fb *
1624drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
1625{
1626 struct drm_output *output = state->output;
1627 struct drm_backend *b = to_drm_backend(output->base.compositor);
1628 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Philipp Zabelfff27972018-09-03 20:13:52 +02001629 bool is_opaque = weston_view_is_opaque(ev, &ev->transform.boundingbox);
Daniel Stonef11ec022016-11-17 17:32:42 +00001630 struct linux_dmabuf_buffer *dmabuf;
1631 struct drm_fb *fb;
Daniel Stonef11ec022016-11-17 17:32:42 +00001632
Daniel Stonef11ec022016-11-17 17:32:42 +00001633 if (ev->alpha != 1.0f)
1634 return NULL;
1635
1636 if (!drm_view_transform_supported(ev, &output->base))
1637 return NULL;
1638
1639 if (!buffer)
1640 return NULL;
1641
1642 if (wl_shm_buffer_get(buffer->resource))
1643 return NULL;
1644
Daniel Stonef522e222016-11-18 12:31:26 +00001645 /* GBM is used for dmabuf import as well as from client wl_buffer. */
Daniel Stonef11ec022016-11-17 17:32:42 +00001646 if (!b->gbm)
1647 return NULL;
1648
1649 dmabuf = linux_dmabuf_buffer_get(buffer->resource);
1650 if (dmabuf) {
Daniel Stonef522e222016-11-18 12:31:26 +00001651 fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque);
1652 if (!fb)
Daniel Stonef11ec022016-11-17 17:32:42 +00001653 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00001654 } else {
Daniel Stonef522e222016-11-18 12:31:26 +00001655 struct gbm_bo *bo;
1656
Daniel Stonef11ec022016-11-17 17:32:42 +00001657 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
1658 buffer->resource, GBM_BO_USE_SCANOUT);
Daniel Stonef522e222016-11-18 12:31:26 +00001659 if (!bo)
1660 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00001661
Daniel Stonef522e222016-11-18 12:31:26 +00001662 fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT);
1663 if (!fb) {
1664 gbm_bo_destroy(bo);
1665 return NULL;
1666 }
Daniel Stonef11ec022016-11-17 17:32:42 +00001667 }
1668
Marius Vladf5ca2f12019-01-22 17:56:36 +02001669 drm_debug(b, "\t\t\t[view] view %p format: %s\n",
1670 ev, fb->format->drm_format_name);
Alexandros Frantzis67629672018-10-19 12:14:11 +03001671 drm_fb_set_buffer(fb, buffer,
1672 ev->surface->buffer_release_ref.buffer_release);
Daniel Stonef11ec022016-11-17 17:32:42 +00001673 return fb;
1674}
1675
Daniel Stoned6e2a762016-11-16 19:33:20 +00001676/**
Daniel Stone2ba17f42015-05-19 20:02:41 +01001677 * Return a plane state from a drm_output_state.
1678 */
1679static struct drm_plane_state *
1680drm_output_state_get_existing_plane(struct drm_output_state *state_output,
1681 struct drm_plane *plane)
1682{
1683 struct drm_plane_state *ps;
1684
1685 wl_list_for_each(ps, &state_output->plane_list, link) {
1686 if (ps->plane == plane)
1687 return ps;
1688 }
1689
1690 return NULL;
1691}
1692
1693/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001694 * Return a plane state from a drm_output_state, either existing or
1695 * freshly allocated.
1696 */
1697static struct drm_plane_state *
1698drm_output_state_get_plane(struct drm_output_state *state_output,
1699 struct drm_plane *plane)
1700{
1701 struct drm_plane_state *ps;
1702
Daniel Stone2ba17f42015-05-19 20:02:41 +01001703 ps = drm_output_state_get_existing_plane(state_output, plane);
1704 if (ps)
1705 return ps;
Daniel Stonebc15f682016-11-14 16:57:01 +00001706
1707 return drm_plane_state_alloc(state_output, plane);
1708}
1709
1710/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001711 * Allocate a new, empty drm_output_state. This should not generally be used
1712 * in the repaint cycle; see drm_output_state_duplicate.
1713 */
1714static struct drm_output_state *
1715drm_output_state_alloc(struct drm_output *output,
1716 struct drm_pending_state *pending_state)
Daniel Stone90648872016-10-21 18:08:37 +01001717{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001718 struct drm_output_state *state = zalloc(sizeof(*state));
1719
1720 assert(state);
1721 state->output = output;
Daniel Stonea08512f2016-11-08 17:46:10 +00001722 state->dpms = WESTON_DPMS_OFF;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001723 state->pending_state = pending_state;
1724 if (pending_state)
1725 wl_list_insert(&pending_state->output_list, &state->link);
1726 else
1727 wl_list_init(&state->link);
1728
Daniel Stonebc15f682016-11-14 16:57:01 +00001729 wl_list_init(&state->plane_list);
1730
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001731 return state;
1732}
1733
1734/**
1735 * Duplicate an existing drm_output_state into a new one. This is generally
1736 * used during the repaint cycle, to capture the existing state of an output
1737 * and modify it to create a new state to be used.
1738 *
1739 * The mode determines whether the output will be reset to an a blank state,
1740 * or an exact mirror of the current state.
1741 */
1742static struct drm_output_state *
1743drm_output_state_duplicate(struct drm_output_state *src,
1744 struct drm_pending_state *pending_state,
1745 enum drm_output_state_duplicate_mode plane_mode)
1746{
1747 struct drm_output_state *dst = malloc(sizeof(*dst));
Daniel Stonebc15f682016-11-14 16:57:01 +00001748 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001749
1750 assert(dst);
1751
1752 /* Copy the whole structure, then individually modify the
1753 * pending_state, as well as the list link into our pending
1754 * state. */
1755 *dst = *src;
1756
1757 dst->pending_state = pending_state;
1758 if (pending_state)
1759 wl_list_insert(&pending_state->output_list, &dst->link);
1760 else
1761 wl_list_init(&dst->link);
1762
Daniel Stonebc15f682016-11-14 16:57:01 +00001763 wl_list_init(&dst->plane_list);
1764
1765 wl_list_for_each(ps, &src->plane_list, link) {
1766 /* Don't carry planes which are now disabled; these should be
1767 * free for other outputs to reuse. */
1768 if (!ps->output)
1769 continue;
1770
1771 if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
1772 (void) drm_plane_state_alloc(dst, ps->plane);
1773 else
1774 (void) drm_plane_state_duplicate(dst, ps);
1775 }
1776
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001777 return dst;
1778}
1779
1780/**
1781 * Free an unused drm_output_state.
1782 */
1783static void
1784drm_output_state_free(struct drm_output_state *state)
1785{
Daniel Stonebc15f682016-11-14 16:57:01 +00001786 struct drm_plane_state *ps, *next;
1787
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001788 if (!state)
1789 return;
1790
Daniel Stonebc15f682016-11-14 16:57:01 +00001791 wl_list_for_each_safe(ps, next, &state->plane_list, link)
1792 drm_plane_state_free(ps, false);
1793
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001794 wl_list_remove(&state->link);
Daniel Stonebc15f682016-11-14 16:57:01 +00001795
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001796 free(state);
Daniel Stone90648872016-10-21 18:08:37 +01001797}
1798
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001799/**
Daniel Stonea08512f2016-11-08 17:46:10 +00001800 * Get output state to disable output
1801 *
1802 * Returns a pointer to an output_state object which can be used to disable
1803 * an output (e.g. DPMS off).
1804 *
1805 * @param pending_state The pending state object owning this update
1806 * @param output The output to disable
1807 * @returns A drm_output_state to disable the output
1808 */
1809static struct drm_output_state *
1810drm_output_get_disable_state(struct drm_pending_state *pending_state,
1811 struct drm_output *output)
1812{
1813 struct drm_output_state *output_state;
1814
1815 output_state = drm_output_state_duplicate(output->state_cur,
1816 pending_state,
1817 DRM_OUTPUT_STATE_CLEAR_PLANES);
1818 output_state->dpms = WESTON_DPMS_OFF;
1819
1820 return output_state;
1821}
1822
1823/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001824 * Allocate a new drm_pending_state
1825 *
1826 * Allocate a new, empty, 'pending state' structure to be used across a
1827 * repaint cycle or similar.
1828 *
1829 * @param backend DRM backend
1830 * @returns Newly-allocated pending state structure
1831 */
1832static struct drm_pending_state *
1833drm_pending_state_alloc(struct drm_backend *backend)
1834{
1835 struct drm_pending_state *ret;
1836
1837 ret = calloc(1, sizeof(*ret));
1838 if (!ret)
1839 return NULL;
1840
1841 ret->backend = backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001842 wl_list_init(&ret->output_list);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001843
1844 return ret;
1845}
1846
1847/**
1848 * Free a drm_pending_state structure
1849 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001850 * Frees a pending_state structure, as well as any output_states connected
1851 * to this pending state.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001852 *
1853 * @param pending_state Pending state structure to free
1854 */
1855static void
1856drm_pending_state_free(struct drm_pending_state *pending_state)
1857{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001858 struct drm_output_state *output_state, *tmp;
1859
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001860 if (!pending_state)
1861 return;
1862
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001863 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1864 link) {
1865 drm_output_state_free(output_state);
1866 }
1867
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001868 free(pending_state);
1869}
1870
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001871/**
1872 * Find an output state in a pending state
1873 *
1874 * Given a pending_state structure, find the output_state for a particular
1875 * output.
1876 *
1877 * @param pending_state Pending state structure to search
1878 * @param output Output to find state for
1879 * @returns Output state if present, or NULL if not
1880 */
1881static struct drm_output_state *
1882drm_pending_state_get_output(struct drm_pending_state *pending_state,
1883 struct drm_output *output)
1884{
1885 struct drm_output_state *output_state;
1886
1887 wl_list_for_each(output_state, &pending_state->output_list, link) {
1888 if (output_state->output == output)
1889 return output_state;
1890 }
1891
1892 return NULL;
1893}
1894
Daniel Stonea08512f2016-11-08 17:46:10 +00001895static int drm_pending_state_apply_sync(struct drm_pending_state *state);
Daniel Stonebb6c19f2016-12-08 17:27:17 +00001896static int drm_pending_state_test(struct drm_pending_state *state);
Daniel Stonea08512f2016-11-08 17:46:10 +00001897
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001898/**
1899 * Mark a drm_output_state (the output's last state) as complete. This handles
1900 * any post-completion actions such as updating the repaint timer, disabling the
1901 * output, and finally freeing the state.
1902 */
1903static void
1904drm_output_update_complete(struct drm_output *output, uint32_t flags,
1905 unsigned int sec, unsigned int usec)
1906{
Daniel Stonea08512f2016-11-08 17:46:10 +00001907 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001908 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001909 struct timespec ts;
1910
1911 /* Stop the pageflip timer instead of rearming it here */
1912 if (output->pageflip_timer)
1913 wl_event_source_timer_update(output->pageflip_timer, 0);
1914
Daniel Stonebc15f682016-11-14 16:57:01 +00001915 wl_list_for_each(ps, &output->state_cur->plane_list, link)
1916 ps->complete = true;
1917
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001918 drm_output_state_free(output->state_last);
1919 output->state_last = NULL;
1920
1921 if (output->destroy_pending) {
Daniel Stonea08512f2016-11-08 17:46:10 +00001922 output->destroy_pending = 0;
1923 output->disable_pending = 0;
1924 output->dpms_off_pending = 0;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001925 drm_output_destroy(&output->base);
1926 return;
1927 } else if (output->disable_pending) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001928 output->disable_pending = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00001929 output->dpms_off_pending = 0;
1930 weston_output_disable(&output->base);
1931 return;
1932 } else if (output->dpms_off_pending) {
1933 struct drm_pending_state *pending = drm_pending_state_alloc(b);
1934 output->dpms_off_pending = 0;
1935 drm_output_get_disable_state(pending, output);
1936 drm_pending_state_apply_sync(pending);
Daniel Stonea08512f2016-11-08 17:46:10 +00001937 } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
1938 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
1939 /* DPMS can happen to us either in the middle of a repaint
1940 * cycle (when we have painted fresh content, only to throw it
1941 * away for DPMS off), or at any other random point. If the
1942 * latter is true, then we cannot go through finish_frame,
1943 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001944 return;
1945 }
1946
1947 ts.tv_sec = sec;
1948 ts.tv_nsec = usec * 1000;
1949 weston_output_finish_frame(&output->base, &ts, flags);
1950
1951 /* We can't call this from frame_notify, because the output's
1952 * repaint needed flag is cleared just after that */
1953 if (output->recorder)
1954 weston_output_schedule_repaint(&output->base);
1955}
1956
1957/**
1958 * Mark an output state as current on the output, i.e. it has been
1959 * submitted to the kernel. The mode argument determines whether this
1960 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
1961 * or asynchronously (in which case we wait for events to complete).
1962 */
1963static void
1964drm_output_assign_state(struct drm_output_state *state,
1965 enum drm_state_apply_mode mode)
1966{
1967 struct drm_output *output = state->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00001968 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001969 struct drm_plane_state *plane_state;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001970
1971 assert(!output->state_last);
1972
1973 if (mode == DRM_STATE_APPLY_ASYNC)
1974 output->state_last = output->state_cur;
1975 else
1976 drm_output_state_free(output->state_cur);
1977
1978 wl_list_remove(&state->link);
1979 wl_list_init(&state->link);
1980 state->pending_state = NULL;
1981
1982 output->state_cur = state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001983
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03001984 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
1985 drm_debug(b, "\t[CRTC:%u] setting pending flip\n", output->crtc_id);
Daniel Stone598ee9d2016-11-16 11:55:20 +00001986 output->atomic_complete_pending = 1;
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03001987 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00001988
Daniel Stonebc15f682016-11-14 16:57:01 +00001989 /* Replace state_cur on each affected plane with the new state, being
1990 * careful to dispose of orphaned (but only orphaned) previous state.
1991 * If the previous state is not orphaned (still has an output_state
1992 * attached), it will be disposed of by freeing the output_state. */
1993 wl_list_for_each(plane_state, &state->plane_list, link) {
1994 struct drm_plane *plane = plane_state->plane;
1995
1996 if (plane->state_cur && !plane->state_cur->output_state)
1997 drm_plane_state_free(plane->state_cur, true);
1998 plane->state_cur = plane_state;
1999
2000 if (mode != DRM_STATE_APPLY_ASYNC) {
2001 plane_state->complete = true;
2002 continue;
2003 }
2004
Daniel Stone598ee9d2016-11-16 11:55:20 +00002005 if (b->atomic_modeset)
2006 continue;
2007
Daniel Stonebc15f682016-11-14 16:57:01 +00002008 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
2009 output->vblank_pending++;
Daniel Stonee2e80132018-01-16 15:37:33 +00002010 else if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
2011 output->page_flip_pending = 1;
Daniel Stonebc15f682016-11-14 16:57:01 +00002012 }
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002013}
2014
Daniel Stonef8290622016-12-09 17:32:10 +00002015static struct drm_plane_state *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002016drm_output_prepare_scanout_view(struct drm_output_state *output_state,
Daniel Stonea284d272018-07-10 18:40:12 +01002017 struct weston_view *ev,
2018 enum drm_output_propose_state_mode mode)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05002019{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002020 struct drm_output *output = output_state->output;
Daniel Stone44abfaa2018-07-10 14:31:06 +01002021 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00002022 struct drm_plane *scanout_plane = output->scanout_plane;
2023 struct drm_plane_state *state;
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00002024 struct drm_fb *fb;
Daniel Stone7cdf2312016-11-16 19:40:29 +00002025 pixman_box32_t *extents;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05002026
Daniel Stone44abfaa2018-07-10 14:31:06 +01002027 assert(!b->sprites_are_broken);
Daniel Stone87fab1c2019-06-17 11:13:20 +01002028 assert(b->atomic_modeset);
Daniel Stonea284d272018-07-10 18:40:12 +01002029 assert(mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
Daniel Stone44abfaa2018-07-10 14:31:06 +01002030
Daniel Stone7cdf2312016-11-16 19:40:29 +00002031 /* Check the view spans exactly the output size, calculated in the
2032 * logical co-ordinate space. */
2033 extents = pixman_region32_extents(&ev->transform.boundingbox);
2034 if (extents->x1 != output->base.x ||
2035 extents->y1 != output->base.y ||
2036 extents->x2 != output->base.x + output->base.width ||
2037 extents->y2 != output->base.y + output->base.height)
Daniel Stone90648872016-10-21 18:08:37 +01002038 return NULL;
2039
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002040 /* If the surface buffer has an in-fence fd, but the plane doesn't
2041 * support fences, we can't place the buffer on this plane. */
2042 if (ev->surface->acquire_fence_fd >= 0 &&
Daniel Stone87fab1c2019-06-17 11:13:20 +01002043 scanout_plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0)
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002044 return NULL;
2045
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00002046 fb = drm_fb_get_from_view(output_state, ev);
Marius Vlad748f09e2018-12-18 10:29:20 +02002047 if (!fb) {
2048 drm_debug(b, "\t\t\t\t[scanout] not placing view %p on scanout: "
2049 " couldn't get fb\n", ev);
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00002050 return NULL;
Marius Vlad748f09e2018-12-18 10:29:20 +02002051 }
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00002052
Daniel Stonee2e80132018-01-16 15:37:33 +00002053 state = drm_output_state_get_plane(output_state, scanout_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +00002054
Daniel Stonea284d272018-07-10 18:40:12 +01002055 /* The only way we can already have a buffer in the scanout plane is
2056 * if we are in mixed mode, or if a client buffer has already been
2057 * placed into scanout. The former case will never call into here,
2058 * and in the latter case, the view must have been marked as occluded,
2059 * meaning we should never have ended up here. */
2060 assert(!state->fb);
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00002061 state->fb = fb;
Daniel Stoneee1aea72017-12-18 13:41:09 +00002062 state->ev = ev;
Daniel Stone7cdf2312016-11-16 19:40:29 +00002063 state->output = output;
2064 if (!drm_plane_state_coords_for_view(state, ev))
2065 goto err;
2066
Daniel Stone9fe4bf82016-12-09 18:23:22 +00002067 if (state->dest_x != 0 || state->dest_y != 0 ||
Daniel Stone7cdf2312016-11-16 19:40:29 +00002068 state->dest_w != (unsigned) output->base.current_mode->width ||
2069 state->dest_h != (unsigned) output->base.current_mode->height)
2070 goto err;
2071
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002072 state->in_fence_fd = ev->surface->acquire_fence_fd;
2073
Daniel Stonea284d272018-07-10 18:40:12 +01002074 /* In plane-only mode, we don't need to test the state now, as we
2075 * will only test it once at the end. */
Daniel Stonef8290622016-12-09 17:32:10 +00002076 return state;
Daniel Stone7cdf2312016-11-16 19:40:29 +00002077
2078err:
2079 drm_plane_state_put_back(state);
2080 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05002081}
2082
Daniel Stone95d48a22017-04-04 17:54:30 +01002083static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002084drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002085{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002086 struct drm_output *output = state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02002087 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002088 struct gbm_bo *bo;
Daniel Stone95d48a22017-04-04 17:54:30 +01002089 struct drm_fb *ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002090
Giulio Camuffo954f1832014-10-11 18:27:30 +03002091 output->base.compositor->renderer->repaint_output(&output->base,
2092 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002093
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01002094 bo = gbm_surface_lock_front_buffer(output->gbm_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002095 if (!bo) {
Antonio Borneo39578632019-04-26 23:57:31 +02002096 weston_log("failed to lock front buffer: %s\n",
2097 strerror(errno));
Daniel Stone95d48a22017-04-04 17:54:30 +01002098 return NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002099 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002100
Daniel Stonedb10df12016-12-08 13:15:58 +00002101 /* The renderer always produces an opaque image. */
2102 ret = drm_fb_get_from_bo(bo, b, true, BUFFER_GBM_SURFACE);
Daniel Stone95d48a22017-04-04 17:54:30 +01002103 if (!ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002104 weston_log("failed to get drm_fb for bo\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01002105 gbm_surface_release_buffer(output->gbm_surface, bo);
Daniel Stone95d48a22017-04-04 17:54:30 +01002106 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002107 }
Daniel Stone95d48a22017-04-04 17:54:30 +01002108 ret->gbm_surface = output->gbm_surface;
2109
2110 return ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002111}
2112
Daniel Stone95d48a22017-04-04 17:54:30 +01002113static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002114drm_output_render_pixman(struct drm_output_state *state,
2115 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002116{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002117 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002118 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002119
2120 output->current_image ^= 1;
2121
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002122 pixman_renderer_output_set_buffer(&output->base,
2123 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +02002124 pixman_renderer_output_set_hw_extra_damage(&output->base,
2125 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002126
Pekka Paalanenacf50c32018-04-23 11:44:56 +02002127 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002128
Pekka Paalanenacf50c32018-04-23 11:44:56 +02002129 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +01002130
2131 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002132}
2133
2134static void
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002135drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002136{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002137 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002138 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +00002139 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +00002140 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02002141 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +01002142 struct drm_fb *fb;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002143
Daniel Stone4e84f7d2017-04-04 17:54:29 +01002144 /* If we already have a client buffer promoted to scanout, then we don't
2145 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +00002146 scanout_state = drm_output_state_get_plane(state,
2147 output->scanout_plane);
2148 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +01002149 return;
2150
Daniel Stonee95169b2016-11-14 17:46:59 +00002151 if (!pixman_region32_not_empty(damage) &&
2152 scanout_plane->state_cur->fb &&
2153 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
2154 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
2155 scanout_plane->state_cur->fb->width ==
2156 output->base.current_mode->width &&
2157 scanout_plane->state_cur->fb->height ==
2158 output->base.current_mode->height) {
2159 fb = drm_fb_ref(scanout_plane->state_cur->fb);
2160 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002161 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00002162 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002163 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00002164 }
Daniel Stone95d48a22017-04-04 17:54:30 +01002165
Daniel Stonee2e80132018-01-16 15:37:33 +00002166 if (!fb) {
2167 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +01002168 return;
Daniel Stonee2e80132018-01-16 15:37:33 +00002169 }
2170
2171 scanout_state->fb = fb;
2172 scanout_state->output = output;
2173
2174 scanout_state->src_x = 0;
2175 scanout_state->src_y = 0;
2176 scanout_state->src_w = output->base.current_mode->width << 16;
2177 scanout_state->src_h = output->base.current_mode->height << 16;
2178
2179 scanout_state->dest_x = 0;
2180 scanout_state->dest_y = 0;
2181 scanout_state->dest_w = scanout_state->src_w >> 16;
2182 scanout_state->dest_h = scanout_state->src_h >> 16;
2183
Deepak Rawat46a1c722018-07-24 14:13:34 -07002184 pixman_region32_copy(&scanout_state->damage, damage);
2185 if (output->base.zoom.active) {
2186 weston_matrix_transform_region(&scanout_state->damage,
2187 &output->base.matrix,
2188 &scanout_state->damage);
2189 } else {
2190 pixman_region32_translate(&scanout_state->damage,
2191 -output->base.x, -output->base.y);
2192 weston_transformed_region(output->base.width,
2193 output->base.height,
2194 output->base.transform,
2195 output->base.current_scale,
2196 &scanout_state->damage,
2197 &scanout_state->damage);
2198 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002199
Giulio Camuffo954f1832014-10-11 18:27:30 +03002200 pixman_region32_subtract(&c->primary_plane.damage,
2201 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002202}
2203
2204static void
Richard Hughese7299962013-05-01 21:52:12 +01002205drm_output_set_gamma(struct weston_output *output_base,
2206 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
2207{
2208 int rc;
Armin Krezović545dba62016-08-05 15:54:18 +02002209 struct drm_output *output = to_drm_output(output_base);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002210 struct drm_backend *backend =
Armin Krezović545dba62016-08-05 15:54:18 +02002211 to_drm_backend(output->base.compositor);
Richard Hughese7299962013-05-01 21:52:12 +01002212
2213 /* check */
2214 if (output_base->gamma_size != size)
2215 return;
Richard Hughese7299962013-05-01 21:52:12 +01002216
Giulio Camuffo954f1832014-10-11 18:27:30 +03002217 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +01002218 output->crtc_id,
2219 size, r, g, b);
2220 if (rc)
Antonio Borneo39578632019-04-26 23:57:31 +02002221 weston_log("set gamma failed: %s\n", strerror(errno));
Richard Hughese7299962013-05-01 21:52:12 +01002222}
2223
Bryce Harringtonada4f072015-06-30 13:25:46 -07002224/* Determine the type of vblank synchronization to use for the output.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002225 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07002226 * The pipe parameter indicates which CRTC is in use. Knowing this, we
2227 * can determine which vblank sequence type to use for it. Traditional
2228 * cards had only two CRTCs, with CRTC 0 using no special flags, and
2229 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
2230 * parameter indicates this.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002231 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07002232 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
2233 * 0-31. If this is non-zero it indicates we're dealing with a
2234 * multi-gpu situation and we need to calculate the vblank sync
2235 * using DRM_BLANK_HIGH_CRTC_MASK.
2236 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +03002237static unsigned int
2238drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02002239{
2240 if (output->pipe > 1)
2241 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
2242 DRM_VBLANK_HIGH_CRTC_MASK;
2243 else if (output->pipe > 0)
2244 return DRM_VBLANK_SECONDARY;
2245 else
2246 return 0;
2247}
2248
David Herrmann1edf44c2013-10-22 17:11:26 +02002249static int
Daniel Stone598ee9d2016-11-16 11:55:20 +00002250drm_output_apply_state_legacy(struct drm_output_state *state)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002251{
Daniel Stonea08512f2016-11-08 17:46:10 +00002252 struct drm_output *output = state->output;
2253 struct drm_backend *backend = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00002254 struct drm_plane *scanout_plane = output->scanout_plane;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002255 struct drm_property_info *dpms_prop;
Daniel Stonee2e80132018-01-16 15:37:33 +00002256 struct drm_plane_state *scanout_state;
Daniel Stonebc15f682016-11-14 16:57:01 +00002257 struct drm_plane_state *ps;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002258 struct drm_mode *mode;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002259 struct drm_head *head;
Marius Vlad1ca025c2019-01-09 12:26:07 +02002260 const struct pixel_format_info *pinfo = NULL;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002261 uint32_t connectors[MAX_CLONED_CONNECTORS];
2262 int n_conn = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00002263 struct timespec now;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002264 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002265
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002266 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2267 assert(n_conn < MAX_CLONED_CONNECTORS);
2268 connectors[n_conn++] = head->connector_id;
2269 }
2270
Derek Foreman2cd87fe2017-04-13 13:48:48 -05002271 /* If disable_planes is set then assign_planes() wasn't
2272 * called for this render, so we could still have a stale
2273 * cursor plane set up.
2274 */
2275 if (output->base.disable_planes) {
2276 output->cursor_view = NULL;
Greg V1f781762018-02-19 17:59:42 +03002277 if (output->cursor_plane) {
2278 output->cursor_plane->base.x = INT32_MIN;
2279 output->cursor_plane->base.y = INT32_MIN;
2280 }
Derek Foreman2cd87fe2017-04-13 13:48:48 -05002281 }
2282
Daniel Stonea08512f2016-11-08 17:46:10 +00002283 if (state->dpms != WESTON_DPMS_ON) {
2284 wl_list_for_each(ps, &state->plane_list, link) {
Daniel Stonef8290622016-12-09 17:32:10 +00002285 struct drm_plane *p = ps->plane;
Daniel Stonea08512f2016-11-08 17:46:10 +00002286 assert(ps->fb == NULL);
2287 assert(ps->output == NULL);
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002288
Daniel Stonea08512f2016-11-08 17:46:10 +00002289 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2290 continue;
2291
2292 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
2293 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2294 if (ret)
Antonio Borneo39578632019-04-26 23:57:31 +02002295 weston_log("drmModeSetPlane failed disable: %s\n",
2296 strerror(errno));
Daniel Stonea08512f2016-11-08 17:46:10 +00002297 }
2298
2299 if (output->cursor_plane) {
2300 ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
2301 0, 0, 0);
2302 if (ret)
Antonio Borneo39578632019-04-26 23:57:31 +02002303 weston_log("drmModeSetCursor failed disable: %s\n",
2304 strerror(errno));
Daniel Stonea08512f2016-11-08 17:46:10 +00002305 }
2306
2307 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002308 NULL, 0, NULL);
Daniel Stonea08512f2016-11-08 17:46:10 +00002309 if (ret)
Antonio Borneo39578632019-04-26 23:57:31 +02002310 weston_log("drmModeSetCrtc failed disabling: %s\n",
2311 strerror(errno));
Daniel Stonea08512f2016-11-08 17:46:10 +00002312
2313 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
2314 weston_compositor_read_presentation_clock(output->base.compositor, &now);
2315 drm_output_update_complete(output,
2316 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
2317 now.tv_sec, now.tv_nsec / 1000);
2318
2319 return 0;
2320 }
2321
2322 scanout_state =
2323 drm_output_state_get_existing_plane(state, scanout_plane);
Daniel Stone087ddf02017-02-14 17:51:30 +00002324
Daniel Stonee2e80132018-01-16 15:37:33 +00002325 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
2326 * legacy PageFlip API doesn't allow us to do clipping either. */
2327 assert(scanout_state->src_x == 0);
2328 assert(scanout_state->src_y == 0);
2329 assert(scanout_state->src_w ==
2330 (unsigned) (output->base.current_mode->width << 16));
2331 assert(scanout_state->src_h ==
2332 (unsigned) (output->base.current_mode->height << 16));
2333 assert(scanout_state->dest_x == 0);
2334 assert(scanout_state->dest_y == 0);
2335 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
2336 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002337 /* The legacy SetCrtc API doesn't support fences */
2338 assert(scanout_state->in_fence_fd == -1);
Daniel Stonee2e80132018-01-16 15:37:33 +00002339
Daniel Stonecb04cc42016-11-16 11:51:27 +00002340 mode = to_drm_mode(output->base.current_mode);
Daniel Stone8eece0c2016-11-17 17:54:00 +00002341 if (backend->state_invalid ||
2342 !scanout_plane->state_cur->fb ||
2343 scanout_plane->state_cur->fb->strides[0] !=
2344 scanout_state->fb->strides[0]) {
Marius Vlad1ca025c2019-01-09 12:26:07 +02002345
Giulio Camuffo954f1832014-10-11 18:27:30 +03002346 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00002347 scanout_state->fb->fb_id,
2348 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002349 connectors, n_conn,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002350 &mode->mode_info);
2351 if (ret) {
Antonio Borneo39578632019-04-26 23:57:31 +02002352 weston_log("set mode failed: %s\n", strerror(errno));
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002353 goto err;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002354 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02002355 }
2356
Marius Vlad1ca025c2019-01-09 12:26:07 +02002357 pinfo = scanout_state->fb->format;
2358 drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
2359 output->crtc_id, scanout_state->plane->plane_id,
2360 pinfo ? pinfo->drm_format_name : "UNKNOWN");
2361
Giulio Camuffo954f1832014-10-11 18:27:30 +03002362 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00002363 scanout_state->fb->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05002364 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002365 weston_log("queueing pageflip failed: %s\n", strerror(errno));
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002366 goto err;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05002367 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002368
Daniel Stone205c0a02017-04-04 17:54:33 +01002369 assert(!output->page_flip_pending);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002370
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002371 if (output->pageflip_timer)
2372 wl_event_source_timer_update(output->pageflip_timer,
2373 backend->pageflip_timeout);
2374
Daniel Stone2ba17f42015-05-19 20:02:41 +01002375 drm_output_set_cursor(state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04002376
Jesse Barnes58ef3792012-02-23 09:45:49 -05002377 /*
2378 * Now, update all the sprite surfaces
2379 */
Daniel Stonebc15f682016-11-14 16:57:01 +00002380 wl_list_for_each(ps, &state->plane_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002381 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002382 drmVBlank vbl = {
2383 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
2384 .request.sequence = 1,
2385 };
Daniel Stonef8290622016-12-09 17:32:10 +00002386 struct drm_plane *p = ps->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002387
Daniel Stone085d2b92015-05-21 00:00:57 +01002388 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002389 continue;
2390
Daniel Stonebc15f682016-11-14 16:57:01 +00002391 assert(p->state_cur->complete);
2392 assert(!!p->state_cur->output == !!p->state_cur->fb);
2393 assert(!p->state_cur->output || p->state_cur->output == output);
2394 assert(!ps->complete);
2395 assert(!ps->output || ps->output == output);
2396 assert(!!ps->output == !!ps->fb);
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002397 /* The legacy SetPlane API doesn't support fences */
2398 assert(ps->in_fence_fd == -1);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002399
Daniel Stonebc15f682016-11-14 16:57:01 +00002400 if (ps->fb && !backend->sprites_hidden)
2401 fb_id = ps->fb->fb_id;
Daniel Stone085d2b92015-05-21 00:00:57 +01002402
2403 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002404 output->crtc_id, fb_id, flags,
Daniel Stonebc15f682016-11-14 16:57:01 +00002405 ps->dest_x, ps->dest_y,
2406 ps->dest_w, ps->dest_h,
2407 ps->src_x, ps->src_y,
2408 ps->src_w, ps->src_h);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002409 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +02002410 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002411 ret, strerror(errno));
2412
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02002413 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -05002414
Jesse Barnes58ef3792012-02-23 09:45:49 -05002415 /*
2416 * Queue a vblank signal so we know when the surface
2417 * becomes active on the display or has been replaced.
2418 */
Daniel Stonebc15f682016-11-14 16:57:01 +00002419 vbl.request.signal = (unsigned long) ps;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002420 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002421 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002422 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002423 ret, strerror(errno));
2424 }
2425 }
2426
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002427 if (state->dpms != output->state_cur->dpms) {
2428 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2429 dpms_prop = &head->props_conn[WDRM_CONNECTOR_DPMS];
2430 if (dpms_prop->prop_id == 0)
2431 continue;
2432
2433 ret = drmModeConnectorSetProperty(backend->drm.fd,
2434 head->connector_id,
2435 dpms_prop->prop_id,
2436 state->dpms);
2437 if (ret) {
2438 weston_log("DRM: DPMS: failed property set for %s\n",
2439 head->base.name);
2440 }
Daniel Stonea08512f2016-11-08 17:46:10 +00002441 }
2442 }
2443
2444 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
2445
David Herrmann1edf44c2013-10-22 17:11:26 +02002446 return 0;
2447
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002448err:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -08002449 output->cursor_view = NULL;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002450 drm_output_state_free(state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002451 return -1;
2452}
David Herrmann1edf44c2013-10-22 17:11:26 +02002453
Daniel Stone598ee9d2016-11-16 11:55:20 +00002454#ifdef HAVE_DRM_ATOMIC
2455static int
2456crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
2457 enum wdrm_crtc_property prop, uint64_t val)
2458{
2459 struct drm_property_info *info = &output->props_crtc[prop];
2460 int ret;
2461
2462 if (info->prop_id == 0)
2463 return -1;
2464
2465 ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
2466 val);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002467 drm_debug(output->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
2468 (unsigned long) output->crtc_id,
2469 (unsigned long) info->prop_id, info->name,
2470 (unsigned long long) val, (unsigned long long) val);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002471 return (ret <= 0) ? -1 : 0;
2472}
2473
2474static int
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002475connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002476 enum wdrm_connector_property prop, uint64_t val)
2477{
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002478 struct drm_property_info *info = &head->props_conn[prop];
Daniel Stone598ee9d2016-11-16 11:55:20 +00002479 int ret;
2480
2481 if (info->prop_id == 0)
2482 return -1;
2483
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002484 ret = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002485 info->prop_id, val);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002486 drm_debug(head->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
2487 (unsigned long) head->connector_id,
2488 (unsigned long) info->prop_id, info->name,
2489 (unsigned long long) val, (unsigned long long) val);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002490 return (ret <= 0) ? -1 : 0;
2491}
2492
2493static int
2494plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
2495 enum wdrm_plane_property prop, uint64_t val)
2496{
2497 struct drm_property_info *info = &plane->props[prop];
2498 int ret;
2499
2500 if (info->prop_id == 0)
2501 return -1;
2502
2503 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
2504 val);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002505 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
2506 (unsigned long) plane->plane_id,
2507 (unsigned long) info->prop_id, info->name,
2508 (unsigned long long) val, (unsigned long long) val);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002509 return (ret <= 0) ? -1 : 0;
2510}
2511
2512static int
2513drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
2514{
2515 int ret;
2516
2517 if (mode->blob_id)
2518 return 0;
2519
2520 ret = drmModeCreatePropertyBlob(backend->drm.fd,
2521 &mode->mode_info,
2522 sizeof(mode->mode_info),
2523 &mode->blob_id);
2524 if (ret != 0)
Antonio Borneo39578632019-04-26 23:57:31 +02002525 weston_log("failed to create mode property blob: %s\n",
2526 strerror(errno));
Daniel Stone598ee9d2016-11-16 11:55:20 +00002527
Daniel Stone2914a6d2019-02-16 16:16:10 +00002528 drm_debug(backend, "\t\t\t[atomic] created new mode blob %lu for %s\n",
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002529 (unsigned long) mode->blob_id, mode->mode_info.name);
2530
Daniel Stone598ee9d2016-11-16 11:55:20 +00002531 return ret;
2532}
2533
2534static int
Deepak Rawat009b3cf2018-07-24 14:05:37 -07002535plane_add_damage(drmModeAtomicReq *req, struct drm_backend *backend,
2536 struct drm_plane_state *plane_state)
2537{
2538 struct drm_plane *plane = plane_state->plane;
2539 struct drm_property_info *info =
2540 &plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
2541 pixman_box32_t *rects;
2542 uint32_t blob_id;
2543 int n_rects;
2544 int ret;
2545
2546 if (!pixman_region32_not_empty(&plane_state->damage))
2547 return 0;
2548
2549 /*
2550 * If a plane doesn't support fb damage blob property, kernel will
2551 * perform full plane update.
2552 */
2553 if (info->prop_id == 0)
2554 return 0;
2555
2556 rects = pixman_region32_rectangles(&plane_state->damage, &n_rects);
2557
2558 ret = drmModeCreatePropertyBlob(backend->drm.fd, rects,
2559 sizeof(*rects) * n_rects, &blob_id);
2560 if (ret != 0)
2561 return ret;
2562
2563 ret = plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS, blob_id);
2564 if (ret != 0)
2565 return ret;
2566
2567 return 0;
2568}
2569
2570static int
Daniel Stone598ee9d2016-11-16 11:55:20 +00002571drm_output_apply_state_atomic(struct drm_output_state *state,
2572 drmModeAtomicReq *req,
2573 uint32_t *flags)
2574{
2575 struct drm_output *output = state->output;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002576 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002577 struct drm_plane_state *plane_state;
2578 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002579 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002580 int ret = 0;
2581
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002582 drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
2583 (*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
2584 (unsigned long) output->base.id, output->base.name);
2585
2586 if (state->dpms != output->state_cur->dpms) {
2587 drm_debug(b, "\t\t\t[atomic] DPMS state differs, modeset OK\n");
Daniel Stone598ee9d2016-11-16 11:55:20 +00002588 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002589 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00002590
2591 if (state->dpms == WESTON_DPMS_ON) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002592 ret = drm_mode_ensure_blob(b, current_mode);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002593 if (ret != 0)
2594 return ret;
2595
2596 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
2597 current_mode->blob_id);
2598 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002599
Daniel Stone76255772018-07-06 11:36:49 +01002600 /* No need for the DPMS property, since it is implicit in
2601 * routing and CRTC activity. */
Pekka Paalanen2f661302017-09-12 16:07:32 +03002602 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2603 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
2604 output->crtc_id);
2605 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00002606 } else {
2607 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
2608 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002609
Daniel Stone76255772018-07-06 11:36:49 +01002610 /* No need for the DPMS property, since it is implicit in
2611 * routing and CRTC activity. */
Pekka Paalanen2f661302017-09-12 16:07:32 +03002612 wl_list_for_each(head, &output->base.head_list, base.output_link)
2613 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002614 }
2615
2616 if (ret != 0) {
2617 weston_log("couldn't set atomic CRTC/connector state\n");
2618 return ret;
2619 }
2620
2621 wl_list_for_each(plane_state, &state->plane_list, link) {
2622 struct drm_plane *plane = plane_state->plane;
Marius Vlad1ca025c2019-01-09 12:26:07 +02002623 const struct pixel_format_info *pinfo = NULL;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002624
2625 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
2626 plane_state->fb ? plane_state->fb->fb_id : 0);
2627 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
2628 plane_state->fb ? output->crtc_id : 0);
2629 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
2630 plane_state->src_x);
2631 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
2632 plane_state->src_y);
2633 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
2634 plane_state->src_w);
2635 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
2636 plane_state->src_h);
2637 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
2638 plane_state->dest_x);
2639 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
2640 plane_state->dest_y);
2641 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
2642 plane_state->dest_w);
2643 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
2644 plane_state->dest_h);
Deepak Rawat009b3cf2018-07-24 14:05:37 -07002645 ret |= plane_add_damage(req, b, plane_state);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002646
Marius Vlad1ca025c2019-01-09 12:26:07 +02002647 if (plane_state->fb && plane_state->fb->format)
2648 pinfo = plane_state->fb->format;
2649
2650 drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
2651 (unsigned long) plane->plane_id,
2652 pinfo ? pinfo->drm_format_name : "UNKNOWN");
2653
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03002654 if (plane_state->in_fence_fd >= 0) {
2655 ret |= plane_add_prop(req, plane,
2656 WDRM_PLANE_IN_FENCE_FD,
2657 plane_state->in_fence_fd);
2658 }
2659
Daniel Stone598ee9d2016-11-16 11:55:20 +00002660 if (ret != 0) {
2661 weston_log("couldn't set plane state\n");
2662 return ret;
2663 }
2664 }
2665
2666 return 0;
2667}
2668
2669/**
2670 * Helper function used only by drm_pending_state_apply, with the same
2671 * guarantees and constraints as that function.
2672 */
2673static int
2674drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
2675 enum drm_state_apply_mode mode)
2676{
2677 struct drm_backend *b = pending_state->backend;
2678 struct drm_output_state *output_state, *tmp;
2679 struct drm_plane *plane;
2680 drmModeAtomicReq *req = drmModeAtomicAlloc();
Daniel Stone3158a2d2018-07-20 19:35:05 +01002681 uint32_t flags;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002682 int ret = 0;
2683
2684 if (!req)
2685 return -1;
2686
Daniel Stone3158a2d2018-07-20 19:35:05 +01002687 switch (mode) {
2688 case DRM_STATE_APPLY_SYNC:
2689 flags = 0;
2690 break;
2691 case DRM_STATE_APPLY_ASYNC:
2692 flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
2693 break;
2694 case DRM_STATE_TEST_ONLY:
2695 flags = DRM_MODE_ATOMIC_TEST_ONLY;
2696 break;
2697 }
2698
Daniel Stone598ee9d2016-11-16 11:55:20 +00002699 if (b->state_invalid) {
Pekka Paalaneneacec812017-09-12 13:43:51 +03002700 struct weston_head *head_base;
2701 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002702 uint32_t *unused;
2703 int err;
2704
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002705 drm_debug(b, "\t\t[atomic] previous state invalid; "
2706 "starting with fresh state\n");
2707
Daniel Stone598ee9d2016-11-16 11:55:20 +00002708 /* If we need to reset all our state (e.g. because we've
2709 * just started, or just been VT-switched in), explicitly
2710 * disable all the CRTCs and connectors we aren't using. */
Pekka Paalaneneacec812017-09-12 13:43:51 +03002711 wl_list_for_each(head_base,
2712 &b->compositor->head_list, compositor_link) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00002713 struct drm_property_info *info;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002714
Pekka Paalaneneacec812017-09-12 13:43:51 +03002715 if (weston_head_is_enabled(head_base))
Daniel Stone598ee9d2016-11-16 11:55:20 +00002716 continue;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002717
Pekka Paalaneneacec812017-09-12 13:43:51 +03002718 head = to_drm_head(head_base);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002719
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002720 drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
2721 head_base->name);
2722
Pekka Paalaneneacec812017-09-12 13:43:51 +03002723 info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
2724 err = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002725 info->prop_id, 0);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002726 drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
2727 (unsigned long) head->connector_id,
2728 (unsigned long) info->prop_id,
2729 info->name);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002730 if (err <= 0)
2731 ret = -1;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002732 }
2733
2734 wl_array_for_each(unused, &b->unused_crtcs) {
2735 struct drm_property_info infos[WDRM_CRTC__COUNT];
2736 struct drm_property_info *info;
2737 drmModeObjectProperties *props;
2738 uint64_t active;
2739
2740 memset(infos, 0, sizeof(infos));
2741
2742 /* We can't emit a disable on a CRTC that's already
2743 * off, as the kernel will refuse to generate an event
2744 * for an off->off state and fail the commit.
2745 */
2746 props = drmModeObjectGetProperties(b->drm.fd,
2747 *unused,
2748 DRM_MODE_OBJECT_CRTC);
2749 if (!props) {
2750 ret = -1;
2751 continue;
2752 }
2753
2754 drm_property_info_populate(b, crtc_props, infos,
2755 WDRM_CRTC__COUNT,
2756 props);
2757
2758 info = &infos[WDRM_CRTC_ACTIVE];
2759 active = drm_property_get_value(info, props, 0);
2760 drmModeFreeObjectProperties(props);
2761 if (active == 0) {
2762 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2763 continue;
2764 }
2765
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002766 drm_debug(b, "\t\t[atomic] disabling unused CRTC %lu\n",
2767 (unsigned long) *unused);
2768
2769 drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
2770 (unsigned long) *unused,
2771 (unsigned long) info->prop_id, info->name);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002772 err = drmModeAtomicAddProperty(req, *unused,
2773 info->prop_id, 0);
2774 if (err <= 0)
2775 ret = -1;
2776
2777 info = &infos[WDRM_CRTC_MODE_ID];
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002778 drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> 0\n",
2779 (unsigned long) *unused,
2780 (unsigned long) info->prop_id, info->name);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002781 err = drmModeAtomicAddProperty(req, *unused,
2782 info->prop_id, 0);
2783 if (err <= 0)
2784 ret = -1;
2785
2786 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2787 }
2788
2789 /* Disable all the planes; planes which are being used will
2790 * override this state in the output-state application. */
2791 wl_list_for_each(plane, &b->plane_list, link) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002792 drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
2793 (unsigned long) plane->plane_id);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002794 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
2795 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
2796 }
2797
2798 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2799 }
2800
2801 wl_list_for_each(output_state, &pending_state->output_list, link) {
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002802 if (output_state->output->virtual)
2803 continue;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002804 if (mode == DRM_STATE_APPLY_SYNC)
2805 assert(output_state->dpms == WESTON_DPMS_OFF);
2806 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
2807 }
2808
2809 if (ret != 0) {
2810 weston_log("atomic: couldn't compile atomic state\n");
2811 goto out;
2812 }
2813
Daniel Stone598ee9d2016-11-16 11:55:20 +00002814 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03002815 drm_debug(b, "[atomic] drmModeAtomicCommit\n");
Daniel Stonebb6c19f2016-12-08 17:27:17 +00002816
2817 /* Test commits do not take ownership of the state; return
2818 * without freeing here. */
2819 if (mode == DRM_STATE_TEST_ONLY) {
2820 drmModeAtomicFree(req);
2821 return ret;
2822 }
2823
Daniel Stone598ee9d2016-11-16 11:55:20 +00002824 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002825 weston_log("atomic: couldn't commit new state: %s\n",
2826 strerror(errno));
Daniel Stone598ee9d2016-11-16 11:55:20 +00002827 goto out;
2828 }
2829
2830 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2831 link)
2832 drm_output_assign_state(output_state, mode);
2833
2834 b->state_invalid = false;
2835
2836 assert(wl_list_empty(&pending_state->output_list));
2837
2838out:
2839 drmModeAtomicFree(req);
2840 drm_pending_state_free(pending_state);
2841 return ret;
2842}
2843#endif
2844
Daniel Stonea08512f2016-11-08 17:46:10 +00002845/**
Daniel Stonebb6c19f2016-12-08 17:27:17 +00002846 * Tests a pending state, to see if the kernel will accept the update as
2847 * constructed.
2848 *
2849 * Using atomic modesetting, the kernel performs the same checks as it would
2850 * on a real commit, returning success or failure without actually modifying
2851 * the running state. It does not return -EBUSY if there are pending updates
2852 * in flight, so states may be tested at any point, however this means a
2853 * state which passed testing may fail on a real commit if the timing is not
2854 * respected (e.g. committing before the previous commit has completed).
2855 *
2856 * Without atomic modesetting, we have no way to check, so we optimistically
2857 * claim it will work.
2858 *
2859 * Unlike drm_pending_state_apply() and drm_pending_state_apply_sync(), this
2860 * function does _not_ take ownership of pending_state, nor does it clear
2861 * state_invalid.
2862 */
2863static int
2864drm_pending_state_test(struct drm_pending_state *pending_state)
2865{
2866#ifdef HAVE_DRM_ATOMIC
2867 struct drm_backend *b = pending_state->backend;
2868
2869 if (b->atomic_modeset)
2870 return drm_pending_state_apply_atomic(pending_state,
2871 DRM_STATE_TEST_ONLY);
2872#endif
2873
2874 /* We have no way to test state before application on the legacy
2875 * modesetting API, so just claim it succeeded. */
2876 return 0;
2877}
2878
2879/**
Daniel Stonea08512f2016-11-08 17:46:10 +00002880 * Applies all of a pending_state asynchronously: the primary entry point for
2881 * applying KMS state to a device. Updates the state for all outputs in the
2882 * pending_state, as well as disabling any unclaimed outputs.
2883 *
2884 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2885 */
2886static int
2887drm_pending_state_apply(struct drm_pending_state *pending_state)
2888{
2889 struct drm_backend *b = pending_state->backend;
2890 struct drm_output_state *output_state, *tmp;
2891 uint32_t *unused;
2892
Daniel Stone598ee9d2016-11-16 11:55:20 +00002893#ifdef HAVE_DRM_ATOMIC
2894 if (b->atomic_modeset)
2895 return drm_pending_state_apply_atomic(pending_state,
2896 DRM_STATE_APPLY_ASYNC);
2897#endif
2898
Daniel Stonea08512f2016-11-08 17:46:10 +00002899 if (b->state_invalid) {
2900 /* If we need to reset all our state (e.g. because we've
2901 * just started, or just been VT-switched in), explicitly
2902 * disable all the CRTCs we aren't using. This also disables
2903 * all connectors on these CRTCs, so we don't need to do that
2904 * separately with the pre-atomic API. */
2905 wl_array_for_each(unused, &b->unused_crtcs)
2906 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2907 NULL);
2908 }
2909
2910 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2911 link) {
2912 struct drm_output *output = output_state->output;
2913 int ret;
2914
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002915 if (output->virtual) {
2916 drm_output_assign_state(output_state,
2917 DRM_STATE_APPLY_ASYNC);
2918 continue;
2919 }
2920
Daniel Stone598ee9d2016-11-16 11:55:20 +00002921 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002922 if (ret != 0) {
2923 weston_log("Couldn't apply state for output %s\n",
2924 output->base.name);
2925 }
2926 }
2927
2928 b->state_invalid = false;
2929
2930 assert(wl_list_empty(&pending_state->output_list));
2931
2932 drm_pending_state_free(pending_state);
2933
2934 return 0;
2935}
2936
2937/**
2938 * The synchronous version of drm_pending_state_apply. May only be used to
2939 * disable outputs. Does so synchronously: the request is guaranteed to have
2940 * completed on return, and the output will not be touched afterwards.
2941 *
2942 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2943 */
2944static int
2945drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
2946{
2947 struct drm_backend *b = pending_state->backend;
2948 struct drm_output_state *output_state, *tmp;
2949 uint32_t *unused;
2950
Daniel Stone598ee9d2016-11-16 11:55:20 +00002951#ifdef HAVE_DRM_ATOMIC
2952 if (b->atomic_modeset)
2953 return drm_pending_state_apply_atomic(pending_state,
2954 DRM_STATE_APPLY_SYNC);
2955#endif
2956
Daniel Stonea08512f2016-11-08 17:46:10 +00002957 if (b->state_invalid) {
2958 /* If we need to reset all our state (e.g. because we've
2959 * just started, or just been VT-switched in), explicitly
2960 * disable all the CRTCs we aren't using. This also disables
2961 * all connectors on these CRTCs, so we don't need to do that
2962 * separately with the pre-atomic API. */
2963 wl_array_for_each(unused, &b->unused_crtcs)
2964 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2965 NULL);
2966 }
2967
2968 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2969 link) {
2970 int ret;
2971
2972 assert(output_state->dpms == WESTON_DPMS_OFF);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002973 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002974 if (ret != 0) {
2975 weston_log("Couldn't apply state for output %s\n",
2976 output_state->output->base.name);
2977 }
2978 }
2979
2980 b->state_invalid = false;
2981
2982 assert(wl_list_empty(&pending_state->output_list));
2983
2984 drm_pending_state_free(pending_state);
2985
2986 return 0;
2987}
2988
2989static int
2990drm_output_repaint(struct weston_output *output_base,
2991 pixman_region32_t *damage,
2992 void *repaint_data)
2993{
2994 struct drm_pending_state *pending_state = repaint_data;
2995 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00002996 struct drm_output_state *state = NULL;
2997 struct drm_plane_state *scanout_state;
2998
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09002999 assert(!output->virtual);
3000
Daniel Stonea08512f2016-11-08 17:46:10 +00003001 if (output->disable_pending || output->destroy_pending)
3002 goto err;
3003
3004 assert(!output->state_last);
3005
3006 /* If planes have been disabled in the core, we might not have
3007 * hit assign_planes at all, so might not have valid output state
3008 * here. */
3009 state = drm_pending_state_get_output(pending_state, output);
3010 if (!state)
3011 state = drm_output_state_duplicate(output->state_cur,
3012 pending_state,
3013 DRM_OUTPUT_STATE_CLEAR_PLANES);
3014 state->dpms = WESTON_DPMS_ON;
3015
3016 drm_output_render(state, damage);
3017 scanout_state = drm_output_state_get_plane(state,
3018 output->scanout_plane);
3019 if (!scanout_state || !scanout_state->fb)
3020 goto err;
3021
Daniel Stonea08512f2016-11-08 17:46:10 +00003022 return 0;
3023
3024err:
3025 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +02003026 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003027}
3028
3029static void
Jonas Ådahle5a12252013-04-05 23:07:11 +02003030drm_output_start_repaint_loop(struct weston_output *output_base)
3031{
Armin Krezović545dba62016-08-05 15:54:18 +02003032 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +00003033 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +00003034 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02003035 struct drm_backend *backend =
3036 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +02003037 struct timespec ts, tnow;
3038 struct timespec vbl2now;
3039 int64_t refresh_nsec;
3040 int ret;
3041 drmVBlank vbl = {
3042 .request.type = DRM_VBLANK_RELATIVE,
3043 .request.sequence = 0,
3044 .request.signal = 0,
3045 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003046
Armin Krezović08368132016-09-30 14:11:05 +02003047 if (output->disable_pending || output->destroy_pending)
Xiong Zhangabd5d472013-10-11 14:43:07 +08003048 return;
3049
Daniel Stonee2e80132018-01-16 15:37:33 +00003050 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003051 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +02003052 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003053 }
3054
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03003055 /* Need to smash all state in from scratch; current timings might not
3056 * be what we want, page flip might not work, etc.
3057 */
Daniel Stone6020f472018-02-05 15:46:20 +00003058 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03003059 goto finish_frame;
3060
Daniel Stonee2e80132018-01-16 15:37:33 +00003061 assert(scanout_plane->state_cur->output == output);
3062
Mario Kleinerf507ec32015-06-21 21:25:14 +02003063 /* Try to get current msc and timestamp via instant query */
3064 vbl.request.type |= drm_waitvblank_pipe(output);
3065 ret = drmWaitVBlank(backend->drm.fd, &vbl);
3066
3067 /* Error ret or zero timestamp means failure to get valid timestamp */
3068 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
3069 ts.tv_sec = vbl.reply.tval_sec;
3070 ts.tv_nsec = vbl.reply.tval_usec * 1000;
3071
3072 /* Valid timestamp for most recent vblank - not stale?
3073 * Stale ts could happen on Linux 3.17+, so make sure it
3074 * is not older than 1 refresh duration since now.
3075 */
3076 weston_compositor_read_presentation_clock(backend->compositor,
3077 &tnow);
3078 timespec_sub(&vbl2now, &tnow, &ts);
3079 refresh_nsec =
3080 millihz_to_nsec(output->base.current_mode->refresh);
3081 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
3082 drm_output_update_msc(output, vbl.reply.sequence);
3083 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02003084 WP_PRESENTATION_FEEDBACK_INVALID);
Mario Kleinerf507ec32015-06-21 21:25:14 +02003085 return;
3086 }
3087 }
3088
3089 /* Immediate query didn't provide valid timestamp.
3090 * Use pageflip fallback.
3091 */
Jonas Ådahle5a12252013-04-05 23:07:11 +02003092
Daniel Stone205c0a02017-04-04 17:54:33 +01003093 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003094 assert(!output->state_last);
3095
3096 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +00003097 drm_output_state_duplicate(output->state_cur, pending_state,
3098 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +01003099
Daniel Stone8747f952016-11-29 20:17:32 +00003100 ret = drm_pending_state_apply(pending_state);
3101 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02003102 weston_log("applying repaint-start state failed: %s\n",
3103 strerror(errno));
David Herrmann3c688c52013-10-22 17:11:25 +02003104 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +02003105 }
David Herrmann3c688c52013-10-22 17:11:25 +02003106
3107 return;
3108
3109finish_frame:
3110 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +00003111 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02003112 WP_PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +02003113}
3114
3115static void
Pekka Paalanen641307c2014-09-23 22:08:47 -04003116drm_output_update_msc(struct drm_output *output, unsigned int seq)
3117{
3118 uint64_t msc_hi = output->base.msc >> 32;
3119
3120 if (seq < (output->base.msc & 0xffffffff))
3121 msc_hi++;
3122
3123 output->base.msc = (msc_hi << 32) + seq;
3124}
3125
3126static void
Jesse Barnes58ef3792012-02-23 09:45:49 -05003127vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
3128 void *data)
3129{
Daniel Stonebc15f682016-11-14 16:57:01 +00003130 struct drm_plane_state *ps = (struct drm_plane_state *) data;
3131 struct drm_output_state *os = ps->output_state;
3132 struct drm_output *output = os->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00003133 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02003134 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
3135 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03003136
Daniel Stone598ee9d2016-11-16 11:55:20 +00003137 assert(!b->atomic_modeset);
3138
Pekka Paalanen641307c2014-09-23 22:08:47 -04003139 drm_output_update_msc(output, frame);
Daniel Stone65d87d02017-04-04 17:54:32 +01003140 output->vblank_pending--;
3141 assert(output->vblank_pending >= 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003142
Daniel Stonebc15f682016-11-14 16:57:01 +00003143 assert(ps->fb);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03003144
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003145 if (output->page_flip_pending || output->vblank_pending)
3146 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00003147
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003148 drm_output_update_complete(output, flags, sec, usec);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003149}
3150
3151static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003152page_flip_handler(int fd, unsigned int frame,
3153 unsigned int sec, unsigned int usec, void *data)
3154{
Armin Krezović545dba62016-08-05 15:54:18 +02003155 struct drm_output *output = data;
Daniel Stone598ee9d2016-11-16 11:55:20 +00003156 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02003157 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
3158 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
3159 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003160
Pekka Paalanen641307c2014-09-23 22:08:47 -04003161 drm_output_update_msc(output, frame);
3162
Daniel Stone598ee9d2016-11-16 11:55:20 +00003163 assert(!b->atomic_modeset);
Daniel Stone205c0a02017-04-04 17:54:33 +01003164 assert(output->page_flip_pending);
Jonas Ådahle5a12252013-04-05 23:07:11 +02003165 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003166
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003167 if (output->vblank_pending)
3168 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00003169
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003170 drm_output_update_complete(output, flags, sec, usec);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02003171}
3172
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003173/**
3174 * Begin a new repaint cycle
3175 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003176 * Called by the core compositor at the beginning of a repaint cycle. Creates
3177 * a new pending_state structure to own any output state created by individual
3178 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003179 */
3180static void *
3181drm_repaint_begin(struct weston_compositor *compositor)
3182{
3183 struct drm_backend *b = to_drm_backend(compositor);
3184 struct drm_pending_state *ret;
3185
3186 ret = drm_pending_state_alloc(b);
3187 b->repaint_data = ret;
3188
Marius Vlad7e4db952019-04-17 13:47:06 +03003189 if (weston_log_scope_is_enabled(b->debug)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003190 char *dbg = weston_compositor_print_scene_graph(compositor);
3191 drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
3192 ret);
3193 drm_debug(b, "%s", dbg);
3194 free(dbg);
3195 }
3196
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003197 return ret;
3198}
3199
3200/**
3201 * Flush a repaint set
3202 *
3203 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003204 * and should be flushed. Frees the pending state, transitioning ownership
3205 * of the output state from the pending state, to the update itself. When
3206 * the update completes (see drm_output_update_complete), the output
3207 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003208 */
3209static void
3210drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
3211{
3212 struct drm_backend *b = to_drm_backend(compositor);
3213 struct drm_pending_state *pending_state = repaint_data;
Daniel Stone6020f472018-02-05 15:46:20 +00003214
Daniel Stonea08512f2016-11-08 17:46:10 +00003215 drm_pending_state_apply(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003216 drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003217 b->repaint_data = NULL;
3218}
3219
3220/**
3221 * Cancel a repaint set
3222 *
3223 * Called by the core compositor when a repaint has finished, so the data
3224 * held across the repaint cycle should be discarded.
3225 */
3226static void
3227drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
3228{
3229 struct drm_backend *b = to_drm_backend(compositor);
3230 struct drm_pending_state *pending_state = repaint_data;
3231
3232 drm_pending_state_free(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003233 drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003234 b->repaint_data = NULL;
3235}
3236
Daniel Stone598ee9d2016-11-16 11:55:20 +00003237#ifdef HAVE_DRM_ATOMIC
3238static void
3239atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
3240 unsigned int usec, unsigned int crtc_id, void *data)
3241{
3242 struct drm_backend *b = data;
3243 struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
3244 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
3245 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
3246 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
3247
3248 /* During the initial modeset, we can disable CRTCs which we don't
3249 * actually handle during normal operation; this will give us events
3250 * for unknown outputs. Ignore them. */
3251 if (!output || !output->base.enabled)
3252 return;
3253
3254 drm_output_update_msc(output, frame);
3255
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03003256 drm_debug(b, "[atomic][CRTC:%u] flip processing started\n", crtc_id);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003257 assert(b->atomic_modeset);
3258 assert(output->atomic_complete_pending);
3259 output->atomic_complete_pending = 0;
3260
3261 drm_output_update_complete(output, flags, sec, usec);
Arkadiusz Hiler5a5cbc02018-10-15 11:06:11 +03003262 drm_debug(b, "[atomic][CRTC:%u] flip processing completed\n", crtc_id);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003263}
3264#endif
3265
Daniel Stonef8290622016-12-09 17:32:10 +00003266static struct drm_plane_state *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003267drm_output_prepare_overlay_view(struct drm_output_state *output_state,
Daniel Stonea284d272018-07-10 18:40:12 +01003268 struct weston_view *ev,
3269 enum drm_output_propose_state_mode mode)
Jesse Barnes58ef3792012-02-23 09:45:49 -05003270{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003271 struct drm_output *output = output_state->output;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02003272 struct weston_compositor *ec = output->base.compositor;
Daniel Stoned6e2a762016-11-16 19:33:20 +00003273 struct drm_backend *b = to_drm_backend(ec);
Daniel Stone08d4edf2017-04-04 17:54:34 +01003274 struct drm_plane *p;
Daniel Stonebc15f682016-11-14 16:57:01 +00003275 struct drm_plane_state *state = NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00003276 struct drm_fb *fb;
Daniel Stonedb10df12016-12-08 13:15:58 +00003277 unsigned int i;
Daniel Stonea284d272018-07-10 18:40:12 +01003278 int ret;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003279 enum {
3280 NO_PLANES,
3281 NO_PLANES_WITH_FORMAT,
3282 NO_PLANES_ACCEPTED,
3283 PLACED_ON_PLANE,
3284 } availability = NO_PLANES;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003285
Daniel Stone44abfaa2018-07-10 14:31:06 +01003286 assert(!b->sprites_are_broken);
Daniel Stone87fab1c2019-06-17 11:13:20 +01003287 assert(b->atomic_modeset);
Kristian Høgsberg65bec242012-03-05 19:57:35 -05003288
Daniel Stonef11ec022016-11-17 17:32:42 +00003289 fb = drm_fb_get_from_view(output_state, ev);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003290 if (!fb) {
3291 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
3292 " couldn't get fb\n", ev);
Daniel Stone296d7a92016-10-21 18:05:37 +01003293 return NULL;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003294 }
Daniel Stone296d7a92016-10-21 18:05:37 +01003295
Daniel Stone085d2b92015-05-21 00:00:57 +01003296 wl_list_for_each(p, &b->plane_list, link) {
3297 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
3298 continue;
3299
Daniel Stone5ff289a2017-10-07 12:59:02 +01003300 if (!drm_plane_is_available(p, output))
Daniel Stonebc15f682016-11-14 16:57:01 +00003301 continue;
3302
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003303 state = drm_output_state_get_plane(output_state, p);
3304 if (state->fb) {
3305 state = NULL;
3306 continue;
3307 }
3308
3309 if (availability == NO_PLANES)
3310 availability = NO_PLANES_WITH_FORMAT;
3311
Daniel Stonef11ec022016-11-17 17:32:42 +00003312 /* Check whether the format is supported */
3313 for (i = 0; i < p->count_formats; i++) {
Sergi Granellf4456222017-01-12 17:17:32 +00003314 unsigned int j;
3315
3316 if (p->formats[i].format != fb->format->format)
3317 continue;
3318
3319 if (fb->modifier == DRM_FORMAT_MOD_INVALID)
3320 break;
3321
3322 for (j = 0; j < p->formats[i].count_modifiers; j++) {
3323 if (p->formats[i].modifiers[j] == fb->modifier)
3324 break;
3325 }
3326 if (j != p->formats[i].count_modifiers)
Daniel Stonef11ec022016-11-17 17:32:42 +00003327 break;
3328 }
Philipp Zabel619958e2019-01-22 11:28:46 +01003329 if (i == p->count_formats) {
3330 drm_plane_state_put_back(state);
3331 state = NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00003332 continue;
Philipp Zabel619958e2019-01-22 11:28:46 +01003333 }
Daniel Stonef11ec022016-11-17 17:32:42 +00003334
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003335 if (availability == NO_PLANES_WITH_FORMAT)
3336 availability = NO_PLANES_ACCEPTED;
Daniel Stonebc15f682016-11-14 16:57:01 +00003337
Daniel Stonea284d272018-07-10 18:40:12 +01003338 state->ev = ev;
3339 state->output = output;
3340 if (!drm_plane_state_coords_for_view(state, ev)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003341 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
3342 "unsuitable transform\n", ev);
Daniel Stonea284d272018-07-10 18:40:12 +01003343 drm_plane_state_put_back(state);
3344 state = NULL;
3345 continue;
3346 }
Daniel Stonea284d272018-07-10 18:40:12 +01003347
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003348 /* If the surface buffer has an in-fence fd, but the plane
3349 * doesn't support fences, we can't place the buffer on this
3350 * plane. */
3351 if (ev->surface->acquire_fence_fd >= 0 &&
Daniel Stone87fab1c2019-06-17 11:13:20 +01003352 p->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003353 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
3354 "no in-fence support\n", ev);
3355 drm_plane_state_put_back(state);
3356 state = NULL;
3357 continue;
3358 }
3359
Daniel Stonea284d272018-07-10 18:40:12 +01003360 /* We hold one reference for the lifetime of this function;
3361 * from calling drm_fb_get_from_view, to the out label where
3362 * we unconditionally drop the reference. So, we take another
3363 * reference here to live within the state. */
3364 state->fb = drm_fb_ref(fb);
3365
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003366 state->in_fence_fd = ev->surface->acquire_fence_fd;
3367
Daniel Stonea284d272018-07-10 18:40:12 +01003368 /* In planes-only mode, we don't have an incremental state to
3369 * test against, so we just hope it'll work. */
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003370 if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
3371 drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
3372 "view %p on overlay %lu in planes-only mode\n",
3373 ev, (unsigned long) p->plane_id);
3374 availability = PLACED_ON_PLANE;
Daniel Stonea284d272018-07-10 18:40:12 +01003375 goto out;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003376 }
Daniel Stonea284d272018-07-10 18:40:12 +01003377
3378 ret = drm_pending_state_test(output_state->pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003379 if (ret == 0) {
3380 drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
3381 "view %p on overlay %d in mixed mode\n",
3382 ev, p->plane_id);
3383 availability = PLACED_ON_PLANE;
Daniel Stonea284d272018-07-10 18:40:12 +01003384 goto out;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003385 }
3386
3387 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay %lu "
3388 "in mixed mode: kernel test failed\n",
3389 ev, (unsigned long) p->plane_id);
Daniel Stonea284d272018-07-10 18:40:12 +01003390
3391 drm_plane_state_put_back(state);
3392 state = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003393 }
3394
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003395 switch (availability) {
3396 case NO_PLANES:
3397 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
3398 "no free overlay planes\n", ev);
3399 break;
3400 case NO_PLANES_WITH_FORMAT:
3401 drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
Marius Vladd4c7bc52019-02-16 21:19:51 +02003402 "no free overlay planes matching format %s (0x%lx) "
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003403 "modifier 0x%llx\n",
Marius Vladd4c7bc52019-02-16 21:19:51 +02003404 ev, fb->format->drm_format_name,
3405 (unsigned long) fb->format,
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003406 (unsigned long long) fb->modifier);
3407 break;
3408 case NO_PLANES_ACCEPTED:
3409 case PLACED_ON_PLANE:
3410 break;
3411 }
3412
Daniel Stonea284d272018-07-10 18:40:12 +01003413out:
3414 drm_fb_unref(fb);
Daniel Stonef8290622016-12-09 17:32:10 +00003415 return state;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003416}
3417
Pekka Paalanend0ead482014-06-16 12:05:40 +03003418/**
3419 * Update the image for the current cursor surface
3420 *
Daniel Stone9b560382016-11-16 19:46:35 +00003421 * @param plane_state DRM cursor plane state
3422 * @param ev Source view for cursor
Pekka Paalanend0ead482014-06-16 12:05:40 +03003423 */
3424static void
Daniel Stone9b560382016-11-16 19:46:35 +00003425cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
Pekka Paalanend0ead482014-06-16 12:05:40 +03003426{
Daniel Stone9b560382016-11-16 19:46:35 +00003427 struct drm_backend *b = plane_state->plane->backend;
3428 struct gbm_bo *bo = plane_state->fb->bo;
Pekka Paalanend0ead482014-06-16 12:05:40 +03003429 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
3430 uint32_t buf[b->cursor_width * b->cursor_height];
3431 int32_t stride;
3432 uint8_t *s;
3433 int i;
3434
3435 assert(buffer && buffer->shm_buffer);
3436 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
Daniel Stone9b560382016-11-16 19:46:35 +00003437 assert(buffer->width <= b->cursor_width);
3438 assert(buffer->height <= b->cursor_height);
Pekka Paalanend0ead482014-06-16 12:05:40 +03003439
3440 memset(buf, 0, sizeof buf);
3441 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
3442 s = wl_shm_buffer_get_data(buffer->shm_buffer);
3443
3444 wl_shm_buffer_begin_access(buffer->shm_buffer);
Daniel Stone9b560382016-11-16 19:46:35 +00003445 for (i = 0; i < buffer->height; i++)
Pekka Paalanend0ead482014-06-16 12:05:40 +03003446 memcpy(buf + i * b->cursor_width,
3447 s + i * stride,
Daniel Stone9b560382016-11-16 19:46:35 +00003448 buffer->width * 4);
Pekka Paalanend0ead482014-06-16 12:05:40 +03003449 wl_shm_buffer_end_access(buffer->shm_buffer);
3450
3451 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Antonio Borneo39578632019-04-26 23:57:31 +02003452 weston_log("failed update cursor: %s\n", strerror(errno));
Pekka Paalanend0ead482014-06-16 12:05:40 +03003453}
3454
Daniel Stonef8290622016-12-09 17:32:10 +00003455static struct drm_plane_state *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003456drm_output_prepare_cursor_view(struct drm_output_state *output_state,
3457 struct weston_view *ev)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04003458{
Daniel Stone2ba17f42015-05-19 20:02:41 +01003459 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02003460 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stone2ba17f42015-05-19 20:02:41 +01003461 struct drm_plane *plane = output->cursor_plane;
3462 struct drm_plane_state *plane_state;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003463 struct wl_shm_buffer *shmbuf;
3464 bool needs_update = false;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003465
Daniel Stonef7a2f832016-12-08 17:19:09 +00003466 assert(!b->cursors_are_broken);
Daniel Stone2ba17f42015-05-19 20:02:41 +01003467
Daniel Stonef7a2f832016-12-08 17:19:09 +00003468 if (!plane)
Daniel Stone2ba17f42015-05-19 20:02:41 +01003469 return NULL;
3470
3471 if (!plane->state_cur->complete)
3472 return NULL;
3473
3474 if (plane->state_cur->output && plane->state_cur->output != output)
3475 return NULL;
3476
Daniel Stone2ba17f42015-05-19 20:02:41 +01003477 /* We use GBM to import SHM buffers. */
3478 if (b->gbm == NULL)
3479 return NULL;
3480
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003481 if (ev->surface->buffer_ref.buffer == NULL) {
3482 drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
3483 "(no buffer available)\n", ev);
Daniel Stone2ba17f42015-05-19 20:02:41 +01003484 return NULL;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003485 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003486 shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003487 if (!shmbuf) {
3488 drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
3489 "(buffer isn't SHM)\n", ev);
Daniel Stone2ba17f42015-05-19 20:02:41 +01003490 return NULL;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003491 }
3492 if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888) {
3493 drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
3494 "(format 0x%lx unsuitable)\n",
3495 ev, (unsigned long) wl_shm_buffer_get_format(shmbuf));
Daniel Stone2ba17f42015-05-19 20:02:41 +01003496 return NULL;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003497 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003498
Daniel Stone2ba17f42015-05-19 20:02:41 +01003499 plane_state =
3500 drm_output_state_get_plane(output_state, output->cursor_plane);
3501
3502 if (plane_state && plane_state->fb)
3503 return NULL;
3504
Daniel Stone9b560382016-11-16 19:46:35 +00003505 /* We can't scale with the legacy API, and we don't try to account for
3506 * simple cropping/translation in cursor_bo_update. */
3507 plane_state->output = output;
3508 if (!drm_plane_state_coords_for_view(plane_state, ev))
3509 goto err;
3510
3511 if (plane_state->src_x != 0 || plane_state->src_y != 0 ||
3512 plane_state->src_w > (unsigned) b->cursor_width << 16 ||
3513 plane_state->src_h > (unsigned) b->cursor_height << 16 ||
3514 plane_state->src_w != plane_state->dest_w << 16 ||
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003515 plane_state->src_h != plane_state->dest_h << 16) {
3516 drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
3517 "(positioning requires cropping or scaling)\n", ev);
Daniel Stone9b560382016-11-16 19:46:35 +00003518 goto err;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003519 }
Daniel Stone9b560382016-11-16 19:46:35 +00003520
Daniel Stone2ba17f42015-05-19 20:02:41 +01003521 /* Since we're setting plane state up front, we need to work out
3522 * whether or not we need to upload a new cursor. We can't use the
3523 * plane damage, since the planes haven't actually been calculated
3524 * yet: instead try to figure it out directly. KMS cursor planes are
3525 * pretty unique here, in that they lie partway between a Weston plane
3526 * (direct scanout) and a renderer. */
3527 if (ev != output->cursor_view ||
3528 pixman_region32_not_empty(&ev->surface->damage)) {
3529 output->current_cursor++;
3530 output->current_cursor =
3531 output->current_cursor %
3532 ARRAY_LENGTH(output->gbm_cursor_fb);
3533 needs_update = true;
3534 }
3535
3536 output->cursor_view = ev;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003537 plane_state->ev = ev;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003538
3539 plane_state->fb =
3540 drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
Daniel Stone9b560382016-11-16 19:46:35 +00003541
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003542 if (needs_update) {
3543 drm_debug(b, "\t\t\t\t[cursor] copying new content to cursor BO\n");
Daniel Stone9b560382016-11-16 19:46:35 +00003544 cursor_bo_update(plane_state, ev);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003545 }
Daniel Stone9b560382016-11-16 19:46:35 +00003546
3547 /* The cursor API is somewhat special: in cursor_bo_update(), we upload
3548 * a buffer which is always cursor_width x cursor_height, even if the
3549 * surface we want to promote is actually smaller than this. Manually
3550 * mangle the plane state to deal with this. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01003551 plane_state->src_w = b->cursor_width << 16;
3552 plane_state->src_h = b->cursor_height << 16;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003553 plane_state->dest_w = b->cursor_width;
3554 plane_state->dest_h = b->cursor_height;
3555
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003556 drm_debug(b, "\t\t\t\t[cursor] provisionally assigned view %p to cursor\n",
3557 ev);
3558
Daniel Stonef8290622016-12-09 17:32:10 +00003559 return plane_state;
Daniel Stone9b560382016-11-16 19:46:35 +00003560
3561err:
3562 drm_plane_state_put_back(plane_state);
3563 return NULL;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003564}
3565
3566static void
3567drm_output_set_cursor(struct drm_output_state *output_state)
3568{
3569 struct drm_output *output = output_state->output;
3570 struct drm_backend *b = to_drm_backend(output->base.compositor);
3571 struct drm_plane *plane = output->cursor_plane;
3572 struct drm_plane_state *state;
3573 EGLint handle;
3574 struct gbm_bo *bo;
3575
3576 if (!plane)
3577 return;
3578
3579 state = drm_output_state_get_existing_plane(output_state, plane);
3580 if (!state)
3581 return;
3582
3583 if (!state->fb) {
3584 pixman_region32_fini(&plane->base.damage);
3585 pixman_region32_init(&plane->base.damage);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003586 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04003587 return;
3588 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003589
Daniel Stone2ba17f42015-05-19 20:02:41 +01003590 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
3591 assert(!plane->state_cur->output || plane->state_cur->output == output);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003592
Daniel Stone2ba17f42015-05-19 20:02:41 +01003593 if (plane->state_cur->fb != state->fb) {
3594 bo = state->fb->bo;
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04003595 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03003596 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
Daniel Stone2ba17f42015-05-19 20:02:41 +01003597 b->cursor_width, b->cursor_height)) {
Antonio Borneo39578632019-04-26 23:57:31 +02003598 weston_log("failed to set cursor: %s\n",
3599 strerror(errno));
Daniel Stone2ba17f42015-05-19 20:02:41 +01003600 goto err;
Rob Clarkab5b1e32012-08-09 13:24:45 -05003601 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003602 }
3603
Daniel Stone2ba17f42015-05-19 20:02:41 +01003604 pixman_region32_fini(&plane->base.damage);
3605 pixman_region32_init(&plane->base.damage);
Pekka Paalanen7eaed402015-11-27 14:20:58 +02003606
Daniel Stone2ba17f42015-05-19 20:02:41 +01003607 if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
3608 state->dest_x, state->dest_y)) {
Antonio Borneo39578632019-04-26 23:57:31 +02003609 weston_log("failed to move cursor: %s\n", strerror(errno));
Daniel Stone2ba17f42015-05-19 20:02:41 +01003610 goto err;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003611 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003612
3613 return;
3614
3615err:
3616 b->cursors_are_broken = 1;
3617 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003618}
3619
Daniel Stoneee1aea72017-12-18 13:41:09 +00003620static struct drm_output_state *
3621drm_output_propose_state(struct weston_output *output_base,
Daniel Stonef7a2f832016-12-08 17:19:09 +00003622 struct drm_pending_state *pending_state,
3623 enum drm_output_propose_state_mode mode)
Daniel Stoneee1aea72017-12-18 13:41:09 +00003624{
3625 struct drm_output *output = to_drm_output(output_base);
Daniel Stone44abfaa2018-07-10 14:31:06 +01003626 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003627 struct drm_output_state *state;
Daniel Stonea284d272018-07-10 18:40:12 +01003628 struct drm_plane_state *scanout_state = NULL;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003629 struct weston_view *ev;
Daniel Stone81082392016-12-09 18:03:31 +00003630 pixman_region32_t surface_overlap, renderer_region, occluded_region;
Daniel Stonef7a2f832016-12-08 17:19:09 +00003631 bool planes_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY);
Daniel Stoned12e5162018-07-10 18:19:37 +01003632 bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003633 int ret;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003634
3635 assert(!output->state_last);
3636 state = drm_output_state_duplicate(output->state_cur,
3637 pending_state,
3638 DRM_OUTPUT_STATE_CLEAR_PLANES);
3639
Daniel Stonea284d272018-07-10 18:40:12 +01003640 /* We implement mixed mode by progressively creating and testing
3641 * incremental states, of scanout + overlay + cursor. Since we
3642 * walk our views top to bottom, the scanout plane is last, however
3643 * we always need it in our scene for the test modeset to be
3644 * meaningful. To do this, we steal a reference to the last
3645 * renderer framebuffer we have, if we think it's basically
3646 * compatible. If we don't have that, then we conservatively fall
3647 * back to only using the renderer for this repaint. */
3648 if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
3649 struct drm_plane *plane = output->scanout_plane;
3650 struct drm_fb *scanout_fb = plane->state_cur->fb;
3651
3652 if (!scanout_fb ||
3653 (scanout_fb->type != BUFFER_GBM_SURFACE &&
3654 scanout_fb->type != BUFFER_PIXMAN_DUMB)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003655 drm_debug(b, "\t\t[state] cannot propose mixed mode: "
3656 "for output %s (%lu): no previous renderer "
3657 "fb\n",
3658 output->base.name,
3659 (unsigned long) output->base.id);
Daniel Stonea284d272018-07-10 18:40:12 +01003660 drm_output_state_free(state);
3661 return NULL;
3662 }
3663
3664 if (scanout_fb->width != output_base->current_mode->width ||
3665 scanout_fb->height != output_base->current_mode->height) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003666 drm_debug(b, "\t\t[state] cannot propose mixed mode "
3667 "for output %s (%lu): previous fb has "
3668 "different size\n",
3669 output->base.name,
3670 (unsigned long) output->base.id);
Daniel Stonea284d272018-07-10 18:40:12 +01003671 drm_output_state_free(state);
3672 return NULL;
3673 }
3674
3675 scanout_state = drm_plane_state_duplicate(state,
3676 plane->state_cur);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003677 drm_debug(b, "\t\t[state] using renderer FB ID %lu for mixed "
3678 "mode for output %s (%lu)\n",
3679 (unsigned long) scanout_fb->fb_id, output->base.name,
3680 (unsigned long) output->base.id);
Daniel Stonea284d272018-07-10 18:40:12 +01003681 }
3682
Daniel Stoneee1aea72017-12-18 13:41:09 +00003683 /*
3684 * Find a surface for each sprite in the output using some heuristics:
3685 * 1) size
3686 * 2) frequency of update
3687 * 3) opacity (though some hw might support alpha blending)
3688 * 4) clipping (this can be fixed with color keys)
3689 *
3690 * The idea is to save on blitting since this should save power.
3691 * If we can get a large video surface on the sprite for example,
3692 * the main display surface may not need to update at all, and
3693 * the client buffer can be used directly for the sprite surface
3694 * as we do for flipping full screen surfaces.
3695 */
3696 pixman_region32_init(&renderer_region);
Daniel Stone81082392016-12-09 18:03:31 +00003697 pixman_region32_init(&occluded_region);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003698
3699 wl_list_for_each(ev, &output_base->compositor->view_list, link) {
Daniel Stonef8290622016-12-09 17:32:10 +00003700 struct drm_plane_state *ps = NULL;
3701 bool force_renderer = false;
Daniel Stone81082392016-12-09 18:03:31 +00003702 pixman_region32_t clipped_view;
Daniel Stoneb41abf92018-07-11 13:03:31 +01003703 bool totally_occluded = false;
3704 bool overlay_occluded = false;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003705
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003706 drm_debug(b, "\t\t\t[view] evaluating view %p for "
3707 "output %s (%lu)\n",
3708 ev, output->base.name,
3709 (unsigned long) output->base.id);
3710
Daniel Stone231ae2f2016-11-29 21:03:44 +00003711 /* If this view doesn't touch our output at all, there's no
3712 * reason to do anything with it. */
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003713 if (!(ev->output_mask & (1u << output->base.id))) {
3714 drm_debug(b, "\t\t\t\t[view] ignoring view %p "
3715 "(not on our output)\n", ev);
Daniel Stone231ae2f2016-11-29 21:03:44 +00003716 continue;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003717 }
Daniel Stone231ae2f2016-11-29 21:03:44 +00003718
3719 /* We only assign planes to views which are exclusively present
3720 * on our output. */
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003721 if (ev->output_mask != (1u << output->base.id)) {
3722 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3723 "(on multiple outputs)\n", ev);
Daniel Stonef8290622016-12-09 17:32:10 +00003724 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003725 }
Daniel Stone231ae2f2016-11-29 21:03:44 +00003726
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003727 if (!ev->surface->buffer_ref.buffer) {
3728 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3729 "(no buffer available)\n", ev);
Daniel Stoneca6fbe32018-07-10 18:08:12 +01003730 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003731 }
Daniel Stoneca6fbe32018-07-10 18:08:12 +01003732
Daniel Stone81082392016-12-09 18:03:31 +00003733 /* Ignore views we know to be totally occluded. */
3734 pixman_region32_init(&clipped_view);
3735 pixman_region32_intersect(&clipped_view,
3736 &ev->transform.boundingbox,
3737 &output->base.region);
3738
3739 pixman_region32_init(&surface_overlap);
3740 pixman_region32_subtract(&surface_overlap, &clipped_view,
3741 &occluded_region);
Daniel Stoneb41abf92018-07-11 13:03:31 +01003742 totally_occluded = !pixman_region32_not_empty(&surface_overlap);
3743 if (totally_occluded) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003744 drm_debug(b, "\t\t\t\t[view] ignoring view %p "
3745 "(occluded on our output)\n", ev);
Daniel Stone81082392016-12-09 18:03:31 +00003746 pixman_region32_fini(&surface_overlap);
3747 pixman_region32_fini(&clipped_view);
3748 continue;
3749 }
3750
Daniel Stoneee1aea72017-12-18 13:41:09 +00003751 /* Since we process views from top to bottom, we know that if
3752 * the view intersects the calculated renderer region, it must
3753 * be part of, or occluded by, it, and cannot go on a plane. */
Daniel Stoneee1aea72017-12-18 13:41:09 +00003754 pixman_region32_intersect(&surface_overlap, &renderer_region,
Daniel Stone81082392016-12-09 18:03:31 +00003755 &clipped_view);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003756 if (pixman_region32_not_empty(&surface_overlap)) {
3757 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3758 "(occluded by renderer views)\n", ev);
Daniel Stonef8290622016-12-09 17:32:10 +00003759 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003760 }
Daniel Stonea0f82762018-07-10 11:44:25 +01003761
3762 /* We do not control the stacking order of overlay planes;
3763 * the scanout plane is strictly stacked bottom and the cursor
3764 * plane top, but the ordering of overlay planes with respect
3765 * to each other is undefined. Make sure we do not have two
3766 * planes overlapping each other. */
3767 pixman_region32_intersect(&surface_overlap, &occluded_region,
3768 &clipped_view);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003769 if (pixman_region32_not_empty(&surface_overlap)) {
3770 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3771 "(occluded by other overlay planes)\n", ev);
Daniel Stoneb41abf92018-07-11 13:03:31 +01003772 overlay_occluded = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003773 }
Daniel Stoneee1aea72017-12-18 13:41:09 +00003774 pixman_region32_fini(&surface_overlap);
3775
Daniel Stonef7a2f832016-12-08 17:19:09 +00003776 /* The cursor plane is 'special' in the sense that we can still
3777 * place it in the legacy API, and we gate that with a separate
3778 * cursors_are_broken flag. */
Daniel Stoneb41abf92018-07-11 13:03:31 +01003779 if (!force_renderer && !overlay_occluded && !b->cursors_are_broken)
Daniel Stonef8290622016-12-09 17:32:10 +00003780 ps = drm_output_prepare_cursor_view(state, ev);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003781
Daniel Stonef8290622016-12-09 17:32:10 +00003782 /* If sprites are disabled or the view is not fully opaque, we
3783 * must put the view into the renderer - unless it has already
3784 * been placed in the cursor plane, which can handle alpha. */
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003785 if (!ps && !planes_ok) {
3786 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3787 "(precluded by mode)\n", ev);
Daniel Stonef8290622016-12-09 17:32:10 +00003788 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003789 }
Philipp Zabelfff27972018-09-03 20:13:52 +02003790 if (!ps && !weston_view_is_opaque(ev, &clipped_view)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003791 drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
3792 "(view not fully opaque)\n", ev);
Daniel Stonef8290622016-12-09 17:32:10 +00003793 force_renderer = true;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003794 }
Daniel Stone81082392016-12-09 18:03:31 +00003795
Daniel Stonea284d272018-07-10 18:40:12 +01003796 /* Only try to place scanout surfaces in planes-only mode; in
3797 * mixed mode, we have already failed to place a view on the
3798 * scanout surface, forcing usage of the renderer on the
3799 * scanout plane. */
3800 if (!ps && !force_renderer && !renderer_ok)
3801 ps = drm_output_prepare_scanout_view(state, ev, mode);
Daniel Stoneb41abf92018-07-11 13:03:31 +01003802
3803 if (!ps && !overlay_occluded && !force_renderer)
Daniel Stonea284d272018-07-10 18:40:12 +01003804 ps = drm_output_prepare_overlay_view(state, ev, mode);
Daniel Stone44abfaa2018-07-10 14:31:06 +01003805
Daniel Stonef8290622016-12-09 17:32:10 +00003806 if (ps) {
Daniel Stonef7a2f832016-12-08 17:19:09 +00003807 /* If we have been assigned to an overlay or scanout
3808 * plane, add this area to the occluded region, so
3809 * other views are known to be behind it. The cursor
3810 * plane, however, is special, in that it blends with
3811 * the content underneath it: the area should neither
3812 * be added to the renderer region nor the occluded
3813 * region. */
Daniel Stonef8290622016-12-09 17:32:10 +00003814 if (ps->plane->type != WDRM_PLANE_TYPE_CURSOR) {
Daniel Stonef7a2f832016-12-08 17:19:09 +00003815 pixman_region32_union(&occluded_region,
3816 &occluded_region,
3817 &clipped_view);
3818 pixman_region32_fini(&clipped_view);
3819 }
3820 continue;
3821 }
Daniel Stoneee1aea72017-12-18 13:41:09 +00003822
Daniel Stoned12e5162018-07-10 18:19:37 +01003823 /* We have been assigned to the primary (renderer) plane:
3824 * check if this is OK, and add ourselves to the renderer
3825 * region if so. */
3826 if (!renderer_ok) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003827 drm_debug(b, "\t\t[view] failing state generation: "
3828 "placing view %p to renderer not allowed\n",
3829 ev);
Daniel Stoned12e5162018-07-10 18:19:37 +01003830 pixman_region32_fini(&clipped_view);
3831 goto err_region;
3832 }
3833
Daniel Stonef7a2f832016-12-08 17:19:09 +00003834 pixman_region32_union(&renderer_region,
3835 &renderer_region,
3836 &clipped_view);
Daniel Stone81082392016-12-09 18:03:31 +00003837 pixman_region32_fini(&clipped_view);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003838 }
3839 pixman_region32_fini(&renderer_region);
Daniel Stone81082392016-12-09 18:03:31 +00003840 pixman_region32_fini(&occluded_region);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003841
Daniel Stone11789222018-07-20 19:55:37 +01003842 /* In renderer-only mode, we can't test the state as we don't have a
3843 * renderer buffer yet. */
3844 if (mode == DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY)
3845 return state;
3846
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003847 /* Check to see if this state will actually work. */
3848 ret = drm_pending_state_test(state->pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003849 if (ret != 0) {
3850 drm_debug(b, "\t\t[view] failing state generation: "
3851 "atomic test not OK\n");
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003852 goto err;
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003853 }
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003854
Daniel Stonea284d272018-07-10 18:40:12 +01003855 /* Counterpart to duplicating scanout state at the top of this
3856 * function: if we have taken a renderer framebuffer and placed it in
3857 * the pending state in order to incrementally test overlay planes,
3858 * remove it now. */
3859 if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
3860 assert(scanout_state->fb->type == BUFFER_GBM_SURFACE ||
3861 scanout_state->fb->type == BUFFER_PIXMAN_DUMB);
3862 drm_plane_state_put_back(scanout_state);
3863 }
Daniel Stoneee1aea72017-12-18 13:41:09 +00003864 return state;
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003865
Daniel Stoned12e5162018-07-10 18:19:37 +01003866err_region:
3867 pixman_region32_fini(&renderer_region);
3868 pixman_region32_fini(&occluded_region);
Daniel Stonebb6c19f2016-12-08 17:27:17 +00003869err:
3870 drm_output_state_free(state);
3871 return NULL;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003872}
3873
Marius Vlad5d767412018-12-14 11:56:10 +02003874static const char *
3875drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
3876{
3877 if (mode < 0 || mode >= ARRAY_LENGTH(drm_output_propose_state_mode_as_string))
3878 return " unknown compositing mode";
3879
3880 return drm_output_propose_state_mode_as_string[mode];
3881}
3882
Daniel Stoneee1aea72017-12-18 13:41:09 +00003883static void
3884drm_assign_planes(struct weston_output *output_base, void *repaint_data)
3885{
3886 struct drm_backend *b = to_drm_backend(output_base->compositor);
3887 struct drm_pending_state *pending_state = repaint_data;
3888 struct drm_output *output = to_drm_output(output_base);
Daniel Stonef7a2f832016-12-08 17:19:09 +00003889 struct drm_output_state *state = NULL;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003890 struct drm_plane_state *plane_state;
3891 struct weston_view *ev;
3892 struct weston_plane *primary = &output_base->compositor->primary_plane;
Marius Vlad5d767412018-12-14 11:56:10 +02003893 enum drm_output_propose_state_mode mode = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003894
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003895 drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
3896 output_base->name, (unsigned long) output_base->id);
3897
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003898 if (!b->sprites_are_broken && !output->virtual) {
Marius Vlad5d767412018-12-14 11:56:10 +02003899 drm_debug(b, "\t[repaint] trying planes-only build state\n");
3900 state = drm_output_propose_state(output_base, pending_state, mode);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003901 if (!state) {
3902 drm_debug(b, "\t[repaint] could not build planes-only "
3903 "state, trying mixed\n");
Marius Vlad5d767412018-12-14 11:56:10 +02003904 mode = DRM_OUTPUT_PROPOSE_STATE_MIXED;
3905 state = drm_output_propose_state(output_base,
3906 pending_state,
3907 mode);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003908 }
3909 if (!state) {
3910 drm_debug(b, "\t[repaint] could not build mixed-mode "
3911 "state, trying renderer-only\n");
3912 }
3913 } else {
3914 drm_debug(b, "\t[state] no overlay plane support\n");
Daniel Stoned12e5162018-07-10 18:19:37 +01003915 }
Daniel Stonef7a2f832016-12-08 17:19:09 +00003916
Marius Vlad5d767412018-12-14 11:56:10 +02003917 if (!state) {
3918 mode = DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY;
Daniel Stonef7a2f832016-12-08 17:19:09 +00003919 state = drm_output_propose_state(output_base, pending_state,
Marius Vladc91cf302018-12-21 12:48:22 +02003920 mode);
Marius Vlad5d767412018-12-14 11:56:10 +02003921 }
Daniel Stonef7a2f832016-12-08 17:19:09 +00003922
3923 assert(state);
Marius Vlad5d767412018-12-14 11:56:10 +02003924 drm_debug(b, "\t[repaint] Using %s composition\n",
3925 drm_propose_state_mode_to_string(mode));
Daniel Stoneee1aea72017-12-18 13:41:09 +00003926
3927 wl_list_for_each(ev, &output_base->compositor->view_list, link) {
3928 struct drm_plane *target_plane = NULL;
3929
Daniel Stone231ae2f2016-11-29 21:03:44 +00003930 /* If this view doesn't touch our output at all, there's no
3931 * reason to do anything with it. */
3932 if (!(ev->output_mask & (1u << output->base.id)))
3933 continue;
3934
Daniel Stoneee1aea72017-12-18 13:41:09 +00003935 /* Test whether this buffer can ever go into a plane:
3936 * non-shm, or small enough to be a cursor.
3937 *
3938 * Also, keep a reference when using the pixman renderer.
3939 * That makes it possible to do a seamless switch to the GL
3940 * renderer and since the pixman renderer keeps a reference
3941 * to the buffer anyway, there is no side effects.
3942 */
3943 if (b->use_pixman ||
3944 (ev->surface->buffer_ref.buffer &&
3945 (!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
3946 (ev->surface->width <= b->cursor_width &&
3947 ev->surface->height <= b->cursor_height))))
3948 ev->surface->keep_buffer = true;
3949 else
3950 ev->surface->keep_buffer = false;
3951
3952 /* This is a bit unpleasant, but lacking a temporary place to
3953 * hang a plane off the view, we have to do a nested walk.
3954 * Our first-order iteration has to be planes rather than
3955 * views, because otherwise we won't reset views which were
3956 * previously on planes to being on the primary plane. */
3957 wl_list_for_each(plane_state, &state->plane_list, link) {
3958 if (plane_state->ev == ev) {
3959 plane_state->ev = NULL;
3960 target_plane = plane_state->plane;
3961 break;
3962 }
3963 }
3964
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003965 if (target_plane) {
3966 drm_debug(b, "\t[repaint] view %p on %s plane %lu\n",
3967 ev, plane_type_enums[target_plane->type].name,
3968 (unsigned long) target_plane->plane_id);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003969 weston_view_move_to_plane(ev, &target_plane->base);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003970 } else {
3971 drm_debug(b, "\t[repaint] view %p using renderer "
3972 "composition\n", ev);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003973 weston_view_move_to_plane(ev, primary);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003974 }
Daniel Stoneee1aea72017-12-18 13:41:09 +00003975
3976 if (!target_plane ||
3977 target_plane->type == WDRM_PLANE_TYPE_CURSOR) {
3978 /* cursor plane & renderer involve a copy */
3979 ev->psf_flags = 0;
3980 } else {
3981 /* All other planes are a direct scanout of a
3982 * single client buffer.
3983 */
3984 ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
3985 }
3986 }
3987
3988 /* We rely on output->cursor_view being both an accurate reflection of
3989 * the cursor plane's state, but also being maintained across repaints
3990 * to avoid unnecessary damage uploads, per the comment in
3991 * drm_output_prepare_cursor_view. In the event that we go from having
3992 * a cursor view to not having a cursor view, we need to clear it. */
3993 if (output->cursor_view) {
3994 plane_state =
3995 drm_output_state_get_existing_plane(state,
3996 output->cursor_plane);
3997 if (!plane_state || !plane_state->fb)
3998 output->cursor_view = NULL;
3999 }
4000}
4001
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304002/*
4003 * Get the aspect-ratio from drmModeModeInfo mode flags.
4004 *
4005 * @param drm_mode_flags- flags from drmModeModeInfo structure.
4006 * @returns aspect-ratio as encoded in enum 'weston_mode_aspect_ratio'.
4007 */
4008static enum weston_mode_aspect_ratio
4009drm_to_weston_mode_aspect_ratio(uint32_t drm_mode_flags)
4010{
4011 return (drm_mode_flags & DRM_MODE_FLAG_PIC_AR_MASK) >>
4012 DRM_MODE_FLAG_PIC_AR_BITS_POS;
4013}
4014
4015static const char *
4016aspect_ratio_to_string(enum weston_mode_aspect_ratio ratio)
4017{
4018 if (ratio < 0 || ratio >= ARRAY_LENGTH(aspect_ratio_as_string) ||
4019 !aspect_ratio_as_string[ratio])
4020 return " (unknown aspect ratio)";
4021
4022 return aspect_ratio_as_string[ratio];
4023}
4024
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004025/**
4026 * Find the closest-matching mode for a given target
4027 *
4028 * Given a target mode, find the most suitable mode amongst the output's
4029 * current mode list to use, preferring the current mode if possible, to
4030 * avoid an expensive mode switch.
4031 *
4032 * @param output DRM output
4033 * @param target_mode Mode to attempt to match
4034 * @returns Pointer to a mode from the output's mode list
4035 */
Alex Wub7b8bda2012-04-17 17:20:48 +08004036static struct drm_mode *
4037choose_mode (struct drm_output *output, struct weston_mode *target_mode)
4038{
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304039 struct drm_mode *tmp_mode = NULL, *mode_fall_back = NULL, *mode;
4040 enum weston_mode_aspect_ratio src_aspect = WESTON_MODE_PIC_AR_NONE;
4041 enum weston_mode_aspect_ratio target_aspect = WESTON_MODE_PIC_AR_NONE;
4042 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08004043
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304044 b = to_drm_backend(output->base.compositor);
4045 target_aspect = target_mode->aspect_ratio;
4046 src_aspect = output->base.current_mode->aspect_ratio;
Hardeningff39efa2013-09-18 23:56:35 +02004047 if (output->base.current_mode->width == target_mode->width &&
4048 output->base.current_mode->height == target_mode->height &&
4049 (output->base.current_mode->refresh == target_mode->refresh ||
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304050 target_mode->refresh == 0)) {
4051 if (!b->aspect_ratio_supported || src_aspect == target_aspect)
4052 return to_drm_mode(output->base.current_mode);
4053 }
Alex Wub7b8bda2012-04-17 17:20:48 +08004054
4055 wl_list_for_each(mode, &output->base.mode_list, base.link) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304056
4057 src_aspect = mode->base.aspect_ratio;
Alex Wub7b8bda2012-04-17 17:20:48 +08004058 if (mode->mode_info.hdisplay == target_mode->width &&
4059 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02004060 if (mode->base.refresh == target_mode->refresh ||
4061 target_mode->refresh == 0) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304062 if (!b->aspect_ratio_supported ||
4063 src_aspect == target_aspect)
4064 return mode;
4065 else if (!mode_fall_back)
4066 mode_fall_back = mode;
4067 } else if (!tmp_mode) {
Alex Wub7b8bda2012-04-17 17:20:48 +08004068 tmp_mode = mode;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304069 }
Alex Wub7b8bda2012-04-17 17:20:48 +08004070 }
4071 }
4072
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304073 if (mode_fall_back)
4074 return mode_fall_back;
4075
Alex Wub7b8bda2012-04-17 17:20:48 +08004076 return tmp_mode;
4077}
4078
4079static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004080drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00004081static void
4082drm_output_fini_egl(struct drm_output *output);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004083static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004084drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00004085static void
4086drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004087
4088static int
Alex Wub7b8bda2012-04-17 17:20:48 +08004089drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
4090{
Daniel Stone02d487a2017-10-07 14:01:45 +01004091 struct drm_output *output = to_drm_output(output_base);
4092 struct drm_backend *b = to_drm_backend(output_base->compositor);
4093 struct drm_mode *drm_mode = choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +08004094
4095 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +01004096 weston_log("%s: invalid resolution %dx%d\n",
4097 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08004098 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004099 }
4100
Hardeningff39efa2013-09-18 23:56:35 +02004101 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08004102 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08004103
Hardeningff39efa2013-09-18 23:56:35 +02004104 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08004105
Hardeningff39efa2013-09-18 23:56:35 +02004106 output->base.current_mode = &drm_mode->base;
4107 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08004108 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
4109
Daniel Stonef30a18c2017-04-04 17:54:31 +01004110 /* XXX: This drops our current buffer too early, before we've started
4111 * displaying it. Ideally this should be much more atomic and
4112 * integrated with a full repaint cycle, rather than doing a
4113 * sledgehammer modeswitch first, and only later showing new
4114 * content.
4115 */
Daniel Stone6020f472018-02-05 15:46:20 +00004116 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +08004117
Giulio Camuffo954f1832014-10-11 18:27:30 +03004118 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004119 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03004120 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004121 weston_log("failed to init output pixman state with "
4122 "new mode\n");
4123 return -1;
4124 }
4125 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +00004126 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03004127 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004128 weston_log("failed to init output egl state with "
4129 "new mode");
4130 return -1;
4131 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004132 }
4133
Alex Wub7b8bda2012-04-17 17:20:48 +08004134 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08004135}
4136
Kristian Høgsbergb1868472011-04-22 12:27:57 -04004137static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004138on_drm_input(int fd, uint32_t mask, void *data)
4139{
Daniel Stone598ee9d2016-11-16 11:55:20 +00004140#ifdef HAVE_DRM_ATOMIC
4141 struct drm_backend *b = data;
4142#endif
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004143 drmEventContext evctx;
4144
4145 memset(&evctx, 0, sizeof evctx);
Daniel Stone598ee9d2016-11-16 11:55:20 +00004146#ifndef HAVE_DRM_ATOMIC
Emil Velikov863e66b2017-04-04 18:07:34 +01004147 evctx.version = 2;
Daniel Stone598ee9d2016-11-16 11:55:20 +00004148#else
4149 evctx.version = 3;
4150 if (b->atomic_modeset)
4151 evctx.page_flip_handler2 = atomic_flip_handler;
4152 else
4153#endif
4154 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05004155 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004156 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04004157
4158 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004159}
4160
4161static int
Daniel Stoneefa504f2016-12-19 16:48:20 +00004162init_kms_caps(struct drm_backend *b)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004163{
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03004164 uint64_t cap;
Daniel Stoneefa504f2016-12-19 16:48:20 +00004165 int ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04004166 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04004167
Daniel Stoneefa504f2016-12-19 16:48:20 +00004168 weston_log("using %s\n", b->drm.filename);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04004169
Daniel Stoneefa504f2016-12-19 16:48:20 +00004170 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03004171 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04004172 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03004173 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04004174 clk_id = CLOCK_REALTIME;
4175
Giulio Camuffo954f1832014-10-11 18:27:30 +03004176 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04004177 weston_log("Error: failed to set presentation clock %d.\n",
4178 clk_id);
4179 return -1;
4180 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02004181
Daniel Stoneefa504f2016-12-19 16:48:20 +00004182 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03004183 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03004184 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03004185 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03004186 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03004187
Daniel Stoneefa504f2016-12-19 16:48:20 +00004188 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03004189 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03004190 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03004191 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03004192 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03004193
Daniel Stonebe1090b2017-09-06 17:29:57 +01004194 if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
4195 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
4196 b->universal_planes = (ret == 0);
4197 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01004198 weston_log("DRM: %s universal planes\n",
4199 b->universal_planes ? "supports" : "does not support");
4200
Pekka Paalanencd011a62016-11-15 22:07:49 +00004201#ifdef HAVE_DRM_ATOMIC
4202 if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00004203 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
4204 if (ret != 0)
4205 cap = 0;
Pekka Paalanencd011a62016-11-15 22:07:49 +00004206 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
Daniel Stone598ee9d2016-11-16 11:55:20 +00004207 b->atomic_modeset = ((ret == 0) && (cap == 1));
Pekka Paalanencd011a62016-11-15 22:07:49 +00004208 }
4209#endif
4210 weston_log("DRM: %s atomic modesetting\n",
4211 b->atomic_modeset ? "supports" : "does not support");
4212
Deepak Rawata864f582018-08-24 13:16:03 -07004213#ifdef HAVE_DRM_ADDFB2_MODIFIERS
4214 ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
4215 if (ret == 0)
4216 b->fb_modifiers = cap;
4217 else
4218#endif
4219 b->fb_modifiers = 0;
4220
Daniel Stone678aabe2016-12-09 16:00:12 +00004221 /*
4222 * KMS support for hardware planes cannot properly synchronize
4223 * without nuclear page flip. Without nuclear/atomic, hw plane
4224 * and cursor plane updates would either tear or cause extra
4225 * waits for vblanks which means dropping the compositor framerate
4226 * to a fraction. For cursors, it's not so bad, so they are
4227 * enabled.
4228 */
Marius Vladbe578572019-01-25 12:56:24 +02004229 if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
Daniel Stone678aabe2016-12-09 16:00:12 +00004230 b->sprites_are_broken = 1;
4231
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304232 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
4233 b->aspect_ratio_supported = (ret == 0);
4234 weston_log("DRM: %s picture aspect ratio\n",
4235 b->aspect_ratio_supported ? "supports" : "does not support");
4236
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02004237 return 0;
4238}
4239
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004240static struct gbm_device *
4241create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02004242{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004243 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01004244
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03004245 gl_renderer = weston_load_module("gl-renderer.so",
4246 "gl_renderer_interface");
4247 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004248 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03004249
4250 /* GBM will load a dri driver, but even though they need symbols from
4251 * libglapi, in some version of Mesa they are not linked to it. Since
4252 * only the gl-renderer module links to it, the call above won't make
4253 * these symbols globally available, and loading the DRI driver fails.
4254 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
4255 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
4256
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004257 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004258
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004259 return gbm;
4260}
4261
Bryce Harringtonc056a982015-05-19 15:25:18 -07004262/* When initializing EGL, if the preferred buffer format isn't available
Bryce Harringtonb9939982016-04-15 20:28:26 -07004263 * we may be able to substitute an ARGB format for an XRGB one.
Derek Foremanc4cfe852015-05-15 12:12:40 -05004264 *
4265 * This returns 0 if substitution isn't possible, but 0 might be a
4266 * legitimate format for other EGL platforms, so the caller is
4267 * responsible for checking for 0 before calling gl_renderer->create().
4268 *
4269 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
4270 * but it's entirely possible we'll see this again on other implementations.
4271 */
4272static int
4273fallback_format_for(uint32_t format)
4274{
4275 switch (format) {
4276 case GBM_FORMAT_XRGB8888:
4277 return GBM_FORMAT_ARGB8888;
4278 case GBM_FORMAT_XRGB2101010:
4279 return GBM_FORMAT_ARGB2101010;
4280 default:
4281 return 0;
4282 }
4283}
4284
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004285static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004286drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004287{
Derek Foreman6d556372015-11-04 14:47:33 -06004288 EGLint format[3] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004289 b->gbm_format,
4290 fallback_format_for(b->gbm_format),
Derek Foreman6d556372015-11-04 14:47:33 -06004291 0,
Derek Foremanc4cfe852015-05-15 12:12:40 -05004292 };
Derek Foreman6d556372015-11-04 14:47:33 -06004293 int n_formats = 2;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01004294
Derek Foremanc4cfe852015-05-15 12:12:40 -05004295 if (format[1])
Derek Foreman6d556372015-11-04 14:47:33 -06004296 n_formats = 3;
Miguel A. Vicodddc6702016-05-18 17:41:07 +02004297 if (gl_renderer->display_create(b->compositor,
4298 EGL_PLATFORM_GBM_KHR,
4299 (void *)b->gbm,
Miguel A. Vico41700e32016-05-18 17:47:59 +02004300 NULL,
Miguel A. Vicodddc6702016-05-18 17:41:07 +02004301 gl_renderer->opaque_attribs,
4302 format,
4303 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004304 return -1;
4305 }
4306
4307 return 0;
4308}
4309
4310static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004311init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004312{
Giulio Camuffo954f1832014-10-11 18:27:30 +03004313 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004314
Giulio Camuffo954f1832014-10-11 18:27:30 +03004315 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02004316 return -1;
4317
Giulio Camuffo954f1832014-10-11 18:27:30 +03004318 if (drm_backend_create_gl_renderer(b) < 0) {
4319 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04004320 return -1;
4321 }
4322
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004323 return 0;
4324}
4325
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004326static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004327init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004328{
Giulio Camuffo954f1832014-10-11 18:27:30 +03004329 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004330}
4331
Sergi Granellf4456222017-01-12 17:17:32 +00004332#ifdef HAVE_DRM_FORMATS_BLOB
4333static inline uint32_t *
4334formats_ptr(struct drm_format_modifier_blob *blob)
4335{
4336 return (uint32_t *)(((char *)blob) + blob->formats_offset);
4337}
4338
4339static inline struct drm_format_modifier *
4340modifiers_ptr(struct drm_format_modifier_blob *blob)
4341{
4342 return (struct drm_format_modifier *)
4343 (((char *)blob) + blob->modifiers_offset);
4344}
4345#endif
4346
4347/**
4348 * Populates the plane's formats array, using either the IN_FORMATS blob
4349 * property (if available), or the plane's format list if not.
4350 */
4351static int
4352drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
4353 const drmModeObjectProperties *props)
4354{
4355 unsigned i;
4356#ifdef HAVE_DRM_FORMATS_BLOB
4357 drmModePropertyBlobRes *blob;
4358 struct drm_format_modifier_blob *fmt_mod_blob;
4359 struct drm_format_modifier *blob_modifiers;
4360 uint32_t *blob_formats;
4361 uint32_t blob_id;
4362
4363 blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
4364 props,
4365 0);
4366 if (blob_id == 0)
4367 goto fallback;
4368
4369 blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
4370 if (!blob)
4371 goto fallback;
4372
4373 fmt_mod_blob = blob->data;
4374 blob_formats = formats_ptr(fmt_mod_blob);
4375 blob_modifiers = modifiers_ptr(fmt_mod_blob);
4376
4377 if (plane->count_formats != fmt_mod_blob->count_formats) {
4378 weston_log("DRM backend: format count differs between "
4379 "plane (%d) and IN_FORMATS (%d)\n",
4380 plane->count_formats,
4381 fmt_mod_blob->count_formats);
4382 weston_log("This represents a kernel bug; Weston is "
4383 "unable to continue.\n");
4384 abort();
4385 }
4386
4387 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
4388 uint32_t count_modifiers = 0;
4389 uint64_t *modifiers = NULL;
4390 unsigned j;
4391
4392 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
4393 struct drm_format_modifier *mod = &blob_modifiers[j];
4394
4395 if ((i < mod->offset) || (i > mod->offset + 63))
4396 continue;
4397 if (!(mod->formats & (1 << (i - mod->offset))))
4398 continue;
4399
4400 modifiers = realloc(modifiers,
4401 (count_modifiers + 1) *
4402 sizeof(modifiers[0]));
4403 assert(modifiers);
4404 modifiers[count_modifiers++] = mod->modifier;
4405 }
4406
4407 plane->formats[i].format = blob_formats[i];
4408 plane->formats[i].modifiers = modifiers;
4409 plane->formats[i].count_modifiers = count_modifiers;
4410 }
4411
4412 drmModeFreePropertyBlob(blob);
4413
4414 return 0;
4415
4416fallback:
4417#endif
4418 /* No IN_FORMATS blob available, so just use the old. */
4419 assert(plane->count_formats == kplane->count_formats);
4420 for (i = 0; i < kplane->count_formats; i++)
4421 plane->formats[i].format = kplane->formats[i];
4422
4423 return 0;
4424}
4425
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004426/**
Pekka Paalanenec272712014-06-05 11:22:25 +03004427 * Create a drm_plane for a hardware plane
4428 *
4429 * Creates one drm_plane structure for a hardware plane, and initialises its
4430 * properties and formats.
4431 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01004432 * In the absence of universal plane support, where KMS does not explicitly
4433 * expose the primary and cursor planes to userspace, this may also create
4434 * an 'internal' plane for internal management.
4435 *
Pekka Paalanenec272712014-06-05 11:22:25 +03004436 * This function does not add the plane to the list of usable planes in Weston
4437 * itself; the caller is responsible for this.
4438 *
4439 * Call drm_plane_destroy to clean up the plane.
4440 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01004441 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +03004442 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +01004443 * @param kplane DRM plane to create, or NULL if creating internal plane
4444 * @param output Output to create internal plane for, or NULL
4445 * @param type Type to use when creating internal plane, or invalid
4446 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +03004447 */
4448static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +01004449drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
4450 struct drm_output *output, enum wdrm_plane_type type,
4451 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +03004452{
4453 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01004454 drmModeObjectProperties *props;
Sergi Granellf4456222017-01-12 17:17:32 +00004455 uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01004456
Daniel Stone2ba17f42015-05-19 20:02:41 +01004457 plane = zalloc(sizeof(*plane) +
Sergi Granellf4456222017-01-12 17:17:32 +00004458 (sizeof(plane->formats[0]) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +03004459 if (!plane) {
4460 weston_log("%s: out of memory\n", __func__);
4461 return NULL;
4462 }
4463
4464 plane->backend = b;
Sergi Granellf4456222017-01-12 17:17:32 +00004465 plane->count_formats = num_formats;
Daniel Stonebc15f682016-11-14 16:57:01 +00004466 plane->state_cur = drm_plane_state_alloc(NULL, plane);
4467 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +03004468
Daniel Stone2ba17f42015-05-19 20:02:41 +01004469 if (kplane) {
4470 plane->possible_crtcs = kplane->possible_crtcs;
4471 plane->plane_id = kplane->plane_id;
Daniel Stone2ba17f42015-05-19 20:02:41 +01004472
4473 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
4474 DRM_MODE_OBJECT_PLANE);
4475 if (!props) {
4476 weston_log("couldn't get plane properties\n");
4477 goto err;
4478 }
4479 drm_property_info_populate(b, plane_props, plane->props,
4480 WDRM_PLANE__COUNT, props);
4481 plane->type =
4482 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
4483 props,
4484 WDRM_PLANE_TYPE__COUNT);
Sergi Granellf4456222017-01-12 17:17:32 +00004485
4486 if (drm_plane_populate_formats(plane, kplane, props) < 0) {
4487 drmModeFreeObjectProperties(props);
4488 goto err;
4489 }
4490
Daniel Stone2ba17f42015-05-19 20:02:41 +01004491 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01004492 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01004493 else {
4494 plane->possible_crtcs = (1 << output->pipe);
4495 plane->plane_id = 0;
4496 plane->count_formats = 1;
Sergi Granellf4456222017-01-12 17:17:32 +00004497 plane->formats[0].format = format;
Daniel Stone2ba17f42015-05-19 20:02:41 +01004498 plane->type = type;
4499 }
4500
4501 if (plane->type == WDRM_PLANE_TYPE__COUNT)
4502 goto err_props;
4503
4504 /* With universal planes, everything is a DRM plane; without
4505 * universal planes, the only DRM planes are overlay planes.
4506 * Everything else is a fake plane. */
4507 if (b->universal_planes) {
4508 assert(kplane);
4509 } else {
4510 if (kplane)
4511 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
4512 else
4513 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
4514 output);
4515 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01004516
Pekka Paalanenec272712014-06-05 11:22:25 +03004517 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01004518 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +03004519
4520 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +01004521
4522err_props:
4523 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
4524err:
4525 drm_plane_state_free(plane->state_cur, true);
4526 free(plane);
4527 return NULL;
4528}
4529
4530/**
4531 * Find, or create, a special-purpose plane
4532 *
4533 * Primary and cursor planes are a special case, in that before universal
4534 * planes, they are driven by non-plane API calls. Without universal plane
4535 * support, the only way to configure a primary plane is via drmModeSetCrtc,
4536 * and the only way to configure a cursor plane is drmModeSetCursor2.
4537 *
4538 * Although they may actually be regular planes in the hardware, without
4539 * universal plane support, these planes are not actually exposed to
4540 * userspace in the regular plane list.
4541 *
4542 * However, for ease of internal tracking, we want to manage all planes
4543 * through the same drm_plane structures. Therefore, when we are running
4544 * without universal plane support, we create fake drm_plane structures
4545 * to track these planes.
4546 *
4547 * @param b DRM backend
4548 * @param output Output to use for plane
4549 * @param type Type of plane
4550 */
4551static struct drm_plane *
4552drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
4553 enum wdrm_plane_type type)
4554{
4555 struct drm_plane *plane;
4556
4557 if (!b->universal_planes) {
4558 uint32_t format;
4559
4560 switch (type) {
4561 case WDRM_PLANE_TYPE_CURSOR:
4562 format = GBM_FORMAT_ARGB8888;
4563 break;
Daniel Stonee2e80132018-01-16 15:37:33 +00004564 case WDRM_PLANE_TYPE_PRIMARY:
4565 /* We don't know what formats the primary plane supports
4566 * before universal planes, so we just assume that the
4567 * GBM format works; however, this isn't set until after
4568 * the output is created. */
4569 format = 0;
4570 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +01004571 default:
4572 assert(!"invalid type in drm_output_find_special_plane");
4573 break;
4574 }
4575
4576 return drm_plane_create(b, NULL, output, type, format);
4577 }
4578
4579 wl_list_for_each(plane, &b->plane_list, link) {
4580 struct drm_output *tmp;
4581 bool found_elsewhere = false;
4582
4583 if (plane->type != type)
4584 continue;
4585 if (!drm_plane_is_available(plane, output))
4586 continue;
4587
4588 /* On some platforms, primary/cursor planes can roam
4589 * between different CRTCs, so make sure we don't claim the
4590 * same plane for two outputs. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01004591 wl_list_for_each(tmp, &b->compositor->output_list,
4592 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +00004593 if (tmp->cursor_plane == plane ||
4594 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +01004595 found_elsewhere = true;
4596 break;
4597 }
4598 }
4599
4600 if (found_elsewhere)
4601 continue;
4602
4603 plane->possible_crtcs = (1 << output->pipe);
4604 return plane;
4605 }
4606
4607 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +03004608}
4609
4610/**
4611 * Destroy one DRM plane
4612 *
4613 * Destroy a DRM plane, removing it from screen and releasing its retained
4614 * buffers in the process. The counterpart to drm_plane_create.
4615 *
4616 * @param plane Plane to deallocate (will be freed)
4617 */
4618static void
4619drm_plane_destroy(struct drm_plane *plane)
4620{
Daniel Stone2ba17f42015-05-19 20:02:41 +01004621 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
4622 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
4623 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +00004624 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01004625 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +03004626 weston_plane_release(&plane->base);
4627 wl_list_remove(&plane->link);
4628 free(plane);
4629}
4630
4631/**
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09004632 * Create a drm_plane for virtual output
4633 *
4634 * Call drm_virtual_plane_destroy to clean up the plane.
4635 *
4636 * @param b DRM compositor backend
4637 * @param output Output to create internal plane for
4638 */
4639static struct drm_plane *
4640drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
4641{
4642 struct drm_plane *plane;
4643
4644 /* num of formats is one */
4645 plane = zalloc(sizeof(*plane) + sizeof(plane->formats[0]));
4646 if (!plane) {
4647 weston_log("%s: out of memory\n", __func__);
4648 return NULL;
4649 }
4650
4651 plane->type = WDRM_PLANE_TYPE_PRIMARY;
4652 plane->backend = b;
4653 plane->state_cur = drm_plane_state_alloc(NULL, plane);
4654 plane->state_cur->complete = true;
4655 plane->formats[0].format = output->gbm_format;
4656 plane->count_formats = 1;
Scott Anderson99553752019-01-28 15:40:55 +13004657 if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && b->fb_modifiers) {
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09004658 uint64_t *modifiers = zalloc(sizeof *modifiers);
4659 if (modifiers) {
4660 *modifiers = DRM_FORMAT_MOD_LINEAR;
4661 plane->formats[0].modifiers = modifiers;
4662 plane->formats[0].count_modifiers = 1;
4663 }
4664 }
4665
4666 weston_plane_init(&plane->base, b->compositor, 0, 0);
4667 wl_list_insert(&b->plane_list, &plane->link);
4668
4669 return plane;
4670}
4671
4672/**
4673 * Destroy one DRM plane
4674 *
4675 * @param plane Plane to deallocate (will be freed)
4676 */
4677static void
4678drm_virtual_plane_destroy(struct drm_plane *plane)
4679{
4680 drm_plane_state_free(plane->state_cur, true);
4681 weston_plane_release(&plane->base);
4682 wl_list_remove(&plane->link);
4683 if (plane->formats[0].modifiers)
4684 free(plane->formats[0].modifiers);
4685 free(plane);
4686}
4687
4688/**
Pekka Paalanenec272712014-06-05 11:22:25 +03004689 * Initialise sprites (overlay planes)
4690 *
4691 * Walk the list of provided DRM planes, and add overlay planes.
4692 *
4693 * Call destroy_sprites to free these planes.
4694 *
4695 * @param b DRM compositor backend
4696 */
4697static void
4698create_sprites(struct drm_backend *b)
4699{
4700 drmModePlaneRes *kplane_res;
4701 drmModePlane *kplane;
4702 struct drm_plane *drm_plane;
4703 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +03004704 kplane_res = drmModeGetPlaneResources(b->drm.fd);
4705 if (!kplane_res) {
4706 weston_log("failed to get plane resources: %s\n",
4707 strerror(errno));
4708 return;
4709 }
4710
4711 for (i = 0; i < kplane_res->count_planes; i++) {
4712 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
4713 if (!kplane)
4714 continue;
4715
Daniel Stone2ba17f42015-05-19 20:02:41 +01004716 drm_plane = drm_plane_create(b, kplane, NULL,
4717 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +03004718 drmModeFreePlane(kplane);
4719 if (!drm_plane)
4720 continue;
4721
Daniel Stone085d2b92015-05-21 00:00:57 +01004722 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
4723 weston_compositor_stack_plane(b->compositor,
4724 &drm_plane->base,
4725 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +03004726 }
4727
4728 drmModeFreePlaneResources(kplane_res);
4729}
4730
4731/**
4732 * Clean up sprites (overlay planes)
4733 *
4734 * The counterpart to create_sprites.
4735 *
4736 * @param b DRM compositor backend
4737 */
4738static void
4739destroy_sprites(struct drm_backend *b)
4740{
4741 struct drm_plane *plane, *next;
4742
Daniel Stone085d2b92015-05-21 00:00:57 +01004743 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03004744 drm_plane_destroy(plane);
4745}
4746
Pekka Paalanendc14fd42017-11-10 15:31:39 +02004747static uint32_t
4748drm_refresh_rate_mHz(const drmModeModeInfo *info)
4749{
4750 uint64_t refresh;
4751
4752 /* Calculate higher precision (mHz) refresh rate */
4753 refresh = (info->clock * 1000000LL / info->htotal +
4754 info->vtotal / 2) / info->vtotal;
4755
4756 if (info->flags & DRM_MODE_FLAG_INTERLACE)
4757 refresh *= 2;
4758 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
4759 refresh /= 2;
4760 if (info->vscan > 1)
4761 refresh /= info->vscan;
4762
4763 return refresh;
4764}
4765
Pekka Paalanenec272712014-06-05 11:22:25 +03004766/**
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004767 * Add a mode to output's mode list
4768 *
4769 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
4770 * output's mode list.
4771 *
4772 * @param output DRM output to add mode to
4773 * @param info DRM mode structure to add
4774 * @returns Newly-allocated Weston/DRM mode structure
4775 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03004776static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004777drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004778{
4779 struct drm_mode *mode;
4780
4781 mode = malloc(sizeof *mode);
4782 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03004783 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004784
4785 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02004786 mode->base.width = info->hdisplay;
4787 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04004788
Pekka Paalanendc14fd42017-11-10 15:31:39 +02004789 mode->base.refresh = drm_refresh_rate_mHz(info);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004790 mode->mode_info = *info;
Daniel Stoned5526cb2016-11-16 10:54:10 +00004791 mode->blob_id = 0;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04004792
4793 if (info->type & DRM_MODE_TYPE_PREFERRED)
4794 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
4795
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304796 mode->base.aspect_ratio = drm_to_weston_mode_aspect_ratio(info->flags);
4797
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004798 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
4799
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03004800 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004801}
4802
Daniel Stoned5526cb2016-11-16 10:54:10 +00004803/**
4804 * Destroys a mode, and removes it from the list.
4805 */
4806static void
4807drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
4808{
4809 if (mode->blob_id)
4810 drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
4811 wl_list_remove(&mode->base.link);
4812 free(mode);
4813}
4814
Pekka Paalanen383b3af2017-09-11 14:40:48 +03004815/** Destroy a list of drm_modes
4816 *
4817 * @param backend The backend for releasing mode property blobs.
4818 * @param mode_list The list linked by drm_mode::base.link.
4819 */
4820static void
4821drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
4822{
4823 struct drm_mode *mode, *next;
4824
4825 wl_list_for_each_safe(mode, next, mode_list, base.link)
4826 drm_output_destroy_mode(backend, mode);
4827}
4828
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004829static int
4830drm_subpixel_to_wayland(int drm_value)
4831{
4832 switch (drm_value) {
4833 default:
4834 case DRM_MODE_SUBPIXEL_UNKNOWN:
4835 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
4836 case DRM_MODE_SUBPIXEL_NONE:
4837 return WL_OUTPUT_SUBPIXEL_NONE;
4838 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
4839 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
4840 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
4841 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
4842 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
4843 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
4844 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
4845 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
4846 }
4847}
4848
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004849/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004850static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +03004851drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004852{
4853 long brightness, max_brightness, norm;
4854
Pekka Paalanence724242017-09-04 12:21:24 +03004855 brightness = backlight_get_brightness(head->backlight);
4856 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004857
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004858 /* convert it on a scale of 0 to 255 */
4859 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004860
4861 return (uint32_t) norm;
4862}
4863
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004864/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004865static void
4866drm_set_backlight(struct weston_output *output_base, uint32_t value)
4867{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004868 struct drm_output *output = to_drm_output(output_base);
4869 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004870 long max_brightness, new_brightness;
4871
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04004872 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004873 return;
4874
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004875 wl_list_for_each(head, &output->base.head_list, base.output_link) {
4876 if (!head->backlight)
4877 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004878
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004879 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004880
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004881 /* get denormalized value */
4882 new_brightness = (value * max_brightness) / 255;
4883
4884 backlight_set_brightness(head->backlight, new_brightness);
4885 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004886}
4887
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02004888static void
4889drm_output_init_backlight(struct drm_output *output)
4890{
4891 struct weston_head *base;
4892 struct drm_head *head;
4893
4894 output->base.set_backlight = NULL;
4895
4896 wl_list_for_each(base, &output->base.head_list, output_link) {
4897 head = to_drm_head(base);
4898
4899 if (head->backlight) {
4900 weston_log("Initialized backlight for head '%s', device %s\n",
4901 head->base.name, head->backlight->path);
4902
4903 if (!output->base.set_backlight) {
4904 output->base.set_backlight = drm_set_backlight;
4905 output->base.backlight_current =
4906 drm_get_backlight(head);
4907 }
4908 }
4909 }
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02004910}
4911
Daniel Stonea08512f2016-11-08 17:46:10 +00004912/**
4913 * Power output on or off
4914 *
4915 * The DPMS/power level of an output is used to switch it on or off. This
4916 * is DRM's hook for doing so, which can called either as part of repaint,
4917 * or independently of the repaint loop.
4918 *
4919 * If we are called as part of repaint, we simply set the relevant bit in
4920 * state and return.
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09004921 *
4922 * This function is never called on a virtual output.
Daniel Stonea08512f2016-11-08 17:46:10 +00004923 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004924static void
4925drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
4926{
Armin Krezović545dba62016-08-05 15:54:18 +02004927 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00004928 struct drm_backend *b = to_drm_backend(output_base->compositor);
4929 struct drm_pending_state *pending_state = b->repaint_data;
4930 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01004931 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004932
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09004933 assert(!output->virtual);
4934
Daniel Stonea08512f2016-11-08 17:46:10 +00004935 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004936 return;
4937
Daniel Stonea08512f2016-11-08 17:46:10 +00004938 /* If we're being called during the repaint loop, then this is
4939 * simple: discard any previously-generated state, and create a new
4940 * state where we disable everything. When we come to flush, this
4941 * will be applied.
4942 *
4943 * However, we need to be careful: we can be called whilst another
4944 * output is in its repaint cycle (pending_state exists), but our
4945 * output still has an incomplete state application outstanding.
4946 * In that case, we need to wait until that completes. */
4947 if (pending_state && !output->state_last) {
4948 /* The repaint loop already sets DPMS on; we don't need to
4949 * explicitly set it on here, as it will already happen
4950 * whilst applying the repaint state. */
4951 if (level == WESTON_DPMS_ON)
4952 return;
4953
4954 state = drm_pending_state_get_output(pending_state, output);
4955 if (state)
4956 drm_output_state_free(state);
4957 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01004958 return;
4959 }
4960
Daniel Stonea08512f2016-11-08 17:46:10 +00004961 /* As we throw everything away when disabling, just send us back through
4962 * a repaint cycle. */
4963 if (level == WESTON_DPMS_ON) {
4964 if (output->dpms_off_pending)
4965 output->dpms_off_pending = 0;
4966 weston_output_schedule_repaint(output_base);
4967 return;
4968 }
4969
4970 /* If we've already got a request in the pipeline, then we need to
4971 * park our DPMS request until that request has quiesced. */
4972 if (output->state_last) {
4973 output->dpms_off_pending = 1;
4974 return;
4975 }
4976
4977 pending_state = drm_pending_state_alloc(b);
4978 drm_output_get_disable_state(pending_state, output);
4979 ret = drm_pending_state_apply_sync(pending_state);
4980 if (ret != 0)
4981 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004982}
4983
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004984static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004985 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
4986 [DRM_MODE_CONNECTOR_VGA] = "VGA",
4987 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
4988 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
4989 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
4990 [DRM_MODE_CONNECTOR_Composite] = "Composite",
4991 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
4992 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
4993 [DRM_MODE_CONNECTOR_Component] = "Component",
4994 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
4995 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
4996 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
4997 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
4998 [DRM_MODE_CONNECTOR_TV] = "TV",
4999 [DRM_MODE_CONNECTOR_eDP] = "eDP",
Pekka Paalanenab81f152015-08-24 14:27:07 +03005000#ifdef DRM_MODE_CONNECTOR_DSI
Pekka Paalanen89c49b32015-08-19 15:25:57 +03005001 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
5002 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Pekka Paalanenab81f152015-08-24 14:27:07 +03005003#endif
Stefan Agner30e283d2018-08-20 17:11:38 +02005004#ifdef DRM_MODE_CONNECTOR_DPI
5005 [DRM_MODE_CONNECTOR_DPI] = "DPI",
5006#endif
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04005007};
5008
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03005009/** Create a name given a DRM connector
5010 *
5011 * \param con The DRM connector whose type and id form the name.
5012 * \return A newly allocate string, or NULL on error. Must be free()'d
5013 * after use.
5014 *
5015 * The name does not identify the DRM display device.
5016 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03005017static char *
5018make_connector_name(const drmModeConnector *con)
5019{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03005020 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03005021 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03005022 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03005023
5024 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
5025 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03005026
5027 if (!type_name)
5028 type_name = "UNNAMED";
5029
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03005030 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
5031 if (ret < 0)
5032 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03005033
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03005034 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03005035}
5036
Daniel Stonee4256832017-04-04 17:54:27 +01005037static void drm_output_fini_cursor_egl(struct drm_output *output)
5038{
5039 unsigned int i;
5040
5041 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
5042 drm_fb_unref(output->gbm_cursor_fb[i]);
5043 output->gbm_cursor_fb[i] = NULL;
5044 }
5045}
5046
5047static int
5048drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
5049{
5050 unsigned int i;
5051
Daniel Stone2ba17f42015-05-19 20:02:41 +01005052 /* No point creating cursors if we don't have a plane for them. */
5053 if (!output->cursor_plane)
5054 return 0;
5055
Daniel Stonee4256832017-04-04 17:54:27 +01005056 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
5057 struct gbm_bo *bo;
5058
5059 bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
5060 GBM_FORMAT_ARGB8888,
5061 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
5062 if (!bo)
5063 goto err;
5064
5065 output->gbm_cursor_fb[i] =
Daniel Stonedb10df12016-12-08 13:15:58 +00005066 drm_fb_get_from_bo(bo, b, false, BUFFER_CURSOR);
Daniel Stonee4256832017-04-04 17:54:27 +01005067 if (!output->gbm_cursor_fb[i]) {
5068 gbm_bo_destroy(bo);
5069 goto err;
5070 }
5071 }
5072
5073 return 0;
5074
5075err:
5076 weston_log("cursor buffers unavailable, using gl cursors\n");
5077 b->cursors_are_broken = 1;
5078 drm_output_fini_cursor_egl(output);
5079 return -1;
5080}
5081
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005082/* Init output state that depends on gl or gbm */
5083static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03005084drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005085{
Derek Foremanc4cfe852015-05-15 12:12:40 -05005086 EGLint format[2] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01005087 output->gbm_format,
5088 fallback_format_for(output->gbm_format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05005089 };
Daniel Stonee4256832017-04-04 17:54:27 +01005090 int n_formats = 1;
Daniel Stone244244d2016-11-18 18:02:08 +00005091 struct weston_mode *mode = output->base.current_mode;
5092 struct drm_plane *plane = output->scanout_plane;
5093 unsigned int i;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02005094
Philipp Zabel5c8eef12019-03-06 11:12:47 +01005095 assert(output->gbm_surface == NULL);
5096
Daniel Stone244244d2016-11-18 18:02:08 +00005097 for (i = 0; i < plane->count_formats; i++) {
5098 if (plane->formats[i].format == output->gbm_format)
5099 break;
5100 }
5101
5102 if (i == plane->count_formats) {
5103 weston_log("format 0x%x not supported by output %s\n",
5104 output->gbm_format, output->base.name);
5105 return -1;
5106 }
5107
5108#ifdef HAVE_GBM_MODIFIERS
5109 if (plane->formats[i].count_modifiers > 0) {
5110 output->gbm_surface =
5111 gbm_surface_create_with_modifiers(b->gbm,
5112 mode->width,
5113 mode->height,
5114 output->gbm_format,
5115 plane->formats[i].modifiers,
5116 plane->formats[i].count_modifiers);
Daniel Stoneee1d9682019-01-31 00:02:25 +00005117 }
5118
5119 /* If allocating with modifiers fails, try again without. This can
5120 * happen when the KMS display device supports modifiers but the
5121 * GBM driver does not, e.g. the old i915 Mesa driver. */
5122 if (!output->gbm_surface)
Daniel Stone244244d2016-11-18 18:02:08 +00005123#endif
5124 {
5125 output->gbm_surface =
5126 gbm_surface_create(b->gbm, mode->width, mode->height,
5127 output->gbm_format,
Tomohito Esaki718a40b2018-01-31 17:50:15 +09005128 output->gbm_bo_flags);
Daniel Stone244244d2016-11-18 18:02:08 +00005129 }
5130
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01005131 if (!output->gbm_surface) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005132 weston_log("failed to create gbm surface\n");
5133 return -1;
5134 }
5135
Derek Foremanc4cfe852015-05-15 12:12:40 -05005136 if (format[1])
5137 n_formats = 2;
Miguel A. Vicoc095cde2016-05-18 17:43:00 +02005138 if (gl_renderer->output_window_create(&output->base,
5139 (EGLNativeWindowType)output->gbm_surface,
5140 output->gbm_surface,
5141 gl_renderer->opaque_attribs,
5142 format,
5143 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02005144 weston_log("failed to create gl renderer output state\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01005145 gbm_surface_destroy(output->gbm_surface);
Philipp Zabel5c8eef12019-03-06 11:12:47 +01005146 output->gbm_surface = NULL;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005147 return -1;
5148 }
5149
Daniel Stonee4256832017-04-04 17:54:27 +01005150 drm_output_init_cursor_egl(output, b);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005151
5152 return 0;
5153}
5154
Daniel Stone3e661f72016-11-04 17:24:06 +00005155static void
5156drm_output_fini_egl(struct drm_output *output)
5157{
Daniel Stonee2e80132018-01-16 15:37:33 +00005158 struct drm_backend *b = to_drm_backend(output->base.compositor);
5159
5160 /* Destroying the GBM surface will destroy all our GBM buffers,
5161 * regardless of refcount. Ensure we destroy them here. */
5162 if (!b->shutting_down &&
5163 output->scanout_plane->state_cur->fb &&
5164 output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
5165 drm_plane_state_free(output->scanout_plane->state_cur, true);
5166 output->scanout_plane->state_cur =
5167 drm_plane_state_alloc(NULL, output->scanout_plane);
5168 output->scanout_plane->state_cur->complete = true;
5169 }
5170
Daniel Stone3e661f72016-11-04 17:24:06 +00005171 gl_renderer->output_destroy(&output->base);
5172 gbm_surface_destroy(output->gbm_surface);
Philipp Zabel5c8eef12019-03-06 11:12:47 +01005173 output->gbm_surface = NULL;
Daniel Stonee4256832017-04-04 17:54:27 +01005174 drm_output_fini_cursor_egl(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00005175}
5176
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04005177static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03005178drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005179{
Hardeningff39efa2013-09-18 23:56:35 +02005180 int w = output->base.current_mode->width;
5181 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03005182 uint32_t format = output->gbm_format;
5183 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005184 unsigned int i;
Pekka Paalanendee412d2018-04-23 11:44:58 +02005185 uint32_t flags = 0;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005186
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03005187 switch (format) {
5188 case GBM_FORMAT_XRGB8888:
5189 pixman_format = PIXMAN_x8r8g8b8;
5190 break;
5191 case GBM_FORMAT_RGB565:
5192 pixman_format = PIXMAN_r5g6b5;
5193 break;
5194 default:
5195 weston_log("Unsupported pixman format 0x%x\n", format);
5196 return -1;
5197 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005198
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03005199 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005200 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03005201 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005202 if (!output->dumb[i])
5203 goto err;
5204
5205 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03005206 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005207 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00005208 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005209 if (!output->image[i])
5210 goto err;
5211 }
5212
Pekka Paalanendee412d2018-04-23 11:44:58 +02005213 if (b->use_pixman_shadow)
5214 flags |= PIXMAN_RENDERER_OUTPUT_USE_SHADOW;
5215
5216 if (pixman_renderer_output_create(&output->base, flags) < 0)
5217 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305218
Pekka Paalanendee412d2018-04-23 11:44:58 +02005219 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
5220 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005221
5222 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02005223 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005224
5225 return 0;
5226
5227err:
5228 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
5229 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01005230 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005231 if (output->image[i])
5232 pixman_image_unref(output->image[i]);
5233
5234 output->dumb[i] = NULL;
5235 output->image[i] = NULL;
5236 }
5237
5238 return -1;
5239}
5240
5241static void
5242drm_output_fini_pixman(struct drm_output *output)
5243{
Daniel Stonee2e80132018-01-16 15:37:33 +00005244 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005245 unsigned int i;
5246
Daniel Stonee2e80132018-01-16 15:37:33 +00005247 /* Destroying the Pixman surface will destroy all our buffers,
5248 * regardless of refcount. Ensure we destroy them here. */
5249 if (!b->shutting_down &&
5250 output->scanout_plane->state_cur->fb &&
5251 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
5252 drm_plane_state_free(output->scanout_plane->state_cur, true);
5253 output->scanout_plane->state_cur =
5254 drm_plane_state_alloc(NULL, output->scanout_plane);
5255 output->scanout_plane->state_cur->complete = true;
5256 }
5257
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005258 pixman_renderer_output_destroy(&output->base);
5259 pixman_region32_fini(&output->previous_damage);
5260
5261 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005262 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01005263 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005264 output->dumb[i] = NULL;
5265 output->image[i] = NULL;
5266 }
5267}
5268
Richard Hughes2b2092a2013-04-24 14:58:02 +01005269static void
5270edid_parse_string(const uint8_t *data, char text[])
5271{
5272 int i;
5273 int replaced = 0;
5274
5275 /* this is always 12 bytes, but we can't guarantee it's null
5276 * terminated or not junk. */
5277 strncpy(text, (const char *) data, 12);
5278
Bryce Harrington9c7de162015-08-28 13:04:26 -07005279 /* guarantee our new string is null-terminated */
5280 text[12] = '\0';
5281
Richard Hughes2b2092a2013-04-24 14:58:02 +01005282 /* remove insane chars */
5283 for (i = 0; text[i] != '\0'; i++) {
5284 if (text[i] == '\n' ||
5285 text[i] == '\r') {
5286 text[i] = '\0';
5287 break;
5288 }
5289 }
5290
5291 /* ensure string is printable */
5292 for (i = 0; text[i] != '\0'; i++) {
5293 if (!isprint(text[i])) {
5294 text[i] = '-';
5295 replaced++;
5296 }
5297 }
5298
5299 /* if the string is random junk, ignore the string */
5300 if (replaced > 4)
5301 text[0] = '\0';
5302}
5303
5304#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
5305#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
5306#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
5307#define EDID_OFFSET_DATA_BLOCKS 0x36
5308#define EDID_OFFSET_LAST_BLOCK 0x6c
5309#define EDID_OFFSET_PNPID 0x08
5310#define EDID_OFFSET_SERIAL 0x0c
5311
5312static int
5313edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
5314{
5315 int i;
5316 uint32_t serial_number;
5317
5318 /* check header */
5319 if (length < 128)
5320 return -1;
5321 if (data[0] != 0x00 || data[1] != 0xff)
5322 return -1;
5323
5324 /* decode the PNP ID from three 5 bit words packed into 2 bytes
5325 * /--08--\/--09--\
5326 * 7654321076543210
5327 * |\---/\---/\---/
5328 * R C1 C2 C3 */
5329 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
5330 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
5331 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
5332 edid->pnp_id[3] = '\0';
5333
5334 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
5335 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
5336 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
5337 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
5338 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
5339 if (serial_number > 0)
5340 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
5341
5342 /* parse EDID data */
5343 for (i = EDID_OFFSET_DATA_BLOCKS;
5344 i <= EDID_OFFSET_LAST_BLOCK;
5345 i += 18) {
5346 /* ignore pixel clock data */
5347 if (data[i] != 0)
5348 continue;
5349 if (data[i+2] != 0)
5350 continue;
5351
5352 /* any useful blocks? */
5353 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
5354 edid_parse_string(&data[i+5],
5355 edid->monitor_name);
5356 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
5357 edid_parse_string(&data[i+5],
5358 edid->serial_number);
5359 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
5360 edid_parse_string(&data[i+5],
5361 edid->eisa_id);
5362 }
5363 }
5364 return 0;
5365}
5366
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03005367/** Parse monitor make, model and serial from EDID
5368 *
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005369 * \param head The head whose \c drm_edid to fill in.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03005370 * \param props The DRM connector properties to get the EDID from.
5371 * \param make[out] The monitor make (PNP ID).
5372 * \param model[out] The monitor model (name).
5373 * \param serial_number[out] The monitor serial number.
5374 *
5375 * Each of \c *make, \c *model and \c *serial_number are set only if the
5376 * information is found in the EDID. The pointers they are set to must not
5377 * be free()'d explicitly, instead they get implicitly freed when the
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005378 * \c drm_head is destroyed.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03005379 */
Richard Hughes2b2092a2013-04-24 14:58:02 +01005380static void
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005381find_and_parse_output_edid(struct drm_head *head,
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03005382 drmModeObjectPropertiesPtr props,
5383 const char **make,
5384 const char **model,
5385 const char **serial_number)
Richard Hughes2b2092a2013-04-24 14:58:02 +01005386{
5387 drmModePropertyBlobPtr edid_blob = NULL;
Daniel Stone02cf4662017-03-03 16:19:39 +00005388 uint32_t blob_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +01005389 int rc;
5390
Daniel Stone02cf4662017-03-03 16:19:39 +00005391 blob_id =
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005392 drm_property_get_value(&head->props_conn[WDRM_CONNECTOR_EDID],
Daniel Stone02cf4662017-03-03 16:19:39 +00005393 props, 0);
5394 if (!blob_id)
5395 return;
5396
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005397 edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id);
Richard Hughes2b2092a2013-04-24 14:58:02 +01005398 if (!edid_blob)
5399 return;
5400
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005401 rc = edid_parse(&head->edid,
Richard Hughes2b2092a2013-04-24 14:58:02 +01005402 edid_blob->data,
5403 edid_blob->length);
5404 if (!rc) {
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005405 if (head->edid.pnp_id[0] != '\0')
5406 *make = head->edid.pnp_id;
5407 if (head->edid.monitor_name[0] != '\0')
5408 *model = head->edid.monitor_name;
5409 if (head->edid.serial_number[0] != '\0')
5410 *serial_number = head->edid.serial_number;
Richard Hughes2b2092a2013-04-24 14:58:02 +01005411 }
5412 drmModeFreePropertyBlob(edid_blob);
5413}
5414
Philipp Zabel61dc4ca2018-08-30 17:39:51 +02005415static bool
5416check_non_desktop(struct drm_head *head, drmModeObjectPropertiesPtr props)
5417{
5418 struct drm_property_info *non_desktop_info =
5419 &head->props_conn[WDRM_CONNECTOR_NON_DESKTOP];
5420
5421 return drm_property_get_value(non_desktop_info, props, 0);
5422}
5423
Kristian Høgsberga30989a2013-05-23 17:23:15 -04005424static int
5425parse_modeline(const char *s, drmModeModeInfo *mode)
5426{
5427 char hsync[16];
5428 char vsync[16];
5429 float fclock;
5430
Pekka Paalanendc4e3c62017-12-05 15:37:41 +02005431 memset(mode, 0, sizeof *mode);
5432
Kristian Høgsberga30989a2013-05-23 17:23:15 -04005433 mode->type = DRM_MODE_TYPE_USERDEF;
5434 mode->hskew = 0;
5435 mode->vscan = 0;
5436 mode->vrefresh = 0;
5437 mode->flags = 0;
5438
Rob Bradford307e09e2013-07-26 16:29:40 +01005439 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04005440 &fclock,
5441 &mode->hdisplay,
5442 &mode->hsync_start,
5443 &mode->hsync_end,
5444 &mode->htotal,
5445 &mode->vdisplay,
5446 &mode->vsync_start,
5447 &mode->vsync_end,
5448 &mode->vtotal, hsync, vsync) != 11)
5449 return -1;
5450
5451 mode->clock = fclock * 1000;
Guido Günther92278e02018-06-26 20:40:08 +02005452 if (strcasecmp(hsync, "+hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04005453 mode->flags |= DRM_MODE_FLAG_PHSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02005454 else if (strcasecmp(hsync, "-hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04005455 mode->flags |= DRM_MODE_FLAG_NHSYNC;
5456 else
5457 return -1;
5458
Guido Günther92278e02018-06-26 20:40:08 +02005459 if (strcasecmp(vsync, "+vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04005460 mode->flags |= DRM_MODE_FLAG_PVSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02005461 else if (strcasecmp(vsync, "-vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04005462 mode->flags |= DRM_MODE_FLAG_NVSYNC;
5463 else
5464 return -1;
5465
Emmanuel Gil Peyrota62138b2016-05-02 22:40:11 +01005466 snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
5467 mode->hdisplay, mode->vdisplay, fclock);
5468
Kristian Høgsberga30989a2013-05-23 17:23:15 -04005469 return 0;
5470}
5471
Rob Bradford66bd9f52013-06-25 18:56:42 +01005472static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03005473setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01005474 struct weston_output *output,
5475 const char *s)
5476{
5477 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05005478 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01005479 struct udev_seat *seat;
5480
Giulio Camuffo954f1832014-10-11 18:27:30 +03005481 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05005482 if (!seat)
5483 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01005484
Derek Foreman0720ea32015-07-15 13:00:35 -05005485 seat->base.output = output;
5486
Derek Foreman1281a362015-07-31 16:55:32 -05005487 pointer = weston_seat_get_pointer(&seat->base);
5488 if (pointer)
5489 weston_pointer_clamp(pointer,
5490 &pointer->x,
5491 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01005492 }
5493}
5494
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005495static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03005496drm_output_attach_head(struct weston_output *output_base,
5497 struct weston_head *head_base)
5498{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02005499 struct drm_backend *b = to_drm_backend(output_base->compositor);
5500
Pekka Paalanenc112f002017-08-28 16:27:20 +03005501 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
5502 return -1;
5503
Pekka Paalanend5f98d82017-12-08 14:45:00 +02005504 if (!output_base->enabled)
5505 return 0;
5506
5507 /* XXX: ensure the configuration will work.
5508 * This is actually impossible without major infrastructure
5509 * work. */
5510
5511 /* Need to go through modeset to add connectors. */
5512 /* XXX: Ideally we'd do this per-output, not globally. */
5513 /* XXX: Doing it globally, what guarantees another output's update
5514 * will not clear the flag before this output is updated?
5515 */
5516 b->state_invalid = true;
5517
5518 weston_output_schedule_repaint(output_base);
5519
Pekka Paalanenc112f002017-08-28 16:27:20 +03005520 return 0;
5521}
5522
Pekka Paalanen7f853792017-11-29 14:33:33 +02005523static void
5524drm_output_detach_head(struct weston_output *output_base,
5525 struct weston_head *head_base)
5526{
5527 struct drm_backend *b = to_drm_backend(output_base->compositor);
5528
5529 if (!output_base->enabled)
5530 return;
5531
5532 /* Need to go through modeset to drop connectors that should no longer
5533 * be driven. */
5534 /* XXX: Ideally we'd do this per-output, not globally. */
5535 b->state_invalid = true;
5536
5537 weston_output_schedule_repaint(output_base);
5538}
5539
Pekka Paalanenc112f002017-08-28 16:27:20 +03005540static int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005541parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005542{
Pekka Paalanen62a94362018-09-26 14:33:36 +03005543 const struct pixel_format_info *pinfo;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005544
Pekka Paalanen62a94362018-09-26 14:33:36 +03005545 if (s == NULL) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005546 *gbm_format = default_value;
Pekka Paalanen62a94362018-09-26 14:33:36 +03005547
5548 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005549 }
5550
Pekka Paalanen62a94362018-09-26 14:33:36 +03005551 pinfo = pixel_format_get_info_by_drm_name(s);
5552 if (!pinfo) {
5553 weston_log("fatal: unrecognized pixel format: %s\n", s);
5554
5555 return -1;
5556 }
5557
5558 /* GBM formats and DRM formats are identical. */
5559 *gbm_format = pinfo->format;
5560
5561 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005562}
5563
Pekka Paalanenf005f252017-11-10 16:34:39 +02005564static uint32_t
5565u32distance(uint32_t a, uint32_t b)
5566{
5567 if (a < b)
5568 return b - a;
5569 else
5570 return a - b;
5571}
5572
5573/** Choose equivalent mode
5574 *
5575 * If the two modes are not equivalent, return NULL.
5576 * Otherwise return the mode that is more likely to work in place of both.
5577 *
5578 * None of the fuzzy matching criteria in this function have any justification.
5579 *
5580 * typedef struct _drmModeModeInfo {
5581 * uint32_t clock;
5582 * uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
5583 * uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
5584 *
5585 * uint32_t vrefresh;
5586 *
5587 * uint32_t flags;
5588 * uint32_t type;
5589 * char name[DRM_DISPLAY_MODE_LEN];
5590 * } drmModeModeInfo, *drmModeModeInfoPtr;
5591 */
5592static const drmModeModeInfo *
5593drm_mode_pick_equivalent(const drmModeModeInfo *a, const drmModeModeInfo *b)
5594{
5595 uint32_t refresh_a, refresh_b;
5596
5597 if (a->hdisplay != b->hdisplay || a->vdisplay != b->vdisplay)
5598 return NULL;
5599
5600 if (a->flags != b->flags)
5601 return NULL;
5602
5603 /* kHz */
5604 if (u32distance(a->clock, b->clock) > 500)
5605 return NULL;
5606
5607 refresh_a = drm_refresh_rate_mHz(a);
5608 refresh_b = drm_refresh_rate_mHz(b);
5609 if (u32distance(refresh_a, refresh_b) > 50)
5610 return NULL;
5611
5612 if ((a->type ^ b->type) & DRM_MODE_TYPE_PREFERRED) {
5613 if (a->type & DRM_MODE_TYPE_PREFERRED)
5614 return a;
5615 else
5616 return b;
5617 }
5618
5619 return a;
5620}
5621
5622/* If the given mode info is not already in the list, add it.
5623 * If it is in the list, either keep the existing or replace it,
5624 * depending on which one is "better".
5625 */
5626static int
5627drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
5628{
5629 struct weston_mode *base;
5630 struct drm_mode *mode;
5631 struct drm_backend *backend;
5632 const drmModeModeInfo *chosen = NULL;
5633
5634 assert(info);
5635
5636 wl_list_for_each(base, &output->base.mode_list, link) {
5637 mode = to_drm_mode(base);
5638 chosen = drm_mode_pick_equivalent(&mode->mode_info, info);
5639 if (chosen)
5640 break;
5641 }
5642
5643 if (chosen == info) {
5644 backend = to_drm_backend(output->base.compositor);
5645 drm_output_destroy_mode(backend, mode);
5646 chosen = NULL;
5647 }
5648
5649 if (!chosen) {
5650 mode = drm_output_add_mode(output, info);
5651 if (!mode)
5652 return -1;
5653 }
5654 /* else { the equivalent mode is already in the list } */
5655
5656 return 0;
5657}
5658
Pekka Paalanen4be24852017-09-11 15:01:12 +03005659/** Rewrite the output's mode list
5660 *
5661 * @param output The output.
5662 * @return 0 on success, -1 on failure.
5663 *
5664 * Destroy all existing modes in the list, and reconstruct a new list from
5665 * scratch, based on the currently attached heads.
5666 *
5667 * On failure the output's mode list may contain some modes.
5668 */
5669static int
5670drm_output_update_modelist_from_heads(struct drm_output *output)
5671{
5672 struct drm_backend *backend = to_drm_backend(output->base.compositor);
5673 struct weston_head *head_base;
5674 struct drm_head *head;
Pekka Paalanen4be24852017-09-11 15:01:12 +03005675 int i;
Pekka Paalanenf005f252017-11-10 16:34:39 +02005676 int ret;
Pekka Paalanen4be24852017-09-11 15:01:12 +03005677
5678 assert(!output->base.enabled);
5679
5680 drm_mode_list_destroy(backend, &output->base.mode_list);
5681
Pekka Paalanenf005f252017-11-10 16:34:39 +02005682 wl_list_for_each(head_base, &output->base.head_list, output_link) {
5683 head = to_drm_head(head_base);
5684 for (i = 0; i < head->connector->count_modes; i++) {
5685 ret = drm_output_try_add_mode(output,
5686 &head->connector->modes[i]);
5687 if (ret < 0)
5688 return -1;
5689 }
Pekka Paalanen4be24852017-09-11 15:01:12 +03005690 }
5691
5692 return 0;
5693}
5694
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005695/**
5696 * Choose suitable mode for an output
5697 *
5698 * Find the most suitable mode to use for initial setup (or reconfiguration on
5699 * hotplug etc) for a DRM output.
5700 *
5701 * @param output DRM output to choose mode for
5702 * @param kind Strategy and preference to use when choosing mode
5703 * @param width Desired width for this output
5704 * @param height Desired height for this output
5705 * @param current_mode Mode currently being displayed on this output
5706 * @param modeline Manually-entered mode (may be NULL)
5707 * @returns A mode from the output's mode list, or NULL if none available
5708 */
5709static struct drm_mode *
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005710drm_output_choose_initial_mode(struct drm_backend *backend,
5711 struct drm_output *output,
5712 enum weston_drm_backend_output_mode mode,
Armin Krezović08368132016-09-30 14:11:05 +02005713 const char *modeline,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005714 const drmModeModeInfo *current_mode)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005715{
5716 struct drm_mode *preferred = NULL;
5717 struct drm_mode *current = NULL;
5718 struct drm_mode *configured = NULL;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305719 struct drm_mode *config_fall_back = NULL;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005720 struct drm_mode *best = NULL;
5721 struct drm_mode *drm_mode;
Armin Krezović08368132016-09-30 14:11:05 +02005722 drmModeModeInfo drm_modeline;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005723 int32_t width = 0;
5724 int32_t height = 0;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01005725 uint32_t refresh = 0;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305726 uint32_t aspect_width = 0;
5727 uint32_t aspect_height = 0;
5728 enum weston_mode_aspect_ratio aspect_ratio = WESTON_MODE_PIC_AR_NONE;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01005729 int n;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005730
Armin Krezović08368132016-09-30 14:11:05 +02005731 if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305732 n = sscanf(modeline, "%dx%d@%d %u:%u", &width, &height,
5733 &refresh, &aspect_width, &aspect_height);
5734 if (backend->aspect_ratio_supported && n == 5) {
5735 if (aspect_width == 4 && aspect_height == 3)
5736 aspect_ratio = WESTON_MODE_PIC_AR_4_3;
5737 else if (aspect_width == 16 && aspect_height == 9)
5738 aspect_ratio = WESTON_MODE_PIC_AR_16_9;
5739 else if (aspect_width == 64 && aspect_height == 27)
5740 aspect_ratio = WESTON_MODE_PIC_AR_64_27;
5741 else if (aspect_width == 256 && aspect_height == 135)
5742 aspect_ratio = WESTON_MODE_PIC_AR_256_135;
5743 else
5744 weston_log("Invalid modeline \"%s\" for output %s\n",
5745 modeline, output->base.name);
5746 }
5747 if (n != 2 && n != 3 && n != 5) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005748 width = -1;
5749
Armin Krezović08368132016-09-30 14:11:05 +02005750 if (parse_modeline(modeline, &drm_modeline) == 0) {
5751 configured = drm_output_add_mode(output, &drm_modeline);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005752 if (!configured)
5753 return NULL;
5754 } else {
5755 weston_log("Invalid modeline \"%s\" for output %s\n",
Armin Krezović08368132016-09-30 14:11:05 +02005756 modeline, output->base.name);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005757 }
5758 }
5759 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005760
5761 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005762 if (width == drm_mode->base.width &&
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01005763 height == drm_mode->base.height &&
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305764 (refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) {
5765 if (!backend->aspect_ratio_supported ||
5766 aspect_ratio == drm_mode->base.aspect_ratio)
5767 configured = drm_mode;
5768 else
5769 config_fall_back = drm_mode;
5770 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005771
comic fans7a5c5622016-03-17 14:29:27 +02005772 if (memcmp(current_mode, &drm_mode->mode_info,
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005773 sizeof *current_mode) == 0)
5774 current = drm_mode;
5775
5776 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
5777 preferred = drm_mode;
5778
5779 best = drm_mode;
5780 }
5781
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005782 if (current == NULL && current_mode->clock != 0) {
5783 current = drm_output_add_mode(output, current_mode);
5784 if (!current)
5785 return NULL;
5786 }
5787
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005788 if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005789 configured = current;
5790
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005791 if (configured)
5792 return configured;
5793
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305794 if (config_fall_back)
5795 return config_fall_back;
5796
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005797 if (preferred)
5798 return preferred;
5799
5800 if (current)
5801 return current;
5802
5803 if (best)
5804 return best;
5805
5806 weston_log("no available modes for %s\n", output->base.name);
5807 return NULL;
5808}
5809
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005810static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005811drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005812{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005813 int drm_fd = backend->drm.fd;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005814 drmModeEncoder *encoder;
5815 drmModeCrtc *crtc;
5816
5817 /* Get the current mode on the crtc that's currently driving
5818 * this connector. */
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005819 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005820 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005821 head->inherited_crtc_id = encoder->crtc_id;
5822
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005823 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
5824 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005825
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005826 if (crtc == NULL)
5827 return -1;
5828 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02005829 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005830 drmModeFreeCrtc(crtc);
5831 }
5832
5833 return 0;
5834}
5835
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005836static int
Armin Krezović08368132016-09-30 14:11:05 +02005837drm_output_set_mode(struct weston_output *base,
5838 enum weston_drm_backend_output_mode mode,
5839 const char *modeline)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005840{
Armin Krezović08368132016-09-30 14:11:05 +02005841 struct drm_output *output = to_drm_output(base);
5842 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005843 struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005844
Armin Krezović445b41b2016-10-09 23:48:16 +02005845 struct drm_mode *current;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005846
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09005847 if (output->virtual)
5848 return -1;
5849
Pekka Paalanen4be24852017-09-11 15:01:12 +03005850 if (drm_output_update_modelist_from_heads(output) < 0)
5851 return -1;
5852
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005853 current = drm_output_choose_initial_mode(b, output, mode, modeline,
5854 &head->inherited_mode);
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005855 if (!current)
Armin Krezović445b41b2016-10-09 23:48:16 +02005856 return -1;
Armin Krezović08368132016-09-30 14:11:05 +02005857
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005858 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02005859 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04005860
Armin Krezović08368132016-09-30 14:11:05 +02005861 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
5862 output->base.native_mode = output->base.current_mode;
5863 output->base.native_scale = output->base.current_scale;
5864
Armin Krezović08368132016-09-30 14:11:05 +02005865 return 0;
Armin Krezović08368132016-09-30 14:11:05 +02005866}
5867
5868static void
5869drm_output_set_gbm_format(struct weston_output *base,
5870 const char *gbm_format)
5871{
5872 struct drm_output *output = to_drm_output(base);
5873 struct drm_backend *b = to_drm_backend(base->compositor);
5874
5875 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
5876 output->gbm_format = b->gbm_format;
Daniel Stonee2e80132018-01-16 15:37:33 +00005877
5878 /* Without universal planes, we can't discover which formats are
5879 * supported by the primary plane; we just hope that the GBM format
5880 * works. */
5881 if (!b->universal_planes)
Sergi Granellf4456222017-01-12 17:17:32 +00005882 output->scanout_plane->formats[0].format = output->gbm_format;
Armin Krezović08368132016-09-30 14:11:05 +02005883}
5884
5885static void
5886drm_output_set_seat(struct weston_output *base,
5887 const char *seat)
5888{
5889 struct drm_output *output = to_drm_output(base);
5890 struct drm_backend *b = to_drm_backend(base->compositor);
5891
5892 setup_output_seat_constraint(b, &output->base,
5893 seat ? seat : "");
5894}
5895
5896static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03005897drm_output_init_gamma_size(struct drm_output *output)
5898{
5899 struct drm_backend *backend = to_drm_backend(output->base.compositor);
5900 drmModeCrtc *crtc;
5901
5902 assert(output->base.compositor);
5903 assert(output->crtc_id != 0);
5904 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
5905 if (!crtc)
5906 return -1;
5907
5908 output->base.gamma_size = crtc->gamma_size;
5909
5910 drmModeFreeCrtc(crtc);
5911
5912 return 0;
5913}
5914
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005915static uint32_t
5916drm_head_get_possible_crtcs_mask(struct drm_head *head)
5917{
5918 uint32_t possible_crtcs = 0;
5919 drmModeEncoder *encoder;
5920 int i;
5921
5922 for (i = 0; i < head->connector->count_encoders; i++) {
5923 encoder = drmModeGetEncoder(head->backend->drm.fd,
5924 head->connector->encoders[i]);
5925 if (!encoder)
5926 continue;
5927
5928 possible_crtcs |= encoder->possible_crtcs;
5929 drmModeFreeEncoder(encoder);
5930 }
5931
5932 return possible_crtcs;
5933}
5934
5935static int
5936drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
5937{
5938 int i;
5939
5940 for (i = 0; i < resources->count_crtcs; i++) {
5941 if (resources->crtcs[i] == crtc_id)
5942 return i;
5943 }
5944
5945 assert(0 && "unknown crtc id");
5946 return -1;
5947}
5948
5949/** Pick a CRTC that might be able to drive all attached connectors
5950 *
5951 * @param output The output whose attached heads to include.
5952 * @param resources The DRM KMS resources.
5953 * @return CRTC index, or -1 on failure or not found.
5954 */
5955static int
5956drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
5957{
5958 struct drm_backend *backend;
5959 struct weston_head *base;
5960 struct drm_head *head;
5961 uint32_t possible_crtcs = 0xffffffff;
5962 int existing_crtc[32];
5963 unsigned j, n = 0;
5964 uint32_t crtc_id;
5965 int best_crtc_index = -1;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005966 int fallback_crtc_index = -1;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005967 int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005968 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005969
5970 backend = to_drm_backend(output->base.compositor);
5971
5972 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
5973 * because it is more often set wrong than not in the kernel. */
5974
5975 /* Accumulate a mask of possible crtcs and find existing routings. */
5976 wl_list_for_each(base, &output->base.head_list, output_link) {
5977 head = to_drm_head(base);
5978
5979 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
5980
5981 crtc_id = head->inherited_crtc_id;
5982 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
5983 existing_crtc[n++] = drm_crtc_get_index(resources,
5984 crtc_id);
5985 }
5986
5987 /* Find a crtc that could drive each connector individually at least,
5988 * and prefer existing routings. */
5989 for (i = 0; i < resources->count_crtcs; i++) {
5990 crtc_id = resources->crtcs[i];
5991
5992 /* Could the crtc not drive each connector? */
5993 if (!(possible_crtcs & (1 << i)))
5994 continue;
5995
5996 /* Is the crtc already in use? */
5997 if (drm_output_find_by_crtc(backend, crtc_id))
5998 continue;
5999
6000 /* Try to preserve the existing CRTC -> connector routing;
6001 * it makes initialisation faster, and also since we have a
6002 * very dumb picking algorithm, may preserve a better
6003 * choice. */
6004 for (j = 0; j < n; j++) {
6005 if (existing_crtc[j] == i)
6006 return i;
6007 }
6008
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02006009 /* Check if any other head had existing routing to this CRTC.
6010 * If they did, this is not the best CRTC as it might be needed
6011 * for another output we haven't enabled yet. */
6012 match = false;
6013 wl_list_for_each(base, &backend->compositor->head_list,
6014 compositor_link) {
6015 head = to_drm_head(base);
6016
6017 if (head->base.output == &output->base)
6018 continue;
6019
6020 if (weston_head_is_enabled(&head->base))
6021 continue;
6022
6023 if (head->inherited_crtc_id == crtc_id) {
6024 match = true;
6025 break;
6026 }
6027 }
6028 if (!match)
6029 best_crtc_index = i;
6030
6031 fallback_crtc_index = i;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02006032 }
6033
6034 if (best_crtc_index != -1)
6035 return best_crtc_index;
6036
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02006037 if (fallback_crtc_index != -1)
6038 return fallback_crtc_index;
6039
Pekka Paalanen27cc4812017-11-20 13:31:06 +02006040 /* Likely possible_crtcs was empty due to asking for clones,
6041 * but since the DRM documentation says the kernel lies, let's
6042 * pick one crtc anyway. Trial and error is the only way to
6043 * be sure if something doesn't work. */
6044
6045 /* First pick any existing assignment. */
6046 for (j = 0; j < n; j++) {
6047 crtc_id = resources->crtcs[existing_crtc[j]];
6048 if (!drm_output_find_by_crtc(backend, crtc_id))
6049 return existing_crtc[j];
6050 }
6051
6052 /* Otherwise pick any available crtc. */
6053 for (i = 0; i < resources->count_crtcs; i++) {
6054 crtc_id = resources->crtcs[i];
6055
6056 if (!drm_output_find_by_crtc(backend, crtc_id))
6057 return i;
6058 }
6059
6060 return -1;
6061}
6062
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03006063/** Allocate a CRTC for the output
6064 *
6065 * @param output The output with no allocated CRTC.
6066 * @param resources DRM KMS resources.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03006067 * @return 0 on success, -1 on failure.
6068 *
Pekka Paalanen27cc4812017-11-20 13:31:06 +02006069 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03006070 * for the output, and loads the CRTC properties.
6071 *
6072 * Populates the cursor and scanout planes.
6073 *
6074 * On failure, the output remains without a CRTC.
6075 */
6076static int
Pekka Paalanen27cc4812017-11-20 13:31:06 +02006077drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03006078{
6079 struct drm_backend *b = to_drm_backend(output->base.compositor);
6080 drmModeObjectPropertiesPtr props;
6081 int i;
6082
6083 assert(output->crtc_id == 0);
6084
Pekka Paalanen27cc4812017-11-20 13:31:06 +02006085 i = drm_output_pick_crtc(output, resources);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03006086 if (i < 0) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02006087 weston_log("Output '%s': No available CRTCs.\n",
6088 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03006089 return -1;
6090 }
6091
6092 output->crtc_id = resources->crtcs[i];
6093 output->pipe = i;
6094
6095 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
6096 DRM_MODE_OBJECT_CRTC);
6097 if (!props) {
6098 weston_log("failed to get CRTC properties\n");
6099 goto err_crtc;
6100 }
6101 drm_property_info_populate(b, crtc_props, output->props_crtc,
6102 WDRM_CRTC__COUNT, props);
6103 drmModeFreeObjectProperties(props);
6104
6105 output->scanout_plane =
6106 drm_output_find_special_plane(b, output,
6107 WDRM_PLANE_TYPE_PRIMARY);
6108 if (!output->scanout_plane) {
6109 weston_log("Failed to find primary plane for output %s\n",
6110 output->base.name);
6111 goto err_crtc;
6112 }
6113
6114 /* Failing to find a cursor plane is not fatal, as we'll fall back
6115 * to software cursor. */
6116 output->cursor_plane =
6117 drm_output_find_special_plane(b, output,
6118 WDRM_PLANE_TYPE_CURSOR);
6119
Pekka Paalanen663d5e92017-09-08 13:32:40 +03006120 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
6121
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03006122 return 0;
6123
6124err_crtc:
6125 output->crtc_id = 0;
6126 output->pipe = 0;
6127
6128 return -1;
6129}
6130
6131/** Free the CRTC from the output
6132 *
6133 * @param output The output whose CRTC to deallocate.
6134 *
6135 * The CRTC reserved for the given output becomes free to use again.
6136 */
6137static void
6138drm_output_fini_crtc(struct drm_output *output)
6139{
6140 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03006141 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03006142
6143 if (!b->universal_planes && !b->shutting_down) {
6144 /* With universal planes, the 'special' planes are allocated at
6145 * startup, freed at shutdown, and live on the plane list in
6146 * between. We want the planes to continue to exist and be freed
6147 * up for other outputs.
6148 *
6149 * Without universal planes, our special planes are
6150 * pseudo-planes allocated at output creation, freed at output
6151 * destruction, and not usable by other outputs.
6152 *
6153 * On the other hand, if the compositor is already shutting down,
6154 * the plane has already been destroyed.
6155 */
6156 if (output->cursor_plane)
6157 drm_plane_destroy(output->cursor_plane);
6158 if (output->scanout_plane)
6159 drm_plane_destroy(output->scanout_plane);
6160 }
6161
6162 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03006163
6164 assert(output->crtc_id != 0);
6165
6166 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
6167 *unused = output->crtc_id;
6168
6169 /* Force resetting unused CRTCs */
6170 b->state_invalid = true;
6171
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03006172 output->crtc_id = 0;
6173 output->cursor_plane = NULL;
6174 output->scanout_plane = NULL;
6175}
6176
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02006177static void
6178drm_output_print_modes(struct drm_output *output)
6179{
6180 struct weston_mode *m;
6181 struct drm_mode *dm;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05306182 const char *aspect_ratio;
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02006183
6184 wl_list_for_each(m, &output->base.mode_list, link) {
6185 dm = to_drm_mode(m);
6186
Ankit Nautiyala21c3932097-03-19 00:24:57 +05306187 aspect_ratio = aspect_ratio_to_string(m->aspect_ratio);
6188 weston_log_continue(STAMP_SPACE "%dx%d@%.1f%s%s%s, %.1f MHz\n",
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02006189 m->width, m->height, m->refresh / 1000.0,
Ankit Nautiyala21c3932097-03-19 00:24:57 +05306190 aspect_ratio,
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02006191 m->flags & WL_OUTPUT_MODE_PREFERRED ?
6192 ", preferred" : "",
6193 m->flags & WL_OUTPUT_MODE_CURRENT ?
6194 ", current" : "",
6195 dm->mode_info.clock / 1000.0);
6196 }
6197}
6198
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03006199static int
Armin Krezović08368132016-09-30 14:11:05 +02006200drm_output_enable(struct weston_output *base)
6201{
6202 struct drm_output *output = to_drm_output(base);
6203 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03006204 drmModeRes *resources;
6205 int ret;
6206
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09006207 assert(!output->virtual);
6208
Pekka Paalanen663d5e92017-09-08 13:32:40 +03006209 resources = drmModeGetResources(b->drm.fd);
6210 if (!resources) {
6211 weston_log("drmModeGetResources failed\n");
6212 return -1;
6213 }
Pekka Paalanen27cc4812017-11-20 13:31:06 +02006214 ret = drm_output_init_crtc(output, resources);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03006215 drmModeFreeResources(resources);
6216 if (ret < 0)
6217 return -1;
6218
6219 if (drm_output_init_gamma_size(output) < 0)
6220 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02006221
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00006222 if (b->pageflip_timeout)
6223 drm_output_pageflip_timer_create(output);
6224
Giulio Camuffo954f1832014-10-11 18:27:30 +03006225 if (b->use_pixman) {
6226 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006227 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00006228 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006229 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03006230 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02006231 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00006232 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04006233 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04006234
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02006235 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02006236
Jonas Ådahle5a12252013-04-05 23:07:11 +02006237 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05006238 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05006239 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02006240 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08006241 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01006242 output->base.set_gamma = drm_output_set_gamma;
6243
Daniel Stone2ba17f42015-05-19 20:02:41 +01006244 if (output->cursor_plane)
6245 weston_compositor_stack_plane(b->compositor,
6246 &output->cursor_plane->base,
6247 NULL);
6248 else
6249 b->cursors_are_broken = 1;
6250
Daniel Stonee2e80132018-01-16 15:37:33 +00006251 weston_compositor_stack_plane(b->compositor,
6252 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03006253 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02006254
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02006255 weston_log("Output %s (crtc %d) video modes:\n",
6256 output->base.name, output->crtc_id);
6257 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04006258
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006259 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01006260
Daniel Stone02cf4662017-03-03 16:19:39 +00006261err:
Pekka Paalanen663d5e92017-09-08 13:32:40 +03006262 drm_output_fini_crtc(output);
6263
David Herrmann0f0d54e2011-12-08 17:05:45 +01006264 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006265}
6266
Jesse Barnes58ef3792012-02-23 09:45:49 -05006267static void
Armin Krezović08368132016-09-30 14:11:05 +02006268drm_output_deinit(struct weston_output *base)
6269{
6270 struct drm_output *output = to_drm_output(base);
6271 struct drm_backend *b = to_drm_backend(base->compositor);
6272
Daniel Stone3e661f72016-11-04 17:24:06 +00006273 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02006274 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00006275 else
6276 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02006277
Daniel Stone2ba17f42015-05-19 20:02:41 +01006278 /* Since our planes are no longer in use anywhere, remove their base
6279 * weston_plane's link from the plane stacking list, unless we're
6280 * shutting down, in which case the plane has already been
6281 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00006282 if (!b->shutting_down) {
6283 wl_list_remove(&output->scanout_plane->base.link);
6284 wl_list_init(&output->scanout_plane->base.link);
6285
6286 if (output->cursor_plane) {
6287 wl_list_remove(&output->cursor_plane->base.link);
6288 wl_list_init(&output->cursor_plane->base.link);
6289 /* Turn off hardware cursor */
6290 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
6291 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01006292 }
Daniel Stone087ddf02017-02-14 17:51:30 +00006293
Pekka Paalanen663d5e92017-09-08 13:32:40 +03006294 drm_output_fini_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02006295}
6296
6297static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03006298drm_head_destroy(struct drm_head *head);
6299
6300static void
Armin Krezović08368132016-09-30 14:11:05 +02006301drm_output_destroy(struct weston_output *base)
6302{
6303 struct drm_output *output = to_drm_output(base);
6304 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02006305
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09006306 assert(!output->virtual);
6307
Daniel Stone598ee9d2016-11-16 11:55:20 +00006308 if (output->page_flip_pending || output->vblank_pending ||
6309 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02006310 output->destroy_pending = 1;
6311 weston_log("destroy output while page flip pending\n");
6312 return;
6313 }
6314
6315 if (output->base.enabled)
6316 drm_output_deinit(&output->base);
6317
Pekka Paalanen383b3af2017-09-11 14:40:48 +03006318 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02006319
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00006320 if (output->pageflip_timer)
6321 wl_event_source_remove(output->pageflip_timer);
6322
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03006323 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02006324
Daniel Stone7b2ddac2016-11-11 19:11:49 +00006325 assert(!output->state_last);
6326 drm_output_state_free(output->state_cur);
6327
Armin Krezović08368132016-09-30 14:11:05 +02006328 free(output);
6329}
6330
6331static int
6332drm_output_disable(struct weston_output *base)
6333{
6334 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02006335
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09006336 assert(!output->virtual);
6337
Daniel Stone598ee9d2016-11-16 11:55:20 +00006338 if (output->page_flip_pending || output->vblank_pending ||
6339 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02006340 output->disable_pending = 1;
6341 return -1;
6342 }
6343
Daniel Stonea08512f2016-11-08 17:46:10 +00006344 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00006345
Armin Krezović08368132016-09-30 14:11:05 +02006346 if (output->base.enabled)
6347 drm_output_deinit(&output->base);
6348
6349 output->disable_pending = 0;
6350
Armin Krezović08368132016-09-30 14:11:05 +02006351 return 0;
6352}
6353
6354/**
Daniel Stone087ddf02017-02-14 17:51:30 +00006355 * Update the list of unused connectors and CRTCs
6356 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03006357 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00006358 *
6359 * @param b Weston backend structure
6360 * @param resources DRM resources for this device
6361 */
6362static void
6363drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
6364{
6365 int i;
6366
Daniel Stone087ddf02017-02-14 17:51:30 +00006367 wl_array_release(&b->unused_crtcs);
6368 wl_array_init(&b->unused_crtcs);
6369
6370 for (i = 0; i < resources->count_crtcs; i++) {
6371 struct drm_output *output;
6372 uint32_t *crtc_id;
6373
6374 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
6375 if (output && output->base.enabled)
6376 continue;
6377
6378 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
6379 *crtc_id = resources->crtcs[i];
6380 }
6381}
6382
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03006383/** Replace connector data and monitor information
6384 *
6385 * @param head The head to update.
6386 * @param connector The connector data to be owned by the head, must match
6387 * the head's connector ID.
6388 * @return 0 on success, -1 on failure.
6389 *
6390 * Takes ownership of @c connector on success, not on failure.
6391 *
6392 * May schedule a heads changed call.
6393 */
6394static int
6395drm_head_assign_connector_info(struct drm_head *head,
6396 drmModeConnector *connector)
6397{
6398 drmModeObjectProperties *props;
6399 const char *make = "unknown";
6400 const char *model = "unknown";
6401 const char *serial_number = "unknown";
6402
6403 assert(connector);
6404 assert(head->connector_id == connector->connector_id);
6405
6406 props = drmModeObjectGetProperties(head->backend->drm.fd,
6407 head->connector_id,
6408 DRM_MODE_OBJECT_CONNECTOR);
6409 if (!props) {
6410 weston_log("Error: failed to get connector '%s' properties\n",
6411 head->base.name);
6412 return -1;
6413 }
6414
6415 if (head->connector)
6416 drmModeFreeConnector(head->connector);
6417 head->connector = connector;
6418
6419 drm_property_info_populate(head->backend, connector_props,
6420 head->props_conn,
6421 WDRM_CONNECTOR__COUNT, props);
6422 find_and_parse_output_edid(head, props, &make, &model, &serial_number);
6423 weston_head_set_monitor_strings(&head->base, make, model, serial_number);
Philipp Zabel61dc4ca2018-08-30 17:39:51 +02006424 weston_head_set_non_desktop(&head->base,
6425 check_non_desktop(head, props));
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03006426 weston_head_set_subpixel(&head->base,
6427 drm_subpixel_to_wayland(head->connector->subpixel));
6428
6429 weston_head_set_physical_size(&head->base, head->connector->mmWidth,
6430 head->connector->mmHeight);
6431
6432 drmModeFreeObjectProperties(props);
6433
6434 /* Unknown connection status is assumed disconnected. */
6435 weston_head_set_connection_status(&head->base,
6436 head->connector->connection == DRM_MODE_CONNECTED);
6437
6438 return 0;
6439}
6440
Pekka Paalanen456dc732017-11-09 15:10:11 +02006441static void
6442drm_head_log_info(struct drm_head *head, const char *msg)
6443{
6444 if (head->base.connected) {
6445 weston_log("DRM: head '%s' %s, connector %d is connected, "
6446 "EDID make '%s', model '%s', serial '%s'\n",
6447 head->base.name, msg, head->connector_id,
6448 head->base.make, head->base.model,
6449 head->base.serial_number ?: "");
6450 } else {
6451 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
6452 head->base.name, msg, head->connector_id);
6453 }
6454}
6455
Pekka Paalanend2e62422017-09-08 15:48:07 +03006456/** Update connector and monitor information
6457 *
6458 * @param head The head to update.
6459 *
6460 * Re-reads the DRM property lists for the connector and updates monitor
6461 * information and connection status. This may schedule a heads changed call
6462 * to the user.
6463 */
6464static void
6465drm_head_update_info(struct drm_head *head)
6466{
6467 drmModeConnector *connector;
6468
6469 connector = drmModeGetConnector(head->backend->drm.fd,
6470 head->connector_id);
6471 if (!connector) {
6472 weston_log("DRM: getting connector info for '%s' failed.\n",
6473 head->base.name);
6474 return;
6475 }
6476
6477 if (drm_head_assign_connector_info(head, connector) < 0)
6478 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02006479
6480 if (head->base.device_changed)
6481 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03006482}
6483
Daniel Stone087ddf02017-02-14 17:51:30 +00006484/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03006485 * Create a Weston head for a connector
6486 *
6487 * Given a DRM connector, create a matching drm_head structure and add it
6488 * to Weston's head list.
6489 *
6490 * @param b Weston backend structure
6491 * @param connector_id DRM connector ID for the head
6492 * @param drm_device udev device pointer
6493 * @returns The new head, or NULL on failure.
6494 */
6495static struct drm_head *
6496drm_head_create(struct drm_backend *backend, uint32_t connector_id,
6497 struct udev_device *drm_device)
6498{
6499 struct drm_head *head;
6500 drmModeConnector *connector;
6501 char *name;
6502
6503 head = zalloc(sizeof *head);
6504 if (!head)
6505 return NULL;
6506
6507 connector = drmModeGetConnector(backend->drm.fd, connector_id);
6508 if (!connector)
6509 goto err_alloc;
6510
6511 name = make_connector_name(connector);
6512 if (!name)
6513 goto err_alloc;
6514
6515 weston_head_init(&head->base, name);
6516 free(name);
6517
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03006518 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03006519 head->backend = backend;
6520
Pekka Paalanence724242017-09-04 12:21:24 +03006521 head->backlight = backlight_init(drm_device, connector->connector_type);
6522
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03006523 if (drm_head_assign_connector_info(head, connector) < 0)
6524 goto err_init;
6525
6526 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
6527 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
6528 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03006529
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02006530 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03006531 weston_log("Failed to retrieve current mode from connector %d.\n",
6532 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02006533 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03006534 }
6535
Pekka Paalanenc112f002017-08-28 16:27:20 +03006536 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02006537 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03006538
6539 return head;
6540
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03006541err_init:
6542 weston_head_release(&head->base);
6543
Pekka Paalanenc112f002017-08-28 16:27:20 +03006544err_alloc:
6545 if (connector)
6546 drmModeFreeConnector(connector);
6547
6548 free(head);
6549
6550 return NULL;
6551}
6552
6553static void
6554drm_head_destroy(struct drm_head *head)
6555{
6556 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03006557
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03006558 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
6559 drmModeFreeConnector(head->connector);
6560
Pekka Paalanence724242017-09-04 12:21:24 +03006561 if (head->backlight)
6562 backlight_destroy(head->backlight);
6563
Pekka Paalanenc112f002017-08-28 16:27:20 +03006564 free(head);
6565}
6566
6567/**
Armin Krezović08368132016-09-30 14:11:05 +02006568 * Create a Weston output structure
6569 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03006570 * Create an "empty" drm_output. This is the implementation of
6571 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02006572 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03006573 * Creating an output is usually followed by drm_output_attach_head()
6574 * and drm_output_enable() to make use of it.
6575 *
6576 * @param compositor The compositor instance.
6577 * @param name Name for the new output.
6578 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02006579 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03006580static struct weston_output *
6581drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02006582{
Pekka Paalanend2e62422017-09-08 15:48:07 +03006583 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02006584 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02006585
Armin Krezović08368132016-09-30 14:11:05 +02006586 output = zalloc(sizeof *output);
6587 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03006588 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02006589
Daniel Stone64dbbee2018-07-20 19:00:06 +01006590 output->backend = b;
Tomohito Esaki718a40b2018-01-31 17:50:15 +09006591 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
Daniel Stone64dbbee2018-07-20 19:00:06 +01006592
Pekka Paalanend2e62422017-09-08 15:48:07 +03006593 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03006594
Armin Krezović08368132016-09-30 14:11:05 +02006595 output->base.enable = drm_output_enable;
6596 output->base.destroy = drm_output_destroy;
6597 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03006598 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02006599 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02006600
6601 output->destroy_pending = 0;
6602 output->disable_pending = 0;
Armin Krezović08368132016-09-30 14:11:05 +02006603
Pekka Paalanen01f60212017-03-24 15:39:24 +02006604 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03006605
Armin Krezović08368132016-09-30 14:11:05 +02006606 weston_compositor_add_pending_output(&output->base, b->compositor);
6607
Pekka Paalanend2e62422017-09-08 15:48:07 +03006608 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02006609}
6610
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006611static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03006612drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006613{
Pekka Paalanend2e62422017-09-08 15:48:07 +03006614 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006615 drmModeRes *resources;
6616 int i;
6617
Giulio Camuffo954f1832014-10-11 18:27:30 +03006618 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006619 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02006620 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006621 return -1;
6622 }
6623
Giulio Camuffo954f1832014-10-11 18:27:30 +03006624 b->min_width = resources->min_width;
6625 b->max_width = resources->max_width;
6626 b->min_height = resources->min_height;
6627 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05006628
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006629 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03006630 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00006631
Pekka Paalanend2e62422017-09-08 15:48:07 +03006632 head = drm_head_create(b, connector_id, drm_device);
6633 if (!head) {
6634 weston_log("DRM: failed to create head for connector %d.\n",
6635 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02006636 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006637 }
6638
Daniel Stone087ddf02017-02-14 17:51:30 +00006639 drm_backend_update_unused_outputs(b, resources);
6640
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006641 drmModeFreeResources(resources);
6642
6643 return 0;
6644}
6645
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006646static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03006647drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006648{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006649 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03006650 struct weston_head *base, *next;
6651 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006652 int i;
6653
Giulio Camuffo954f1832014-10-11 18:27:30 +03006654 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006655 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02006656 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006657 return;
6658 }
6659
Pekka Paalanend2e62422017-09-08 15:48:07 +03006660 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006661 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00006662 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02006663
Pekka Paalanend2e62422017-09-08 15:48:07 +03006664 head = drm_head_find_by_connector(b, connector_id);
6665 if (head) {
6666 drm_head_update_info(head);
6667 } else {
6668 head = drm_head_create(b, connector_id, drm_device);
6669 if (!head)
6670 weston_log("DRM: failed to create head for hot-added connector %d.\n",
6671 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01006672 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006673 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006674
Pekka Paalanend2e62422017-09-08 15:48:07 +03006675 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03006676 wl_list_for_each_safe(base, next,
6677 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03006678 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006679
Pekka Paalanena0a37462017-08-31 15:41:57 +03006680 head = to_drm_head(base);
6681
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006682 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03006683 if (resources->connectors[i] == head->connector_id) {
6684 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006685 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006686 }
6687 }
Armin Krezović08368132016-09-30 14:11:05 +02006688
Pekka Paalanend2e62422017-09-08 15:48:07 +03006689 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006690 continue;
6691
Pekka Paalanend2e62422017-09-08 15:48:07 +03006692 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
6693 head->base.name, head->connector_id);
6694 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006695 }
6696
Daniel Stone087ddf02017-02-14 17:51:30 +00006697 drm_backend_update_unused_outputs(b, resources);
6698
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006699 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006700}
6701
6702static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03006703udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006704{
David Herrmannd7488c22012-03-11 20:05:21 +01006705 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01006706 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01006707
6708 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006709 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01006710 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02006711
David Herrmann6ac52db2012-03-11 20:05:22 +01006712 val = udev_device_get_property_value(device, "HOTPLUG");
6713 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006714 return 0;
6715
David Herrmann6ac52db2012-03-11 20:05:22 +01006716 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006717}
6718
Kristian Høgsbergb1868472011-04-22 12:27:57 -04006719static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006720udev_drm_event(int fd, uint32_t mask, void *data)
6721{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006722 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006723 struct udev_device *event;
6724
Giulio Camuffo954f1832014-10-11 18:27:30 +03006725 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02006726
Giulio Camuffo954f1832014-10-11 18:27:30 +03006727 if (udev_event_is_hotplug(b, event))
Pekka Paalanend2e62422017-09-08 15:48:07 +03006728 drm_backend_update_heads(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006729
6730 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04006731
6732 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006733}
6734
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006735static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05006736drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006737{
Armin Krezović545dba62016-08-05 15:54:18 +02006738 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03006739 struct weston_head *base, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006740
Giulio Camuffo954f1832014-10-11 18:27:30 +03006741 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02006742
Giulio Camuffo954f1832014-10-11 18:27:30 +03006743 wl_event_source_remove(b->udev_drm_source);
6744 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02006745
Daniel Stoneb57c6a02017-10-05 16:27:21 +01006746 b->shutting_down = true;
6747
Giulio Camuffo954f1832014-10-11 18:27:30 +03006748 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04006749
Marius Vlad7e4db952019-04-17 13:47:06 +03006750 weston_compositor_log_scope_destroy(b->debug);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01006751 b->debug = NULL;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03006752 weston_compositor_shutdown(ec);
6753
Pekka Paalanenc112f002017-08-28 16:27:20 +03006754 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
6755 drm_head_destroy(to_drm_head(base));
6756
Giulio Camuffo954f1832014-10-11 18:27:30 +03006757 if (b->gbm)
6758 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006759
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02006760 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03006761 udev_unref(b->udev);
6762
Giulio Camuffo954f1832014-10-11 18:27:30 +03006763 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006764
Daniel Stone087ddf02017-02-14 17:51:30 +00006765 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00006766
Giulio Camuffo954f1832014-10-11 18:27:30 +03006767 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02006768 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006769 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006770}
6771
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006772static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006773session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006774{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006775 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02006776 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01006777 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04006778 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006779
Giulio Camuffo954f1832014-10-11 18:27:30 +03006780 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006781 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00006782 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05006783 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00006784 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006785 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006786 } else {
6787 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03006788 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04006789
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01006790 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04006791
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05006792 /* If we have a repaint scheduled (either from a
6793 * pending pageflip or the idle handler), make sure we
6794 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01006795 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05006796 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05006797 * back, we schedule a repaint, which will process
6798 * pending frame callbacks. */
6799
Giulio Camuffo954f1832014-10-11 18:27:30 +03006800 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00006801 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01006802 if (output->cursor_plane)
6803 drmModeSetCursor(b->drm.fd, output->crtc_id,
6804 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05006805 }
6806
Giulio Camuffo954f1832014-10-11 18:27:30 +03006807 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04006808 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05006809
Daniel Stone085d2b92015-05-21 00:00:57 +01006810 wl_list_for_each(plane, &b->plane_list, link) {
6811 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
6812 continue;
6813
Giulio Camuffo954f1832014-10-11 18:27:30 +03006814 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01006815 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04006816 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05006817 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01006818 }
6819 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006820}
6821
Robert Beckett8d23ab72019-06-13 16:55:44 +01006822
6823/**
6824 * Handle KMS GPU being added/removed
6825 *
6826 * If the device being added/removed is the KMS device, we activate/deactivate
6827 * the compositor session.
6828 *
6829 * @param compositor The compositor instance.
6830 * @param device The device being added/removed.
6831 * @param added Whether the device is being added (or removed)
6832 */
6833static void
6834drm_device_changed(struct weston_compositor *compositor,
6835 dev_t device, bool added)
6836{
6837 struct drm_backend *b = to_drm_backend(compositor);
6838
6839 if (b->drm.fd < 0 || b->drm.devnum != device)
6840 return;
6841
6842 compositor->session_active = added;
6843 wl_signal_emit(&compositor->session_signal, compositor);
6844}
6845
Daniel Stoneefa504f2016-12-19 16:48:20 +00006846/**
6847 * Determines whether or not a device is capable of modesetting. If successful,
6848 * sets b->drm.fd and b->drm.filename to the opened device.
6849 */
6850static bool
6851drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
6852{
6853 const char *filename = udev_device_get_devnode(device);
6854 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01006855 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006856 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02006857 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00006858
6859 if (!filename)
6860 return false;
6861
6862 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
6863 if (fd < 0)
6864 return false;
6865
6866 res = drmModeGetResources(fd);
6867 if (!res)
6868 goto out_fd;
6869
6870 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
6871 res->count_encoders <= 0)
6872 goto out_res;
6873
6874 if (sysnum)
6875 id = atoi(sysnum);
6876 if (!sysnum || id < 0) {
6877 weston_log("couldn't get sysnum for device %s\n", filename);
6878 goto out_res;
6879 }
6880
6881 /* We can be called successfully on multiple devices; if we have,
6882 * clean up old entries. */
6883 if (b->drm.fd >= 0)
6884 weston_launcher_close(b->compositor->launcher, b->drm.fd);
6885 free(b->drm.filename);
6886
6887 b->drm.fd = fd;
6888 b->drm.id = id;
6889 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01006890 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00006891
Sergi Granellceb59812017-03-28 12:44:04 +02006892 drmModeFreeResources(res);
6893
Daniel Stoneefa504f2016-12-19 16:48:20 +00006894 return true;
6895
6896out_res:
6897 drmModeFreeResources(res);
6898out_fd:
6899 weston_launcher_close(b->compositor->launcher, fd);
6900 return false;
6901}
6902
David Herrmann0af066f2012-10-29 19:21:16 +01006903/*
6904 * Find primary GPU
6905 * Some systems may have multiple DRM devices attached to a single seat. This
6906 * function loops over all devices and tries to find a PCI device with the
6907 * boot_vga sysfs attribute set to 1.
6908 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00006909 * Devices are also vetted to make sure they are are capable of modesetting,
6910 * rather than pure render nodes (GPU with no display), or pure
6911 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01006912 */
6913static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03006914find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01006915{
6916 struct udev_enumerate *e;
6917 struct udev_list_entry *entry;
6918 const char *path, *device_seat, *id;
6919 struct udev_device *device, *drm_device, *pci;
6920
Giulio Camuffo954f1832014-10-11 18:27:30 +03006921 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01006922 udev_enumerate_add_match_subsystem(e, "drm");
6923 udev_enumerate_add_match_sysname(e, "card[0-9]*");
6924
6925 udev_enumerate_scan_devices(e);
6926 drm_device = NULL;
6927 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00006928 bool is_boot_vga = false;
6929
David Herrmann0af066f2012-10-29 19:21:16 +01006930 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006931 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01006932 if (!device)
6933 continue;
6934 device_seat = udev_device_get_property_value(device, "ID_SEAT");
6935 if (!device_seat)
6936 device_seat = default_seat;
6937 if (strcmp(device_seat, seat)) {
6938 udev_device_unref(device);
6939 continue;
6940 }
6941
6942 pci = udev_device_get_parent_with_subsystem_devtype(device,
6943 "pci", NULL);
6944 if (pci) {
6945 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00006946 if (id && !strcmp(id, "1"))
6947 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01006948 }
6949
Daniel Stoneefa504f2016-12-19 16:48:20 +00006950 /* If we already have a modesetting-capable device, and this
6951 * device isn't our boot-VGA device, we aren't going to use
6952 * it. */
6953 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01006954 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006955 continue;
6956 }
6957
6958 /* Make sure this device is actually capable of modesetting;
6959 * if this call succeeds, b->drm.{fd,filename} will be set,
6960 * and any old values freed. */
6961 if (!drm_device_is_kms(b, device)) {
6962 udev_device_unref(device);
6963 continue;
6964 }
6965
6966 /* There can only be one boot_vga device, and we try to use it
6967 * at all costs. */
6968 if (is_boot_vga) {
6969 if (drm_device)
6970 udev_device_unref(drm_device);
6971 drm_device = device;
6972 break;
6973 }
6974
6975 /* Per the (!is_boot_vga && drm_device) test above, we only
6976 * trump existing saved devices with boot-VGA devices, so if
6977 * we end up here, this must be the first device we've seen. */
6978 assert(!drm_device);
6979 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01006980 }
6981
Daniel Stoneefa504f2016-12-19 16:48:20 +00006982 /* If we're returning a device to use, we must have an open FD for
6983 * it. */
6984 assert(!!drm_device == (b->drm.fd >= 0));
6985
David Herrmann0af066f2012-10-29 19:21:16 +01006986 udev_enumerate_unref(e);
6987 return drm_device;
6988}
6989
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03006990static struct udev_device *
6991open_specific_drm_device(struct drm_backend *b, const char *name)
6992{
6993 struct udev_device *device;
6994
6995 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
6996 if (!device) {
6997 weston_log("ERROR: could not open DRM device '%s'\n", name);
6998 return NULL;
6999 }
7000
7001 if (!drm_device_is_kms(b, device)) {
7002 udev_device_unref(device);
7003 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
7004 return NULL;
7005 }
7006
7007 /* If we're returning a device to use, we must have an open FD for
7008 * it. */
7009 assert(b->drm.fd >= 0);
7010
7011 return device;
7012}
7013
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02007014static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02007015planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
7016 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02007017{
Giulio Camuffo954f1832014-10-11 18:27:30 +03007018 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02007019
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02007020 switch (key) {
7021 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007022 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02007023 break;
7024 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01007025 /* We don't support overlay-plane usage with legacy KMS. */
7026 if (b->atomic_modeset)
7027 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02007028 break;
7029 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007030 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02007031 break;
7032 default:
7033 break;
7034 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02007035}
7036
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07007037#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007038static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03007039recorder_destroy(struct drm_output *output)
7040{
7041 vaapi_recorder_destroy(output->recorder);
7042 output->recorder = NULL;
7043
7044 output->base.disable_planes--;
7045
7046 wl_list_remove(&output->recorder_frame_listener.link);
7047 weston_log("[libva recorder] done\n");
7048}
7049
7050static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007051recorder_frame_notify(struct wl_listener *listener, void *data)
7052{
7053 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03007054 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007055 int fd, ret;
7056
7057 output = container_of(listener, struct drm_output,
7058 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02007059 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007060
7061 if (!output->recorder)
7062 return;
7063
Daniel Stonee2e80132018-01-16 15:37:33 +00007064 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00007065 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007066 DRM_CLOEXEC, &fd);
7067 if (ret) {
7068 weston_log("[libva recorder] "
7069 "failed to create prime fd for front buffer\n");
7070 return;
7071 }
7072
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03007073 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00007074 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03007075 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02007076 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03007077 recorder_destroy(output);
7078 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007079}
7080
7081static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03007082create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007083 const char *filename)
7084{
7085 int fd;
7086 drm_magic_t magic;
7087
Giulio Camuffo954f1832014-10-11 18:27:30 +03007088 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007089 if (fd < 0)
7090 return NULL;
7091
7092 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007093 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007094
7095 return vaapi_recorder_create(fd, width, height, filename);
7096}
7097
7098static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02007099recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
7100 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007101{
Giulio Camuffo954f1832014-10-11 18:27:30 +03007102 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007103 struct drm_output *output;
7104 int width, height;
7105
Giulio Camuffo954f1832014-10-11 18:27:30 +03007106 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007107 struct drm_output, base.link);
7108
7109 if (!output->recorder) {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01007110 if (output->gbm_format != GBM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03007111 weston_log("failed to start vaapi recorder: "
7112 "output format not supported\n");
7113 return;
7114 }
7115
Hardeningff39efa2013-09-18 23:56:35 +02007116 width = output->base.current_mode->width;
7117 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007118
7119 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03007120 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007121 if (!output->recorder) {
7122 weston_log("failed to create vaapi recorder\n");
7123 return;
7124 }
7125
7126 output->base.disable_planes++;
7127
7128 output->recorder_frame_listener.notify = recorder_frame_notify;
7129 wl_signal_add(&output->base.frame_signal,
7130 &output->recorder_frame_listener);
7131
7132 weston_output_schedule_repaint(&output->base);
7133
7134 weston_log("[libva recorder] initialized\n");
7135 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03007136 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007137 }
7138}
7139#else
7140static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02007141recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
7142 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03007143{
7144 weston_log("Compiled without libva support\n");
7145}
7146#endif
7147
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007148static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03007149switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007150{
7151 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03007152 bool dmabuf_support_inited;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03007153 bool linux_explicit_sync_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007154
Giulio Camuffo954f1832014-10-11 18:27:30 +03007155 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007156 return;
7157
Pekka Paalanene4d231e2014-06-12 15:12:48 +03007158 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03007159 linux_explicit_sync_inited =
7160 b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03007161
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007162 weston_log("Switching to GL renderer\n");
7163
Giulio Camuffo954f1832014-10-11 18:27:30 +03007164 b->gbm = create_gbm_device(b->drm.fd);
7165 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007166 weston_log("Failed to create gbm device. "
7167 "Aborting renderer switch\n");
7168 return;
7169 }
7170
Giulio Camuffo954f1832014-10-11 18:27:30 +03007171 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007172 pixman_renderer_output_destroy(&output->base);
7173
Giulio Camuffo954f1832014-10-11 18:27:30 +03007174 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007175
Giulio Camuffo954f1832014-10-11 18:27:30 +03007176 if (drm_backend_create_gl_renderer(b) < 0) {
7177 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007178 weston_log("Failed to create GL renderer. Quitting.\n");
7179 /* FIXME: we need a function to shutdown cleanly */
7180 assert(0);
7181 }
7182
Giulio Camuffo954f1832014-10-11 18:27:30 +03007183 wl_list_for_each(output, &b->compositor->output_list, base.link)
7184 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007185
Giulio Camuffo954f1832014-10-11 18:27:30 +03007186 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03007187
7188 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
7189 if (linux_dmabuf_setup(b->compositor) < 0)
7190 weston_log("Error: initializing dmabuf "
7191 "support failed.\n");
7192 }
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03007193
7194 if (!linux_explicit_sync_inited &&
7195 (b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC)) {
7196 if (linux_explicit_synchronization_setup(b->compositor) < 0)
7197 weston_log("Error: initializing explicit "
7198 " synchronization support failed.\n");
7199 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007200}
7201
7202static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02007203renderer_switch_binding(struct weston_keyboard *keyboard,
7204 const struct timespec *time, uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007205{
Derek Foreman8ae2db52015-07-15 13:00:36 -05007206 struct drm_backend *b =
Armin Krezović545dba62016-08-05 15:54:18 +02007207 to_drm_backend(keyboard->seat->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007208
Giulio Camuffo954f1832014-10-11 18:27:30 +03007209 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02007210}
7211
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09007212static void
7213drm_virtual_output_start_repaint_loop(struct weston_output *output_base)
7214{
7215 weston_output_finish_frame(output_base, NULL,
7216 WP_PRESENTATION_FEEDBACK_INVALID);
7217}
7218
7219static int
7220drm_virtual_output_submit_frame(struct drm_output *output,
7221 struct drm_fb *fb)
7222{
7223 struct drm_backend *b = to_drm_backend(output->base.compositor);
7224 int fd, ret;
7225
7226 assert(fb->num_planes == 1);
7227 ret = drmPrimeHandleToFD(b->drm.fd, fb->handles[0], DRM_CLOEXEC, &fd);
7228 if (ret) {
7229 weston_log("drmPrimeHandleFD failed, errno=%d\n", errno);
7230 return -1;
7231 }
7232
7233 drm_fb_ref(fb);
7234 ret = output->virtual_submit_frame(&output->base, fd, fb->strides[0],
7235 fb);
7236 if (ret < 0) {
7237 drm_fb_unref(fb);
7238 close(fd);
7239 }
7240 return ret;
7241}
7242
7243static int
7244drm_virtual_output_repaint(struct weston_output *output_base,
7245 pixman_region32_t *damage,
7246 void *repaint_data)
7247{
7248 struct drm_pending_state *pending_state = repaint_data;
7249 struct drm_output_state *state = NULL;
7250 struct drm_output *output = to_drm_output(output_base);
7251 struct drm_plane *scanout_plane = output->scanout_plane;
7252 struct drm_plane_state *scanout_state;
7253
7254 assert(output->virtual);
7255
7256 if (output->disable_pending || output->destroy_pending)
7257 goto err;
7258
7259 /* Drop frame if there isn't free buffers */
7260 if (!gbm_surface_has_free_buffers(output->gbm_surface)) {
7261 weston_log("%s: Drop frame!!\n", __func__);
7262 return -1;
7263 }
7264
7265 assert(!output->state_last);
7266
7267 /* If planes have been disabled in the core, we might not have
7268 * hit assign_planes at all, so might not have valid output state
7269 * here. */
7270 state = drm_pending_state_get_output(pending_state, output);
7271 if (!state)
7272 state = drm_output_state_duplicate(output->state_cur,
7273 pending_state,
7274 DRM_OUTPUT_STATE_CLEAR_PLANES);
7275
7276 drm_output_render(state, damage);
7277 scanout_state = drm_output_state_get_plane(state, scanout_plane);
7278 if (!scanout_state || !scanout_state->fb)
7279 goto err;
7280
7281 if (drm_virtual_output_submit_frame(output, scanout_state->fb) < 0)
7282 goto err;
7283
7284 return 0;
7285
7286err:
7287 drm_output_state_free(state);
7288 return -1;
7289}
7290
7291static void
7292drm_virtual_output_deinit(struct weston_output *base)
7293{
7294 struct drm_output *output = to_drm_output(base);
7295
7296 drm_output_fini_egl(output);
7297
7298 drm_virtual_plane_destroy(output->scanout_plane);
7299}
7300
7301static void
7302drm_virtual_output_destroy(struct weston_output *base)
7303{
7304 struct drm_output *output = to_drm_output(base);
7305
7306 assert(output->virtual);
7307
7308 if (output->base.enabled)
7309 drm_virtual_output_deinit(&output->base);
7310
7311 weston_output_release(&output->base);
7312
7313 drm_output_state_free(output->state_cur);
7314
7315 free(output);
7316}
7317
7318static int
7319drm_virtual_output_enable(struct weston_output *output_base)
7320{
7321 struct drm_output *output = to_drm_output(output_base);
7322 struct drm_backend *b = to_drm_backend(output_base->compositor);
7323
7324 assert(output->virtual);
7325
7326 if (b->use_pixman) {
7327 weston_log("Not support pixman renderer on Virtual output\n");
7328 goto err;
7329 }
7330
7331 if (!output->virtual_submit_frame) {
7332 weston_log("The virtual_submit_frame hook is not set\n");
7333 goto err;
7334 }
7335
7336 output->scanout_plane = drm_virtual_plane_create(b, output);
7337 if (!output->scanout_plane) {
7338 weston_log("Failed to find primary plane for output %s\n",
7339 output->base.name);
7340 return -1;
7341 }
7342
7343 if (drm_output_init_egl(output, b) < 0) {
7344 weston_log("Failed to init output gl state\n");
7345 goto err;
7346 }
7347
7348 output->base.start_repaint_loop = drm_virtual_output_start_repaint_loop;
7349 output->base.repaint = drm_virtual_output_repaint;
7350 output->base.assign_planes = drm_assign_planes;
7351 output->base.set_dpms = NULL;
7352 output->base.switch_mode = NULL;
7353 output->base.gamma_size = 0;
7354 output->base.set_gamma = NULL;
7355
7356 weston_compositor_stack_plane(b->compositor,
7357 &output->scanout_plane->base,
7358 &b->compositor->primary_plane);
7359
7360 return 0;
7361err:
7362 return -1;
7363}
7364
7365static int
7366drm_virtual_output_disable(struct weston_output *base)
7367{
7368 struct drm_output *output = to_drm_output(base);
7369
7370 assert(output->virtual);
7371
7372 if (output->base.enabled)
7373 drm_virtual_output_deinit(&output->base);
7374
7375 return 0;
7376}
7377
7378static struct weston_output *
7379drm_virtual_output_create(struct weston_compositor *c, char *name)
7380{
7381 struct drm_output *output;
7382
7383 output = zalloc(sizeof *output);
7384 if (!output)
7385 return NULL;
7386
7387 output->virtual = true;
7388 output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
7389
7390 weston_output_init(&output->base, c, name);
7391
7392 output->base.enable = drm_virtual_output_enable;
7393 output->base.destroy = drm_virtual_output_destroy;
7394 output->base.disable = drm_virtual_output_disable;
7395 output->base.attach_head = NULL;
7396
7397 output->state_cur = drm_output_state_alloc(output, NULL);
7398
7399 weston_compositor_add_pending_output(&output->base, c);
7400
7401 return &output->base;
7402}
7403
7404static uint32_t
7405drm_virtual_output_set_gbm_format(struct weston_output *base,
7406 const char *gbm_format)
7407{
7408 struct drm_output *output = to_drm_output(base);
7409 struct drm_backend *b = to_drm_backend(base->compositor);
7410
7411 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
7412 output->gbm_format = b->gbm_format;
7413
7414 return output->gbm_format;
7415}
7416
7417static void
7418drm_virtual_output_set_submit_frame_cb(struct weston_output *output_base,
7419 submit_frame_cb cb)
7420{
7421 struct drm_output *output = to_drm_output(output_base);
7422
7423 output->virtual_submit_frame = cb;
7424}
7425
7426static int
7427drm_virtual_output_get_fence_fd(struct weston_output *output_base)
7428{
7429 return gl_renderer->create_fence_fd(output_base);
7430}
7431
7432static void
7433drm_virtual_output_buffer_released(struct drm_fb *fb)
7434{
7435 drm_fb_unref(fb);
7436}
7437
7438static void
7439drm_virtual_output_finish_frame(struct weston_output *output_base,
7440 struct timespec *stamp,
7441 uint32_t presented_flags)
7442{
7443 struct drm_output *output = to_drm_output(output_base);
7444 struct drm_plane_state *ps;
7445
7446 wl_list_for_each(ps, &output->state_cur->plane_list, link)
7447 ps->complete = true;
7448
7449 drm_output_state_free(output->state_last);
7450 output->state_last = NULL;
7451
7452 weston_output_finish_frame(&output->base, stamp, presented_flags);
7453
7454 /* We can't call this from frame_notify, because the output's
7455 * repaint needed flag is cleared just after that */
7456 if (output->recorder)
7457 weston_output_schedule_repaint(&output->base);
7458}
7459
Armin Krezović08368132016-09-30 14:11:05 +02007460static const struct weston_drm_output_api api = {
7461 drm_output_set_mode,
7462 drm_output_set_gbm_format,
7463 drm_output_set_seat,
7464};
7465
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09007466static const struct weston_drm_virtual_output_api virt_api = {
7467 drm_virtual_output_create,
7468 drm_virtual_output_set_gbm_format,
7469 drm_virtual_output_set_submit_frame_cb,
7470 drm_virtual_output_get_fence_fd,
7471 drm_virtual_output_buffer_released,
7472 drm_virtual_output_finish_frame
7473};
7474
Giulio Camuffo954f1832014-10-11 18:27:30 +03007475static struct drm_backend *
7476drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007477 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007478{
Giulio Camuffo954f1832014-10-11 18:27:30 +03007479 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01007480 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007481 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007482 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04007483 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02007484 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007485
nerdopolisb16c4ac2018-06-29 08:17:46 -04007486 session_seat = getenv("XDG_SEAT");
7487 if (session_seat)
7488 seat_id = session_seat;
7489
7490 if (config->seat_id)
7491 seat_id = config->seat_id;
7492
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04007493 weston_log("initializing drm backend\n");
7494
Giulio Camuffo954f1832014-10-11 18:27:30 +03007495 b = zalloc(sizeof *b);
7496 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007497 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01007498
Daniel Stone6020f472018-02-05 15:46:20 +00007499 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00007500 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00007501 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00007502
Giulio Camuffo954f1832014-10-11 18:27:30 +03007503 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007504 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00007505 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02007506 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07007507
Marius Vlad7e4db952019-04-17 13:47:06 +03007508 b->debug = weston_compositor_add_log_scope(compositor->weston_log_ctx,
7509 "drm-backend",
7510 "Debug messages from DRM/KMS backend\n",
7511 NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01007512
Pekka Paalanen7da9a382017-08-30 11:29:49 +03007513 compositor->backend = &b->base;
7514
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007515 if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
7516 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07007517
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01007518 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007519 compositor->launcher = weston_launcher_connect(compositor, config->tty,
7520 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007521 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02007522 weston_log("fatal: drm backend should be run using "
7523 "weston-launch binary, or your system should "
7524 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01007525 goto err_compositor;
7526 }
7527
Giulio Camuffo954f1832014-10-11 18:27:30 +03007528 b->udev = udev_new();
7529 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02007530 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07007531 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007532 }
7533
Giulio Camuffo954f1832014-10-11 18:27:30 +03007534 b->session_listener.notify = session_notify;
7535 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05007536
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03007537 if (config->specific_device)
7538 drm_device = open_specific_drm_device(b, config->specific_device);
7539 else
7540 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04007541 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02007542 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07007543 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007544 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007545
Daniel Stoneefa504f2016-12-19 16:48:20 +00007546 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02007547 weston_log("failed to initialize kms\n");
7548 goto err_udev_dev;
7549 }
7550
Giulio Camuffo954f1832014-10-11 18:27:30 +03007551 if (b->use_pixman) {
7552 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02007553 weston_log("failed to initialize pixman renderer\n");
7554 goto err_udev_dev;
7555 }
7556 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03007557 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02007558 weston_log("failed to initialize egl\n");
7559 goto err_udev_dev;
7560 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007561 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05007562
Giulio Camuffo954f1832014-10-11 18:27:30 +03007563 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00007564 b->base.repaint_begin = drm_repaint_begin;
7565 b->base.repaint_flush = drm_repaint_flush;
7566 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03007567 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01007568 b->base.device_changed = drm_device_changed;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02007569
Bob Ham91880f12016-01-12 10:21:47 +00007570 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04007571
Daniel Stone085d2b92015-05-21 00:00:57 +01007572 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007573 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05007574
Giulio Camuffo954f1832014-10-11 18:27:30 +03007575 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03007576 compositor, b->udev, seat_id,
7577 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03007578 weston_log("failed to create input devices\n");
7579 goto err_sprite;
7580 }
7581
Pekka Paalanend2e62422017-09-08 15:48:07 +03007582 if (drm_backend_create_heads(b, drm_device) < 0) {
7583 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03007584 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007585 }
7586
Jason Ekstrand9fc71512014-04-02 19:53:46 -05007587 /* A this point we have some idea of whether or not we have a working
7588 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03007589 if (!b->cursors_are_broken)
7590 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05007591
Giulio Camuffo954f1832014-10-11 18:27:30 +03007592 loop = wl_display_get_event_loop(compositor->wl_display);
7593 b->drm_source =
7594 wl_event_loop_add_fd(loop, b->drm.fd,
7595 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04007596
Giulio Camuffo954f1832014-10-11 18:27:30 +03007597 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
7598 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05007599 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01007600 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01007601 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03007602 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01007603 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007604 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02007605 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03007606 udev_monitor_get_fd(b->udev_monitor),
7607 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01007608
Giulio Camuffo954f1832014-10-11 18:27:30 +03007609 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02007610 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01007611 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01007612 }
7613
Daniel Stonea96b93c2012-06-22 14:04:37 +01007614 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007615
Giulio Camuffo954f1832014-10-11 18:27:30 +03007616 weston_compositor_add_debug_binding(compositor, KEY_O,
7617 planes_binding, b);
7618 weston_compositor_add_debug_binding(compositor, KEY_C,
7619 planes_binding, b);
7620 weston_compositor_add_debug_binding(compositor, KEY_V,
7621 planes_binding, b);
7622 weston_compositor_add_debug_binding(compositor, KEY_Q,
7623 recorder_binding, b);
7624 weston_compositor_add_debug_binding(compositor, KEY_W,
7625 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02007626
Pekka Paalanene4d231e2014-06-12 15:12:48 +03007627 if (compositor->renderer->import_dmabuf) {
7628 if (linux_dmabuf_setup(compositor) < 0)
7629 weston_log("Error: initializing dmabuf "
7630 "support failed.\n");
7631 }
7632
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03007633 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
7634 if (linux_explicit_synchronization_setup(compositor) < 0)
7635 weston_log("Error: initializing explicit "
7636 " synchronization support failed.\n");
7637 }
7638
Armin Krezović08368132016-09-30 14:11:05 +02007639 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
7640 &api, sizeof(api));
7641
7642 if (ret < 0) {
7643 weston_log("Failed to register output API.\n");
7644 goto err_udev_monitor;
7645 }
7646
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09007647 ret = weston_plugin_api_register(compositor,
7648 WESTON_DRM_VIRTUAL_OUTPUT_API_NAME,
7649 &virt_api, sizeof(virt_api));
7650 if (ret < 0) {
7651 weston_log("Failed to register virtual output API.\n");
7652 goto err_udev_monitor;
7653 }
7654
Giulio Camuffo954f1832014-10-11 18:27:30 +03007655 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01007656
7657err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007658 wl_event_source_remove(b->udev_drm_source);
7659 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007660err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007661 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03007662err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007663 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04007664err_sprite:
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01007665 if (b->gbm)
7666 gbm_device_destroy(b->gbm);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007667 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007668err_udev_dev:
7669 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07007670err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007671 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007672err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007673 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007674err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03007675 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007676 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01007677 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007678}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04007679
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007680static void
7681config_init_to_defaults(struct weston_drm_backend_config *config)
7682{
Pekka Paalanendee412d2018-04-23 11:44:58 +02007683 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007684}
7685
Giulio Camuffo954f1832014-10-11 18:27:30 +03007686WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01007687weston_backend_init(struct weston_compositor *compositor,
7688 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04007689{
Giulio Camuffo954f1832014-10-11 18:27:30 +03007690 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007691 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04007692
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007693 if (config_base == NULL ||
7694 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
7695 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
7696 weston_log("drm backend config structure is invalid\n");
7697 return -1;
7698 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02007699
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007700 config_init_to_defaults(&config);
7701 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07007702
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007703 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03007704 if (b == NULL)
7705 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07007706
Giulio Camuffo954f1832014-10-11 18:27:30 +03007707 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04007708}