blob: 87e3e5d257a9dcb82c2b7ca357a05af89b372dad [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
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07007 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070015 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027 */
28
Daniel Stonec228e232013-05-22 18:03:19 +030029#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040030
Jesse Barnes58ef3792012-02-23 09:45:49 -050031#include <errno.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030032#include <stdint.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010034#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040035#include <string.h>
36#include <fcntl.h>
37#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040038#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070039#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030040#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020041#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030042#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030043#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040044
Benjamin Franzkec649a922011-03-02 11:56:04 +010045#include <xf86drm.h>
46#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050047#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010048
Benjamin Franzke060cf802011-04-30 09:32:11 +020049#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040050#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020051
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070052#include "compositor.h"
53#include "compositor-drm.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070054#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020055#include "shared/timespec-util.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010056#include "gl-renderer.h"
Vincent Abriouc9506672016-10-05 16:14:07 +020057#include "weston-egl-ext.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020058#include "pixman-renderer.h"
Daniel Stone0b70fa42017-04-04 17:54:23 +010059#include "pixel-formats.h"
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070060#include "libbacklight.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100061#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010062#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030063#include "vaapi-recorder.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020064#include "presentation-time-server-protocol.h"
Pekka Paalanene4d231e2014-06-12 15:12:48 +030065#include "linux-dmabuf.h"
Micah Fedkec8890122017-02-01 15:28:23 -050066#include "linux-dmabuf-unstable-v1-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040067
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030068#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
69#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
70#endif
71
Pekka Paalanenc5de57f2015-05-20 23:01:44 +010072#ifndef DRM_CLIENT_CAP_UNIVERSAL_PLANES
73#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
74#endif
75
Ankit Nautiyala21c3932097-03-19 00:24:57 +053076#ifndef DRM_CLIENT_CAP_ASPECT_RATIO
77#define DRM_CLIENT_CAP_ASPECT_RATIO 4
78#endif
79
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030080#ifndef DRM_CAP_CURSOR_WIDTH
81#define DRM_CAP_CURSOR_WIDTH 0x8
82#endif
83
84#ifndef DRM_CAP_CURSOR_HEIGHT
85#define DRM_CAP_CURSOR_HEIGHT 0x9
86#endif
87
88#ifndef GBM_BO_USE_CURSOR
89#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
90#endif
91
Pekka Paalanendfc06832017-11-20 14:04:38 +020092#define MAX_CLONED_CONNECTORS 4
Pekka Paalanenc112f002017-08-28 16:27:20 +030093
Daniel Stone02cf4662017-03-03 16:19:39 +000094/**
Ankit Nautiyala21c3932097-03-19 00:24:57 +053095 * aspect ratio info taken from the drmModeModeInfo flag bits 19-22,
96 * which should be used to fill the aspect ratio field in weston_mode.
97 */
98#define DRM_MODE_FLAG_PIC_AR_BITS_POS 19
99#ifndef DRM_MODE_FLAG_PIC_AR_MASK
100#define DRM_MODE_FLAG_PIC_AR_MASK (0xF << DRM_MODE_FLAG_PIC_AR_BITS_POS)
101#endif
102
103/**
Daniel Stone02cf4662017-03-03 16:19:39 +0000104 * Represents the values of an enum-type KMS property
105 */
106struct drm_property_enum_info {
107 const char *name; /**< name as string (static, not freed) */
108 bool valid; /**< true if value is supported; ignore if false */
109 uint64_t value; /**< raw value */
110};
111
112/**
113 * Holds information on a DRM property, including its ID and the enum
114 * values it holds.
115 *
116 * DRM properties are allocated dynamically, and maintained as DRM objects
117 * within the normal object ID space; they thus do not have a stable ID
118 * to refer to. This includes enum values, which must be referred to by
119 * integer values, but these are not stable.
120 *
121 * drm_property_info allows a cache to be maintained where Weston can use
122 * enum values internally to refer to properties, with the mapping to DRM
123 * ID values being maintained internally.
124 */
125struct drm_property_info {
126 const char *name; /**< name as string (static, not freed) */
127 uint32_t prop_id; /**< KMS property object ID */
128 unsigned int num_enum_values; /**< number of enum values */
129 struct drm_property_enum_info *enum_values; /**< array of enum values */
130};
131
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000132/**
Daniel Stone598ee9d2016-11-16 11:55:20 +0000133 * List of properties attached to DRM planes
134 */
135enum wdrm_plane_property {
136 WDRM_PLANE_TYPE = 0,
137 WDRM_PLANE_SRC_X,
138 WDRM_PLANE_SRC_Y,
139 WDRM_PLANE_SRC_W,
140 WDRM_PLANE_SRC_H,
141 WDRM_PLANE_CRTC_X,
142 WDRM_PLANE_CRTC_Y,
143 WDRM_PLANE_CRTC_W,
144 WDRM_PLANE_CRTC_H,
145 WDRM_PLANE_FB_ID,
146 WDRM_PLANE_CRTC_ID,
147 WDRM_PLANE__COUNT
148};
149
150/**
151 * Possible values for the WDRM_PLANE_TYPE property.
152 */
153enum wdrm_plane_type {
154 WDRM_PLANE_TYPE_PRIMARY = 0,
155 WDRM_PLANE_TYPE_CURSOR,
156 WDRM_PLANE_TYPE_OVERLAY,
157 WDRM_PLANE_TYPE__COUNT
158};
159
160static struct drm_property_enum_info plane_type_enums[] = {
161 [WDRM_PLANE_TYPE_PRIMARY] = {
162 .name = "Primary",
163 },
164 [WDRM_PLANE_TYPE_OVERLAY] = {
165 .name = "Overlay",
166 },
167 [WDRM_PLANE_TYPE_CURSOR] = {
168 .name = "Cursor",
169 },
170};
171
172static const struct drm_property_info plane_props[] = {
173 [WDRM_PLANE_TYPE] = {
174 .name = "type",
175 .enum_values = plane_type_enums,
176 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
177 },
178 [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
179 [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
180 [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
181 [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
182 [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
183 [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
184 [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
185 [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
186 [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
187 [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
188};
189
190/**
191 * List of properties attached to a DRM connector
192 */
193enum wdrm_connector_property {
194 WDRM_CONNECTOR_EDID = 0,
195 WDRM_CONNECTOR_DPMS,
196 WDRM_CONNECTOR_CRTC_ID,
197 WDRM_CONNECTOR__COUNT
198};
199
Daniel Stone76255772018-07-06 11:36:49 +0100200enum wdrm_dpms_state {
201 WDRM_DPMS_STATE_OFF = 0,
202 WDRM_DPMS_STATE_ON,
203 WDRM_DPMS_STATE_STANDBY, /* unused */
204 WDRM_DPMS_STATE_SUSPEND, /* unused */
205 WDRM_DPMS_STATE__COUNT
206};
207
208static struct drm_property_enum_info dpms_state_enums[] = {
209 [WDRM_DPMS_STATE_OFF] = {
210 .name = "Off",
211 },
212 [WDRM_DPMS_STATE_ON] = {
213 .name = "On",
214 },
215 [WDRM_DPMS_STATE_STANDBY] = {
216 .name = "Standby",
217 },
218 [WDRM_DPMS_STATE_SUSPEND] = {
219 .name = "Suspend",
220 },
221};
222
Daniel Stone598ee9d2016-11-16 11:55:20 +0000223static const struct drm_property_info connector_props[] = {
224 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
Daniel Stone76255772018-07-06 11:36:49 +0100225 [WDRM_CONNECTOR_DPMS] = {
226 .name = "DPMS",
227 .enum_values = dpms_state_enums,
228 .num_enum_values = WDRM_DPMS_STATE__COUNT,
229 },
Daniel Stone598ee9d2016-11-16 11:55:20 +0000230 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
231};
232
233/**
Pekka Paalanencd011a62016-11-15 22:07:49 +0000234 * List of properties attached to DRM CRTCs
235 */
236enum wdrm_crtc_property {
237 WDRM_CRTC_MODE_ID = 0,
238 WDRM_CRTC_ACTIVE,
239 WDRM_CRTC__COUNT
240};
241
Daniel Stone598ee9d2016-11-16 11:55:20 +0000242static const struct drm_property_info crtc_props[] = {
243 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
244 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
245};
246
Pekka Paalanencd011a62016-11-15 22:07:49 +0000247/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000248 * Mode for drm_output_state_duplicate.
249 */
250enum drm_output_state_duplicate_mode {
251 DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
252 DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
253};
254
255/**
256 * Mode for drm_pending_state_apply and co.
257 */
258enum drm_state_apply_mode {
259 DRM_STATE_APPLY_SYNC, /**< state fully processed */
260 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
261};
262
Giulio Camuffo954f1832014-10-11 18:27:30 +0300263struct drm_backend {
264 struct weston_backend base;
265 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400266
267 struct udev *udev;
268 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400269
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100270 struct udev_monitor *udev_monitor;
271 struct wl_event_source *udev_drm_source;
272
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100273 struct {
David Herrmannd7488c22012-03-11 20:05:21 +0100274 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100275 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300276 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100277 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200278 struct gbm_device *gbm;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700279 struct wl_listener session_listener;
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +0100280 uint32_t gbm_format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200281
Rob Clark4339add2012-08-09 14:18:28 -0500282 /* we need these parameters in order to not fail drmModeAddFB2()
283 * due to out of bounds dimensions, and then mistakenly set
284 * sprites_are_broken:
285 */
Daniel Stonef214fdc2016-11-14 17:43:57 +0000286 int min_width, max_width;
287 int min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -0500288
Daniel Stone085d2b92015-05-21 00:00:57 +0100289 struct wl_list plane_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500290 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200291 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500292
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000293 void *repaint_data;
294
Daniel Stone6020f472018-02-05 15:46:20 +0000295 bool state_invalid;
296
Pekka Paalaneneacec812017-09-12 13:43:51 +0300297 /* CRTC IDs not used by any enabled output. */
Daniel Stone087ddf02017-02-14 17:51:30 +0000298 struct wl_array unused_crtcs;
299
Rob Clarkab5b1e32012-08-09 13:24:45 -0500300 int cursors_are_broken;
301
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100302 bool universal_planes;
Pekka Paalanencd011a62016-11-15 22:07:49 +0000303 bool atomic_modeset;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100304
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200305 int use_pixman;
Pekka Paalanendee412d2018-04-23 11:44:58 +0200306 bool use_pixman_shadow;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200307
Rob Bradfordd355b802013-05-31 18:09:55 +0100308 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300309
Daniel Stone70d337d2015-06-16 18:42:23 +0100310 int32_t cursor_width;
311 int32_t cursor_height;
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +0000312
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000313 uint32_t pageflip_timeout;
Daniel Stoneb57c6a02017-10-05 16:27:21 +0100314
315 bool shutting_down;
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530316
317 bool aspect_ratio_supported;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400318};
319
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400320struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500321 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400322 drmModeModeInfo mode_info;
Daniel Stoned5526cb2016-11-16 10:54:10 +0000323 uint32_t blob_id;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400324};
325
Daniel Stonefc175a72017-04-04 17:54:22 +0100326enum drm_fb_type {
327 BUFFER_INVALID = 0, /**< never used */
328 BUFFER_CLIENT, /**< directly sourced from client */
Daniel Stonef522e222016-11-18 12:31:26 +0000329 BUFFER_DMABUF, /**< imported from linux_dmabuf client */
Daniel Stonefc175a72017-04-04 17:54:22 +0100330 BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
331 BUFFER_GBM_SURFACE, /**< internal EGL rendering */
Daniel Stonee4256832017-04-04 17:54:27 +0100332 BUFFER_CURSOR, /**< internal cursor buffer */
Daniel Stonefc175a72017-04-04 17:54:22 +0100333};
334
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300335struct drm_fb {
Daniel Stonefc175a72017-04-04 17:54:22 +0100336 enum drm_fb_type type;
337
Daniel Stone6e7a9612017-04-04 17:54:26 +0100338 int refcnt;
339
Daniel Stone8eece0c2016-11-17 17:54:00 +0000340 uint32_t fb_id, size;
341 uint32_t handles[4];
342 uint32_t strides[4];
343 uint32_t offsets[4];
Daniel Stone0b70fa42017-04-04 17:54:23 +0100344 const struct pixel_format_info *format;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000345 uint64_t modifier;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000346 int width, height;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200347 int fd;
Pekka Paalanende685b82012-12-04 15:58:12 +0200348 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200349
350 /* Used by gbm fbs */
351 struct gbm_bo *bo;
Daniel Stone05a5ac22017-04-04 17:54:25 +0100352 struct gbm_surface *gbm_surface;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200353
354 /* Used by dumb fbs */
355 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356};
357
Richard Hughes2b2092a2013-04-24 14:58:02 +0100358struct drm_edid {
359 char eisa_id[13];
360 char monitor_name[13];
361 char pnp_id[5];
362 char serial_number[13];
363};
364
Daniel Stone08d4edf2017-04-04 17:54:34 +0100365/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000366 * Pending state holds one or more drm_output_state structures, collected from
367 * performing repaint. This pending state is transient, and only lives between
368 * beginning a repaint group and flushing the results: after flush, each
369 * output state will complete and be retired separately.
370 */
371struct drm_pending_state {
372 struct drm_backend *backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000373 struct wl_list output_list;
374};
375
376/*
377 * Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
378 * plus >= 1 each of encoder/connector/plane. Since everything but the planes
379 * is currently statically assigned per-output, we mainly use this to track
380 * plane state.
381 *
382 * pending_state is set when the output state is owned by a pending_state,
383 * i.e. when it is being constructed and has not yet been applied. When the
384 * output state has been applied, the owning pending_state is freed.
385 */
386struct drm_output_state {
387 struct drm_pending_state *pending_state;
388 struct drm_output *output;
389 struct wl_list link;
Daniel Stonea08512f2016-11-08 17:46:10 +0000390 enum dpms_enum dpms;
Daniel Stonebc15f682016-11-14 16:57:01 +0000391 struct wl_list plane_list;
392};
393
394/**
395 * Plane state holds the dynamic state for a plane: where it is positioned,
396 * and which buffer it is currently displaying.
397 *
398 * The plane state is owned by an output state, except when setting an initial
399 * state. See drm_output_state for notes on state object lifetime.
400 */
401struct drm_plane_state {
402 struct drm_plane *plane;
403 struct drm_output *output;
404 struct drm_output_state *output_state;
405
406 struct drm_fb *fb;
407
408 int32_t src_x, src_y;
409 uint32_t src_w, src_h;
410 int32_t dest_x, dest_y;
411 uint32_t dest_w, dest_h;
412
413 bool complete;
414
415 struct wl_list link; /* drm_output_state::plane_list */
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000416};
417
418/**
Daniel Stone08d4edf2017-04-04 17:54:34 +0100419 * A plane represents one buffer, positioned within a CRTC, and stacked
420 * relative to other planes on the same CRTC.
421 *
422 * Each CRTC has a 'primary plane', which use used to display the classic
423 * framebuffer contents, as accessed through the legacy drmModeSetCrtc
424 * call (which combines setting the CRTC's actual physical mode, and the
425 * properties of the primary plane).
426 *
427 * The cursor plane also has its own alternate legacy API.
428 *
429 * Other planes are used opportunistically to display content we do not
430 * wish to blit into the primary plane. These non-primary/cursor planes
431 * are referred to as 'sprites'.
432 */
433struct drm_plane {
Daniel Stone08d4edf2017-04-04 17:54:34 +0100434 struct weston_plane base;
435
Daniel Stone08d4edf2017-04-04 17:54:34 +0100436 struct drm_backend *backend;
437
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100438 enum wdrm_plane_type type;
439
Daniel Stone08d4edf2017-04-04 17:54:34 +0100440 uint32_t possible_crtcs;
441 uint32_t plane_id;
442 uint32_t count_formats;
443
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100444 struct drm_property_info props[WDRM_PLANE__COUNT];
445
Daniel Stonebc15f682016-11-14 16:57:01 +0000446 /* The last state submitted to the kernel for this plane. */
447 struct drm_plane_state *state_cur;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100448
Daniel Stonebc15f682016-11-14 16:57:01 +0000449 struct wl_list link;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100450
451 uint32_t formats[];
452};
453
Pekka Paalanenc112f002017-08-28 16:27:20 +0300454struct drm_head {
455 struct weston_head base;
456 struct drm_backend *backend;
457
Armin Krezović08368132016-09-30 14:11:05 +0200458 drmModeConnector *connector;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400459 uint32_t connector_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100460 struct drm_edid edid;
Daniel Stone02cf4662017-03-03 16:19:39 +0000461
462 /* Holds the properties for the connector */
463 struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300464
465 struct backlight *backlight;
Pekka Paalanen13d233e2017-09-11 14:06:11 +0300466
467 drmModeModeInfo inherited_mode; /**< Original mode on the connector */
Pekka Paalanen27cc4812017-11-20 13:31:06 +0200468 uint32_t inherited_crtc_id; /**< Original CRTC assignment */
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300469};
470
471struct drm_output {
472 struct weston_output base;
473
474 uint32_t crtc_id; /* object ID to pass to DRM functions */
475 int pipe; /* index of CRTC in resource array / bitmasks */
476
Pekka Paalanencd011a62016-11-15 22:07:49 +0000477 /* Holds the properties for the CRTC */
478 struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200479
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300480 int vblank_pending;
481 int page_flip_pending;
Daniel Stone598ee9d2016-11-16 11:55:20 +0000482 int atomic_complete_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800483 int destroy_pending;
Armin Krezović08368132016-09-30 14:11:05 +0200484 int disable_pending;
Daniel Stonea08512f2016-11-08 17:46:10 +0000485 int dpms_off_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300486
Daniel Stonee4256832017-04-04 17:54:27 +0100487 struct drm_fb *gbm_cursor_fb[2];
Daniel Stone2ba17f42015-05-19 20:02:41 +0100488 struct drm_plane *cursor_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500489 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400490 int current_cursor;
Daniel Stone5bb8f582017-04-04 17:54:28 +0100491
492 struct gbm_surface *gbm_surface;
493 uint32_t gbm_format;
494
Daniel Stonee2e80132018-01-16 15:37:33 +0000495 /* Plane being displayed directly on the CRTC */
496 struct drm_plane *scanout_plane;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200497
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000498 /* The last state submitted to the kernel for this CRTC. */
499 struct drm_output_state *state_cur;
500 /* The previously-submitted state, where the hardware has not
501 * yet acknowledged completion of state_cur. */
502 struct drm_output_state *state_last;
503
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200504 struct drm_fb *dumb[2];
505 pixman_image_t *image[2];
506 int current_image;
507 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300508
509 struct vaapi_recorder *recorder;
510 struct wl_listener recorder_frame_listener;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000511
512 struct wl_event_source *pageflip_timer;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400513};
514
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530515static const char *const aspect_ratio_as_string[] = {
516 [WESTON_MODE_PIC_AR_NONE] = "",
517 [WESTON_MODE_PIC_AR_4_3] = " 4:3",
518 [WESTON_MODE_PIC_AR_16_9] = " 16:9",
519 [WESTON_MODE_PIC_AR_64_27] = " 64:27",
520 [WESTON_MODE_PIC_AR_256_135] = " 256:135",
521};
522
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300523static struct gl_renderer_interface *gl_renderer;
524
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500525static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400526
Daniel Stone087ddf02017-02-14 17:51:30 +0000527static void
528wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
529{
530 uint32_t *pos, *end;
531
532 end = (uint32_t *) ((char *) array->data + array->size);
533
534 wl_array_for_each(pos, array) {
535 if (*pos != elm)
536 continue;
537
538 array->size -= sizeof(*pos);
539 if (pos + 1 == end)
540 break;
541
542 memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
543 break;
544 }
545}
546
Pekka Paalanenc112f002017-08-28 16:27:20 +0300547static inline struct drm_head *
548to_drm_head(struct weston_head *base)
549{
550 return container_of(base, struct drm_head, base);
551}
552
Armin Krezović545dba62016-08-05 15:54:18 +0200553static inline struct drm_output *
554to_drm_output(struct weston_output *base)
555{
556 return container_of(base, struct drm_output, base);
557}
558
559static inline struct drm_backend *
560to_drm_backend(struct weston_compositor *base)
561{
562 return container_of(base->backend, struct drm_backend, base);
563}
564
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000565static int
566pageflip_timeout(void *data) {
567 /*
568 * Our timer just went off, that means we're not receiving drm
569 * page flip events anymore for that output. Let's gracefully exit
570 * weston with a return value so devs can debug what's going on.
571 */
572 struct drm_output *output = data;
573 struct weston_compositor *compositor = output->base.compositor;
574
575 weston_log("Pageflip timeout reached on output %s, your "
576 "driver is probably buggy! Exiting.\n",
577 output->base.name);
578 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
579
580 return 0;
581}
582
583/* Creates the pageflip timer. Note that it isn't armed by default */
584static int
585drm_output_pageflip_timer_create(struct drm_output *output)
586{
587 struct wl_event_loop *loop = NULL;
588 struct weston_compositor *ec = output->base.compositor;
589
590 loop = wl_display_get_event_loop(ec->wl_display);
591 assert(loop);
592 output->pageflip_timer = wl_event_loop_add_timer(loop,
593 pageflip_timeout,
594 output);
595
596 if (output->pageflip_timer == NULL) {
597 weston_log("creating drm pageflip timer failed: %m\n");
598 return -1;
599 }
600
601 return 0;
602}
603
Daniel Stonecb04cc42016-11-16 11:51:27 +0000604static inline struct drm_mode *
605to_drm_mode(struct weston_mode *base)
606{
607 return container_of(base, struct drm_mode, base);
608}
609
Daniel Stone02cf4662017-03-03 16:19:39 +0000610/**
611 * Get the current value of a KMS property
612 *
613 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
614 * for the target property, return the current value of that property,
615 * with an optional default. If the property is a KMS enum type, the return
616 * value will be translated into the appropriate internal enum.
617 *
618 * If the property is not present, the default value will be returned.
619 *
620 * @param info Internal structure for property to look up
621 * @param props Raw KMS properties for the target object
622 * @param def Value to return if property is not found
623 */
624static uint64_t
625drm_property_get_value(struct drm_property_info *info,
Daniel Stone85eebdf2018-07-05 17:55:43 +0100626 const drmModeObjectProperties *props,
Daniel Stone02cf4662017-03-03 16:19:39 +0000627 uint64_t def)
628{
629 unsigned int i;
630
631 if (info->prop_id == 0)
632 return def;
633
634 for (i = 0; i < props->count_props; i++) {
635 unsigned int j;
636
637 if (props->props[i] != info->prop_id)
638 continue;
639
640 /* Simple (non-enum) types can return the value directly */
641 if (info->num_enum_values == 0)
642 return props->prop_values[i];
643
644 /* Map from raw value to enum value */
645 for (j = 0; j < info->num_enum_values; j++) {
646 if (!info->enum_values[j].valid)
647 continue;
648 if (info->enum_values[j].value != props->prop_values[i])
649 continue;
650
651 return j;
652 }
653
654 /* We don't have a mapping for this enum; return default. */
655 break;
656 }
657
658 return def;
659}
660
661/**
662 * Cache DRM property values
663 *
664 * Update a per-object array of drm_property_info structures, given the
665 * DRM properties of the object.
666 *
667 * Call this every time an object newly appears (note that only connectors
668 * can be hotplugged), the first time it is seen, or when its status changes
669 * in a way which invalidates the potential property values (currently, the
670 * only case for this is connector hotplug).
671 *
672 * This updates the property IDs and enum values within the drm_property_info
673 * array.
674 *
675 * DRM property enum values are dynamic at runtime; the user must query the
676 * property to find out the desired runtime value for a requested string
677 * name. Using the 'type' field on planes as an example, there is no single
678 * hardcoded constant for primary plane types; instead, the property must be
679 * queried at runtime to find the value associated with the string "Primary".
680 *
681 * This helper queries and caches the enum values, to allow us to use a set
682 * of compile-time-constant enums portably across various implementations.
683 * The values given in enum_names are searched for, and stored in the
684 * same-indexed field of the map array.
685 *
686 * @param b DRM backend object
687 * @param src DRM property info array to source from
688 * @param info DRM property info array to copy into
689 * @param num_infos Number of entries in the source array
690 * @param props DRM object properties for the object
691 */
692static void
693drm_property_info_populate(struct drm_backend *b,
694 const struct drm_property_info *src,
695 struct drm_property_info *info,
696 unsigned int num_infos,
697 drmModeObjectProperties *props)
698{
699 drmModePropertyRes *prop;
700 unsigned i, j;
701
702 for (i = 0; i < num_infos; i++) {
703 unsigned int j;
704
705 info[i].name = src[i].name;
706 info[i].prop_id = 0;
707 info[i].num_enum_values = src[i].num_enum_values;
708
709 if (src[i].num_enum_values == 0)
710 continue;
711
712 info[i].enum_values =
713 malloc(src[i].num_enum_values *
714 sizeof(*info[i].enum_values));
715 assert(info[i].enum_values);
716 for (j = 0; j < info[i].num_enum_values; j++) {
717 info[i].enum_values[j].name = src[i].enum_values[j].name;
718 info[i].enum_values[j].valid = false;
719 }
720 }
721
722 for (i = 0; i < props->count_props; i++) {
723 unsigned int k;
724
725 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
726 if (!prop)
727 continue;
728
729 for (j = 0; j < num_infos; j++) {
730 if (!strcmp(prop->name, info[j].name))
731 break;
732 }
733
734 /* We don't know/care about this property. */
735 if (j == num_infos) {
736#ifdef DEBUG
737 weston_log("DRM debug: unrecognized property %u '%s'\n",
738 prop->prop_id, prop->name);
739#endif
740 drmModeFreeProperty(prop);
741 continue;
742 }
743
744 if (info[j].num_enum_values == 0 &&
745 (prop->flags & DRM_MODE_PROP_ENUM)) {
746 weston_log("DRM: expected property %s to not be an"
747 " enum, but it is; ignoring\n", prop->name);
748 drmModeFreeProperty(prop);
749 continue;
750 }
751
752 info[j].prop_id = props->props[i];
753
754 if (info[j].num_enum_values == 0) {
755 drmModeFreeProperty(prop);
756 continue;
757 }
758
759 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
760 weston_log("DRM: expected property %s to be an enum,"
761 " but it is not; ignoring\n", prop->name);
762 drmModeFreeProperty(prop);
763 info[j].prop_id = 0;
764 continue;
765 }
766
767 for (k = 0; k < info[j].num_enum_values; k++) {
768 int l;
769
770 for (l = 0; l < prop->count_enums; l++) {
771 if (!strcmp(prop->enums[l].name,
772 info[j].enum_values[k].name))
773 break;
774 }
775
776 if (l == prop->count_enums)
777 continue;
778
779 info[j].enum_values[k].valid = true;
780 info[j].enum_values[k].value = prop->enums[l].value;
781 }
782
783 drmModeFreeProperty(prop);
784 }
785
786#ifdef DEBUG
787 for (i = 0; i < num_infos; i++) {
788 if (info[i].prop_id == 0)
789 weston_log("DRM warning: property '%s' missing\n",
790 info[i].name);
791 }
792#endif
793}
794
795/**
796 * Free DRM property information
797 *
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300798 * Frees all memory associated with a DRM property info array and zeroes
799 * it out, leaving it usable for a further drm_property_info_update() or
800 * drm_property_info_free().
Daniel Stone02cf4662017-03-03 16:19:39 +0000801 *
802 * @param info DRM property info array
803 * @param num_props Number of entries in array to free
804 */
805static void
806drm_property_info_free(struct drm_property_info *info, int num_props)
807{
808 int i;
809
810 for (i = 0; i < num_props; i++)
811 free(info[i].enum_values);
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300812
813 memset(info, 0, sizeof(*info) * num_props);
Daniel Stone02cf4662017-03-03 16:19:39 +0000814}
815
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400816static void
Daniel Stone2ba17f42015-05-19 20:02:41 +0100817drm_output_set_cursor(struct drm_output_state *output_state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400818
Mario Kleinerf507ec32015-06-21 21:25:14 +0200819static void
820drm_output_update_msc(struct drm_output *output, unsigned int seq);
821
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000822static void
823drm_output_destroy(struct weston_output *output_base);
824
Daniel Stone5ff289a2017-10-07 12:59:02 +0100825/**
826 * Returns true if the plane can be used on the given output for its current
827 * repaint cycle.
828 */
829static bool
830drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100832 assert(plane->state_cur);
833
834 /* The plane still has a request not yet completed by the kernel. */
835 if (!plane->state_cur->complete)
836 return false;
837
838 /* The plane is still active on another output. */
839 if (plane->state_cur->output && plane->state_cur->output != output)
840 return false;
841
842 /* Check whether the plane can be used with this CRTC; possible_crtcs
843 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Daniel Stone08d4edf2017-04-04 17:54:34 +0100844 return !!(plane->possible_crtcs & (1 << output->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500845}
846
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000847static struct drm_output *
848drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
849{
850 struct drm_output *output;
851
852 wl_list_for_each(output, &b->compositor->output_list, base.link) {
853 if (output->crtc_id == crtc_id)
854 return output;
855 }
856
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000857 return NULL;
858}
859
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300860static struct drm_head *
861drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
862{
863 struct weston_head *base;
864 struct drm_head *head;
865
866 wl_list_for_each(base,
867 &backend->compositor->head_list, compositor_link) {
868 head = to_drm_head(base);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300869 if (head->connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300870 return head;
871 }
872
873 return NULL;
874}
875
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300876static void
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100877drm_fb_destroy(struct drm_fb *fb)
878{
879 if (fb->fb_id != 0)
880 drmModeRmFB(fb->fd, fb->fb_id);
881 weston_buffer_reference(&fb->buffer_ref, NULL);
882 free(fb);
883}
884
885static void
886drm_fb_destroy_dumb(struct drm_fb *fb)
887{
888 struct drm_mode_destroy_dumb destroy_arg;
889
890 assert(fb->type == BUFFER_PIXMAN_DUMB);
891
892 if (fb->map && fb->size > 0)
893 munmap(fb->map, fb->size);
894
895 memset(&destroy_arg, 0, sizeof(destroy_arg));
Daniel Stone8eece0c2016-11-17 17:54:00 +0000896 destroy_arg.handle = fb->handles[0];
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100897 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
898
899 drm_fb_destroy(fb);
900}
901
902static void
903drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300904{
905 struct drm_fb *fb = data;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300906
Daniel Stonee4256832017-04-04 17:54:27 +0100907 assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
908 fb->type == BUFFER_CURSOR);
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100909 drm_fb_destroy(fb);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300910}
911
Daniel Stone8eece0c2016-11-17 17:54:00 +0000912static int
913drm_fb_addfb(struct drm_fb *fb)
914{
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000915 int ret = -EINVAL;
916#ifdef HAVE_DRM_ADDFB2_MODIFIERS
917 uint64_t mods[4] = { };
Daniel Stonedc082cb2018-07-09 13:49:04 +0100918 size_t i;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000919#endif
920
921 /* If we have a modifier set, we must only use the WithModifiers
922 * entrypoint; we cannot import it through legacy ioctls. */
923 if (fb->modifier != DRM_FORMAT_MOD_INVALID) {
924 /* KMS demands that if a modifier is set, it must be the same
925 * for all planes. */
926#ifdef HAVE_DRM_ADDFB2_MODIFIERS
Daniel Stonedc082cb2018-07-09 13:49:04 +0100927 for (i = 0; i < ARRAY_LENGTH(mods) && fb->handles[i]; i++)
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000928 mods[i] = fb->modifier;
929 ret = drmModeAddFB2WithModifiers(fb->fd, fb->width, fb->height,
930 fb->format->format,
931 fb->handles, fb->strides,
932 fb->offsets, mods, &fb->fb_id,
933 DRM_MODE_FB_MODIFIERS);
934#endif
935 return ret;
936 }
Daniel Stone8eece0c2016-11-17 17:54:00 +0000937
938 ret = drmModeAddFB2(fb->fd, fb->width, fb->height, fb->format->format,
939 fb->handles, fb->strides, fb->offsets, &fb->fb_id,
940 0);
941 if (ret == 0)
942 return 0;
943
944 /* Legacy AddFB can't always infer the format from depth/bpp alone, so
945 * check if our format is one of the lucky ones. */
946 if (!fb->format->depth || !fb->format->bpp)
947 return ret;
948
949 /* Cannot fall back to AddFB for multi-planar formats either. */
950 if (fb->handles[1] || fb->handles[2] || fb->handles[3])
951 return ret;
952
953 ret = drmModeAddFB(fb->fd, fb->width, fb->height,
954 fb->format->depth, fb->format->bpp,
955 fb->strides[0], fb->handles[0], &fb->fb_id);
956 return ret;
957}
958
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300959static struct drm_fb *
Daniel Stonef214fdc2016-11-14 17:43:57 +0000960drm_fb_create_dumb(struct drm_backend *b, int width, int height,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300961 uint32_t format)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200962{
963 struct drm_fb *fb;
964 int ret;
965
966 struct drm_mode_create_dumb create_arg;
967 struct drm_mode_destroy_dumb destroy_arg;
968 struct drm_mode_map_dumb map_arg;
969
Peter Huttererf3d62272013-08-08 11:57:05 +1000970 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200971 if (!fb)
972 return NULL;
Daniel Stone6e7a9612017-04-04 17:54:26 +0100973 fb->refcnt = 1;
974
Daniel Stone0b70fa42017-04-04 17:54:23 +0100975 fb->format = pixel_format_get_info(format);
976 if (!fb->format) {
977 weston_log("failed to look up format 0x%lx\n",
978 (unsigned long) format);
979 goto err_fb;
980 }
981
982 if (!fb->format->depth || !fb->format->bpp) {
983 weston_log("format 0x%lx is not compatible with dumb buffers\n",
984 (unsigned long) format);
985 goto err_fb;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300986 }
987
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700988 memset(&create_arg, 0, sizeof create_arg);
Daniel Stone0b70fa42017-04-04 17:54:23 +0100989 create_arg.bpp = fb->format->bpp;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200990 create_arg.width = width;
991 create_arg.height = height;
992
Giulio Camuffo954f1832014-10-11 18:27:30 +0300993 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200994 if (ret)
995 goto err_fb;
996
Daniel Stonefc175a72017-04-04 17:54:22 +0100997 fb->type = BUFFER_PIXMAN_DUMB;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000998 fb->modifier = DRM_FORMAT_MOD_INVALID;
Daniel Stone8eece0c2016-11-17 17:54:00 +0000999 fb->handles[0] = create_arg.handle;
1000 fb->strides[0] = create_arg.pitch;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001001 fb->size = create_arg.size;
Daniel Stonec8c917c2016-11-14 17:45:58 +00001002 fb->width = width;
1003 fb->height = height;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001004 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001005
Daniel Stone8eece0c2016-11-17 17:54:00 +00001006 if (drm_fb_addfb(fb) != 0) {
1007 weston_log("failed to create kms fb: %m\n");
1008 goto err_bo;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001009 }
1010
Kristian Høgsbergac6104e2013-08-21 22:14:14 -07001011 memset(&map_arg, 0, sizeof map_arg);
Daniel Stone8eece0c2016-11-17 17:54:00 +00001012 map_arg.handle = fb->handles[0];
Chris Michaeleb2074a2013-05-01 21:26:02 -04001013 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001014 if (ret)
1015 goto err_add_fb;
1016
Chris Michael4a7ce1f2015-11-10 10:40:37 -05001017 fb->map = mmap(NULL, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001018 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001019 if (fb->map == MAP_FAILED)
1020 goto err_add_fb;
1021
1022 return fb;
1023
1024err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +03001025 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001026err_bo:
1027 memset(&destroy_arg, 0, sizeof(destroy_arg));
1028 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001029 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001030err_fb:
1031 free(fb);
1032 return NULL;
1033}
1034
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001035static struct drm_fb *
Daniel Stone6e7a9612017-04-04 17:54:26 +01001036drm_fb_ref(struct drm_fb *fb)
1037{
1038 fb->refcnt++;
1039 return fb;
1040}
1041
Daniel Stonef522e222016-11-18 12:31:26 +00001042static void
1043drm_fb_destroy_dmabuf(struct drm_fb *fb)
1044{
1045 /* We deliberately do not close the GEM handles here; GBM manages
1046 * their lifetime through the BO. */
1047 if (fb->bo)
1048 gbm_bo_destroy(fb->bo);
1049 drm_fb_destroy(fb);
1050}
1051
1052static struct drm_fb *
1053drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
1054 struct drm_backend *backend, bool is_opaque)
1055{
1056#ifdef HAVE_GBM_FD_IMPORT
1057 struct drm_fb *fb;
1058 struct gbm_import_fd_data import_legacy = {
1059 .width = dmabuf->attributes.width,
1060 .height = dmabuf->attributes.height,
1061 .format = dmabuf->attributes.format,
1062 .stride = dmabuf->attributes.stride[0],
1063 .fd = dmabuf->attributes.fd[0],
1064 };
1065 struct gbm_import_fd_modifier_data import_mod = {
1066 .width = dmabuf->attributes.width,
1067 .height = dmabuf->attributes.height,
1068 .format = dmabuf->attributes.format,
1069 .num_fds = dmabuf->attributes.n_planes,
1070 .modifier = dmabuf->attributes.modifier[0],
1071 };
1072 int i;
1073
1074 /* XXX: TODO:
1075 *
1076 * Currently the buffer is rejected if any dmabuf attribute
1077 * flag is set. This keeps us from passing an inverted /
1078 * interlaced / bottom-first buffer (or any other type that may
1079 * be added in the future) through to an overlay. Ultimately,
1080 * these types of buffers should be handled through buffer
1081 * transforms and not as spot-checks requiring specific
1082 * knowledge. */
1083 if (dmabuf->attributes.flags)
1084 return NULL;
1085
1086 fb = zalloc(sizeof *fb);
1087 if (fb == NULL)
1088 return NULL;
1089
1090 fb->refcnt = 1;
1091 fb->type = BUFFER_DMABUF;
1092
1093 static_assert(ARRAY_LENGTH(import_mod.fds) ==
1094 ARRAY_LENGTH(dmabuf->attributes.fd),
1095 "GBM and linux_dmabuf FD size must match");
1096 static_assert(sizeof(import_mod.fds) == sizeof(dmabuf->attributes.fd),
1097 "GBM and linux_dmabuf FD size must match");
1098 memcpy(import_mod.fds, dmabuf->attributes.fd, sizeof(import_mod.fds));
1099
1100 static_assert(ARRAY_LENGTH(import_mod.strides) ==
1101 ARRAY_LENGTH(dmabuf->attributes.stride),
1102 "GBM and linux_dmabuf stride size must match");
1103 static_assert(sizeof(import_mod.strides) ==
1104 sizeof(dmabuf->attributes.stride),
1105 "GBM and linux_dmabuf stride size must match");
1106 memcpy(import_mod.strides, dmabuf->attributes.stride,
1107 sizeof(import_mod.strides));
1108
1109 static_assert(ARRAY_LENGTH(import_mod.offsets) ==
1110 ARRAY_LENGTH(dmabuf->attributes.offset),
1111 "GBM and linux_dmabuf offset size must match");
1112 static_assert(sizeof(import_mod.offsets) ==
1113 sizeof(dmabuf->attributes.offset),
1114 "GBM and linux_dmabuf offset size must match");
1115 memcpy(import_mod.offsets, dmabuf->attributes.offset,
1116 sizeof(import_mod.offsets));
1117
1118 /* The legacy FD-import path does not allow us to supply modifiers,
1119 * multiple planes, or buffer offsets. */
1120 if (dmabuf->attributes.modifier[0] != DRM_FORMAT_MOD_INVALID ||
1121 import_mod.num_fds > 1 ||
1122 import_mod.offsets[0] > 0) {
1123 fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
1124 &import_mod,
1125 GBM_BO_USE_SCANOUT);
1126 } else {
1127 fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD,
1128 &import_legacy,
1129 GBM_BO_USE_SCANOUT);
1130 }
1131
1132 if (!fb->bo)
1133 goto err_free;
1134
1135 fb->width = dmabuf->attributes.width;
1136 fb->height = dmabuf->attributes.height;
1137 fb->modifier = dmabuf->attributes.modifier[0];
1138 fb->size = 0;
1139 fb->fd = backend->drm.fd;
1140
1141 static_assert(ARRAY_LENGTH(fb->strides) ==
1142 ARRAY_LENGTH(dmabuf->attributes.stride),
1143 "drm_fb and dmabuf stride size must match");
1144 static_assert(sizeof(fb->strides) == sizeof(dmabuf->attributes.stride),
1145 "drm_fb and dmabuf stride size must match");
1146 memcpy(fb->strides, dmabuf->attributes.stride, sizeof(fb->strides));
1147 static_assert(ARRAY_LENGTH(fb->offsets) ==
1148 ARRAY_LENGTH(dmabuf->attributes.offset),
1149 "drm_fb and dmabuf offset size must match");
1150 static_assert(sizeof(fb->offsets) == sizeof(dmabuf->attributes.offset),
1151 "drm_fb and dmabuf offset size must match");
1152 memcpy(fb->offsets, dmabuf->attributes.offset, sizeof(fb->offsets));
1153
1154 fb->format = pixel_format_get_info(dmabuf->attributes.format);
1155 if (!fb->format) {
1156 weston_log("couldn't look up format info for 0x%lx\n",
1157 (unsigned long) dmabuf->attributes.format);
1158 goto err_free;
1159 }
1160
1161 if (is_opaque)
1162 fb->format = pixel_format_get_opaque_substitute(fb->format);
1163
1164 if (backend->min_width > fb->width ||
1165 fb->width > backend->max_width ||
1166 backend->min_height > fb->height ||
1167 fb->height > backend->max_height) {
1168 weston_log("bo geometry out of bounds\n");
1169 goto err_free;
1170 }
1171
1172 for (i = 0; i < dmabuf->attributes.n_planes; i++) {
1173 fb->handles[i] = gbm_bo_get_handle_for_plane(fb->bo, i).u32;
1174 if (!fb->handles[i])
1175 goto err_free;
1176 }
1177
1178 if (drm_fb_addfb(fb) != 0) {
1179 weston_log("failed to create kms fb: %m\n");
1180 goto err_free;
1181 }
1182
1183 return fb;
1184
1185err_free:
1186 drm_fb_destroy_dmabuf(fb);
1187#endif
1188 return NULL;
1189}
1190
Daniel Stone6e7a9612017-04-04 17:54:26 +01001191static struct drm_fb *
Daniel Stonefc175a72017-04-04 17:54:22 +01001192drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
Daniel Stonedb10df12016-12-08 13:15:58 +00001193 bool is_opaque, enum drm_fb_type type)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001194{
1195 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001196
Daniel Stonefc175a72017-04-04 17:54:22 +01001197 if (fb) {
1198 assert(fb->type == type);
Daniel Stone6e7a9612017-04-04 17:54:26 +01001199 return drm_fb_ref(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +01001200 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001201
Bryce Harringtonde16d892014-11-20 22:21:57 -08001202 fb = zalloc(sizeof *fb);
1203 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001204 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001205
Daniel Stonefc175a72017-04-04 17:54:22 +01001206 fb->type = type;
Daniel Stone6e7a9612017-04-04 17:54:26 +01001207 fb->refcnt = 1;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001208 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001209
Daniel Stonec8c917c2016-11-14 17:45:58 +00001210 fb->width = gbm_bo_get_width(bo);
1211 fb->height = gbm_bo_get_height(bo);
Daniel Stone8eece0c2016-11-17 17:54:00 +00001212 fb->strides[0] = gbm_bo_get_stride(bo);
1213 fb->handles[0] = gbm_bo_get_handle(bo).u32;
Daniel Stonedb10df12016-12-08 13:15:58 +00001214 fb->format = pixel_format_get_info(gbm_bo_get_format(bo));
Daniel Stone65a4dbc2016-12-08 16:36:18 +00001215 fb->modifier = DRM_FORMAT_MOD_INVALID;
Daniel Stonebdebc312018-07-09 13:51:51 +01001216 fb->size = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001217 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001218
Daniel Stone0b70fa42017-04-04 17:54:23 +01001219 if (!fb->format) {
1220 weston_log("couldn't look up format 0x%lx\n",
Daniel Stonedb10df12016-12-08 13:15:58 +00001221 (unsigned long) gbm_bo_get_format(bo));
Daniel Stone0b70fa42017-04-04 17:54:23 +01001222 goto err_free;
1223 }
1224
Daniel Stonedb10df12016-12-08 13:15:58 +00001225 /* We can scanout an ARGB buffer if the surface's opaque region covers
1226 * the whole output, but we have to use XRGB as the KMS format code. */
1227 if (is_opaque)
1228 fb->format = pixel_format_get_opaque_substitute(fb->format);
1229
Daniel Stonec8c917c2016-11-14 17:45:58 +00001230 if (backend->min_width > fb->width ||
1231 fb->width > backend->max_width ||
1232 backend->min_height > fb->height ||
1233 fb->height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001234 weston_log("bo geometry out of bounds\n");
1235 goto err_free;
1236 }
1237
Daniel Stone8eece0c2016-11-17 17:54:00 +00001238 if (drm_fb_addfb(fb) != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001239 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001240 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001241 }
1242
Tomohito Esaki576f42e2017-04-04 17:54:24 +01001243 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001244
1245 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001246
1247err_free:
1248 free(fb);
1249 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001250}
1251
1252static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001253drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001254{
Pekka Paalanende685b82012-12-04 15:58:12 +02001255 assert(fb->buffer_ref.buffer == NULL);
Daniel Stonef522e222016-11-18 12:31:26 +00001256 assert(fb->type == BUFFER_CLIENT || fb->type == BUFFER_DMABUF);
Pekka Paalanende685b82012-12-04 15:58:12 +02001257 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001258}
1259
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001260static void
Daniel Stone05a5ac22017-04-04 17:54:25 +01001261drm_fb_unref(struct drm_fb *fb)
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001262{
1263 if (!fb)
1264 return;
1265
Daniel Stone6e7a9612017-04-04 17:54:26 +01001266 assert(fb->refcnt > 0);
1267 if (--fb->refcnt > 0)
1268 return;
1269
Daniel Stonefc175a72017-04-04 17:54:22 +01001270 switch (fb->type) {
1271 case BUFFER_PIXMAN_DUMB:
Daniel Stone6e7a9612017-04-04 17:54:26 +01001272 drm_fb_destroy_dumb(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +01001273 break;
Daniel Stonee4256832017-04-04 17:54:27 +01001274 case BUFFER_CURSOR:
Daniel Stonefc175a72017-04-04 17:54:22 +01001275 case BUFFER_CLIENT:
1276 gbm_bo_destroy(fb->bo);
1277 break;
1278 case BUFFER_GBM_SURFACE:
Daniel Stone05a5ac22017-04-04 17:54:25 +01001279 gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
Daniel Stonefc175a72017-04-04 17:54:22 +01001280 break;
Daniel Stonef522e222016-11-18 12:31:26 +00001281 case BUFFER_DMABUF:
1282 drm_fb_destroy_dmabuf(fb);
1283 break;
Daniel Stonefc175a72017-04-04 17:54:22 +01001284 default:
1285 assert(NULL);
1286 break;
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001287 }
1288}
1289
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001290/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001291 * Allocate a new, empty, plane state.
1292 */
1293static struct drm_plane_state *
1294drm_plane_state_alloc(struct drm_output_state *state_output,
1295 struct drm_plane *plane)
1296{
1297 struct drm_plane_state *state = zalloc(sizeof(*state));
1298
1299 assert(state);
1300 state->output_state = state_output;
1301 state->plane = plane;
1302
1303 /* Here we only add the plane state to the desired link, and not
1304 * set the member. Having an output pointer set means that the
1305 * plane will be displayed on the output; this won't be the case
1306 * when we go to disable a plane. In this case, it must be part of
1307 * the commit (and thus the output state), but the member must be
1308 * NULL, as it will not be on any output when the state takes
1309 * effect.
1310 */
1311 if (state_output)
1312 wl_list_insert(&state_output->plane_list, &state->link);
1313 else
1314 wl_list_init(&state->link);
1315
1316 return state;
1317}
1318
1319/**
1320 * Free an existing plane state. As a special case, the state will not
1321 * normally be freed if it is the current state; see drm_plane_set_state.
1322 */
1323static void
1324drm_plane_state_free(struct drm_plane_state *state, bool force)
1325{
1326 if (!state)
1327 return;
1328
1329 wl_list_remove(&state->link);
1330 wl_list_init(&state->link);
1331 state->output_state = NULL;
1332
1333 if (force || state != state->plane->state_cur) {
1334 drm_fb_unref(state->fb);
1335 free(state);
1336 }
1337}
1338
1339/**
1340 * Duplicate an existing plane state into a new plane state, storing it within
1341 * the given output state. If the output state already contains a plane state
1342 * for the drm_plane referenced by 'src', that plane state is freed first.
1343 */
1344static struct drm_plane_state *
1345drm_plane_state_duplicate(struct drm_output_state *state_output,
1346 struct drm_plane_state *src)
1347{
1348 struct drm_plane_state *dst = malloc(sizeof(*dst));
1349 struct drm_plane_state *old, *tmp;
1350
1351 assert(src);
1352 assert(dst);
1353 *dst = *src;
1354 wl_list_init(&dst->link);
1355
1356 wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
1357 /* Duplicating a plane state into the same output state, so
1358 * it can replace itself with an identical copy of itself,
1359 * makes no sense. */
1360 assert(old != src);
1361 if (old->plane == dst->plane)
1362 drm_plane_state_free(old, false);
1363 }
1364
1365 wl_list_insert(&state_output->plane_list, &dst->link);
1366 if (src->fb)
1367 dst->fb = drm_fb_ref(src->fb);
1368 dst->output_state = state_output;
1369 dst->complete = false;
1370
1371 return dst;
1372}
1373
1374/**
1375 * Remove a plane state from an output state; if the plane was previously
1376 * enabled, then replace it with a disabling state. This ensures that the
1377 * output state was untouched from it was before the plane state was
1378 * modified by the caller of this function.
1379 *
1380 * This is required as drm_output_state_get_plane may either allocate a
1381 * new plane state, in which case this function will just perform a matching
1382 * drm_plane_state_free, or it may instead repurpose an existing disabling
1383 * state (if the plane was previously active), in which case this function
1384 * will reset it.
1385 */
1386static void
1387drm_plane_state_put_back(struct drm_plane_state *state)
1388{
1389 struct drm_output_state *state_output;
1390 struct drm_plane *plane;
1391
1392 if (!state)
1393 return;
1394
1395 state_output = state->output_state;
1396 plane = state->plane;
1397 drm_plane_state_free(state, false);
1398
1399 /* Plane was previously disabled; no need to keep this temporary
1400 * state around. */
1401 if (!plane->state_cur->fb)
1402 return;
1403
1404 (void) drm_plane_state_alloc(state_output, plane);
1405}
1406
Daniel Stonece137472016-11-16 19:35:03 +00001407static bool
1408drm_view_transform_supported(struct weston_view *ev, struct weston_output *output)
1409{
1410 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
1411
1412 /* This will incorrectly disallow cases where the combination of
1413 * buffer and view transformations match the output transform.
1414 * Fixing this requires a full analysis of the transformation
1415 * chain. */
1416 if (ev->transform.enabled &&
1417 ev->transform.matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE)
1418 return false;
1419
1420 if (viewport->buffer.transform != output->transform)
1421 return false;
1422
1423 return true;
1424}
1425
Daniel Stonebc15f682016-11-14 16:57:01 +00001426/**
Daniel Stoned6e2a762016-11-16 19:33:20 +00001427 * Given a weston_view, fill the drm_plane_state's co-ordinates to display on
1428 * a given plane.
1429 */
Daniel Stonece137472016-11-16 19:35:03 +00001430static bool
Daniel Stoned6e2a762016-11-16 19:33:20 +00001431drm_plane_state_coords_for_view(struct drm_plane_state *state,
1432 struct weston_view *ev)
1433{
1434 struct drm_output *output = state->output;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001435 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001436 pixman_region32_t dest_rect, src_rect;
1437 pixman_box32_t *box, tbox;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001438 float sxf1, syf1, sxf2, syf2;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001439
Daniel Stonece137472016-11-16 19:35:03 +00001440 if (!drm_view_transform_supported(ev, &output->base))
1441 return false;
1442
Daniel Stoned6e2a762016-11-16 19:33:20 +00001443 /* Update the base weston_plane co-ordinates. */
1444 box = pixman_region32_extents(&ev->transform.boundingbox);
1445 state->plane->base.x = box->x1;
1446 state->plane->base.y = box->y1;
1447
1448 /* First calculate the destination co-ordinates by taking the
1449 * area of the view which is visible on this output, performing any
1450 * transforms to account for output rotation and scale as necessary. */
1451 pixman_region32_init(&dest_rect);
1452 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
1453 &output->base.region);
1454 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
1455 box = pixman_region32_extents(&dest_rect);
1456 tbox = weston_transformed_rect(output->base.width,
1457 output->base.height,
1458 output->base.transform,
1459 output->base.current_scale,
1460 *box);
1461 state->dest_x = tbox.x1;
1462 state->dest_y = tbox.y1;
1463 state->dest_w = tbox.x2 - tbox.x1;
1464 state->dest_h = tbox.y2 - tbox.y1;
1465 pixman_region32_fini(&dest_rect);
1466
1467 /* Now calculate the source rectangle, by finding the extents of the
1468 * view, and working backwards to source co-ordinates. */
1469 pixman_region32_init(&src_rect);
1470 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
1471 &output->base.region);
1472 box = pixman_region32_extents(&src_rect);
Daniel Stonedf2726a2017-02-07 18:48:19 +00001473 weston_view_from_global_float(ev, box->x1, box->y1, &sxf1, &syf1);
1474 weston_surface_to_buffer_float(ev->surface, sxf1, syf1, &sxf1, &syf1);
1475 weston_view_from_global_float(ev, box->x2, box->y2, &sxf2, &syf2);
1476 weston_surface_to_buffer_float(ev->surface, sxf2, syf2, &sxf2, &syf2);
1477 pixman_region32_fini(&src_rect);
Daniel Stoned6e2a762016-11-16 19:33:20 +00001478
Daniel Stonedf2726a2017-02-07 18:48:19 +00001479 /* Buffer transforms may mean that x2 is to the left of x1, and/or that
1480 * y2 is above y1. */
1481 if (sxf2 < sxf1) {
1482 double tmp = sxf1;
1483 sxf1 = sxf2;
1484 sxf2 = tmp;
1485 }
1486 if (syf2 < syf1) {
1487 double tmp = syf1;
1488 syf1 = syf2;
1489 syf2 = tmp;
1490 }
1491
1492 /* Shift from S23.8 wl_fixed to U16.16 KMS fixed-point encoding. */
1493 state->src_x = wl_fixed_from_double(sxf1) << 8;
1494 state->src_y = wl_fixed_from_double(syf1) << 8;
1495 state->src_w = wl_fixed_from_double(sxf2 - sxf1) << 8;
1496 state->src_h = wl_fixed_from_double(syf2 - syf1) << 8;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001497
1498 /* Clamp our source co-ordinates to surface bounds; it's possible
1499 * for intermediate translations to give us slightly incorrect
1500 * co-ordinates if we have, for example, multiple zooming
1501 * transformations. View bounding boxes are also explicitly rounded
1502 * greedily. */
Daniel Stonedf2726a2017-02-07 18:48:19 +00001503 if (state->src_x < 0)
1504 state->src_x = 0;
1505 if (state->src_y < 0)
1506 state->src_y = 0;
1507 if (state->src_w > (uint32_t) ((buffer->width << 16) - state->src_x))
1508 state->src_w = (buffer->width << 16) - state->src_x;
1509 if (state->src_h > (uint32_t) ((buffer->height << 16) - state->src_y))
1510 state->src_h = (buffer->height << 16) - state->src_y;
Daniel Stonece137472016-11-16 19:35:03 +00001511
1512 return true;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001513}
1514
Daniel Stonef11ec022016-11-17 17:32:42 +00001515static bool
1516drm_view_is_opaque(struct weston_view *ev)
1517{
1518 pixman_region32_t r;
1519 bool ret = false;
1520
1521 pixman_region32_init_rect(&r, 0, 0,
1522 ev->surface->width,
1523 ev->surface->height);
1524 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
1525
1526 if (!pixman_region32_not_empty(&r))
1527 ret = true;
1528
1529 pixman_region32_fini(&r);
1530
1531 return ret;
1532}
1533
1534static struct drm_fb *
1535drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
1536{
1537 struct drm_output *output = state->output;
1538 struct drm_backend *b = to_drm_backend(output->base.compositor);
1539 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Daniel Stonef522e222016-11-18 12:31:26 +00001540 bool is_opaque = drm_view_is_opaque(ev);
Daniel Stonef11ec022016-11-17 17:32:42 +00001541 struct linux_dmabuf_buffer *dmabuf;
1542 struct drm_fb *fb;
Daniel Stonef11ec022016-11-17 17:32:42 +00001543
1544 /* Don't import buffers which span multiple outputs. */
1545 if (ev->output_mask != (1u << output->base.id))
1546 return NULL;
1547
1548 if (ev->alpha != 1.0f)
1549 return NULL;
1550
1551 if (!drm_view_transform_supported(ev, &output->base))
1552 return NULL;
1553
1554 if (!buffer)
1555 return NULL;
1556
1557 if (wl_shm_buffer_get(buffer->resource))
1558 return NULL;
1559
Daniel Stonef522e222016-11-18 12:31:26 +00001560 /* GBM is used for dmabuf import as well as from client wl_buffer. */
Daniel Stonef11ec022016-11-17 17:32:42 +00001561 if (!b->gbm)
1562 return NULL;
1563
1564 dmabuf = linux_dmabuf_buffer_get(buffer->resource);
1565 if (dmabuf) {
Daniel Stonef522e222016-11-18 12:31:26 +00001566 fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque);
1567 if (!fb)
Daniel Stonef11ec022016-11-17 17:32:42 +00001568 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00001569 } else {
Daniel Stonef522e222016-11-18 12:31:26 +00001570 struct gbm_bo *bo;
1571
Daniel Stonef11ec022016-11-17 17:32:42 +00001572 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
1573 buffer->resource, GBM_BO_USE_SCANOUT);
Daniel Stonef522e222016-11-18 12:31:26 +00001574 if (!bo)
1575 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00001576
Daniel Stonef522e222016-11-18 12:31:26 +00001577 fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT);
1578 if (!fb) {
1579 gbm_bo_destroy(bo);
1580 return NULL;
1581 }
Daniel Stonef11ec022016-11-17 17:32:42 +00001582 }
1583
1584 drm_fb_set_buffer(fb, buffer);
1585 return fb;
1586}
1587
Daniel Stoned6e2a762016-11-16 19:33:20 +00001588/**
Daniel Stone2ba17f42015-05-19 20:02:41 +01001589 * Return a plane state from a drm_output_state.
1590 */
1591static struct drm_plane_state *
1592drm_output_state_get_existing_plane(struct drm_output_state *state_output,
1593 struct drm_plane *plane)
1594{
1595 struct drm_plane_state *ps;
1596
1597 wl_list_for_each(ps, &state_output->plane_list, link) {
1598 if (ps->plane == plane)
1599 return ps;
1600 }
1601
1602 return NULL;
1603}
1604
1605/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001606 * Return a plane state from a drm_output_state, either existing or
1607 * freshly allocated.
1608 */
1609static struct drm_plane_state *
1610drm_output_state_get_plane(struct drm_output_state *state_output,
1611 struct drm_plane *plane)
1612{
1613 struct drm_plane_state *ps;
1614
Daniel Stone2ba17f42015-05-19 20:02:41 +01001615 ps = drm_output_state_get_existing_plane(state_output, plane);
1616 if (ps)
1617 return ps;
Daniel Stonebc15f682016-11-14 16:57:01 +00001618
1619 return drm_plane_state_alloc(state_output, plane);
1620}
1621
1622/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001623 * Allocate a new, empty drm_output_state. This should not generally be used
1624 * in the repaint cycle; see drm_output_state_duplicate.
1625 */
1626static struct drm_output_state *
1627drm_output_state_alloc(struct drm_output *output,
1628 struct drm_pending_state *pending_state)
Daniel Stone90648872016-10-21 18:08:37 +01001629{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001630 struct drm_output_state *state = zalloc(sizeof(*state));
1631
1632 assert(state);
1633 state->output = output;
Daniel Stonea08512f2016-11-08 17:46:10 +00001634 state->dpms = WESTON_DPMS_OFF;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001635 state->pending_state = pending_state;
1636 if (pending_state)
1637 wl_list_insert(&pending_state->output_list, &state->link);
1638 else
1639 wl_list_init(&state->link);
1640
Daniel Stonebc15f682016-11-14 16:57:01 +00001641 wl_list_init(&state->plane_list);
1642
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001643 return state;
1644}
1645
1646/**
1647 * Duplicate an existing drm_output_state into a new one. This is generally
1648 * used during the repaint cycle, to capture the existing state of an output
1649 * and modify it to create a new state to be used.
1650 *
1651 * The mode determines whether the output will be reset to an a blank state,
1652 * or an exact mirror of the current state.
1653 */
1654static struct drm_output_state *
1655drm_output_state_duplicate(struct drm_output_state *src,
1656 struct drm_pending_state *pending_state,
1657 enum drm_output_state_duplicate_mode plane_mode)
1658{
1659 struct drm_output_state *dst = malloc(sizeof(*dst));
Daniel Stonebc15f682016-11-14 16:57:01 +00001660 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001661
1662 assert(dst);
1663
1664 /* Copy the whole structure, then individually modify the
1665 * pending_state, as well as the list link into our pending
1666 * state. */
1667 *dst = *src;
1668
1669 dst->pending_state = pending_state;
1670 if (pending_state)
1671 wl_list_insert(&pending_state->output_list, &dst->link);
1672 else
1673 wl_list_init(&dst->link);
1674
Daniel Stonebc15f682016-11-14 16:57:01 +00001675 wl_list_init(&dst->plane_list);
1676
1677 wl_list_for_each(ps, &src->plane_list, link) {
1678 /* Don't carry planes which are now disabled; these should be
1679 * free for other outputs to reuse. */
1680 if (!ps->output)
1681 continue;
1682
1683 if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
1684 (void) drm_plane_state_alloc(dst, ps->plane);
1685 else
1686 (void) drm_plane_state_duplicate(dst, ps);
1687 }
1688
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001689 return dst;
1690}
1691
1692/**
1693 * Free an unused drm_output_state.
1694 */
1695static void
1696drm_output_state_free(struct drm_output_state *state)
1697{
Daniel Stonebc15f682016-11-14 16:57:01 +00001698 struct drm_plane_state *ps, *next;
1699
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001700 if (!state)
1701 return;
1702
Daniel Stonebc15f682016-11-14 16:57:01 +00001703 wl_list_for_each_safe(ps, next, &state->plane_list, link)
1704 drm_plane_state_free(ps, false);
1705
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001706 wl_list_remove(&state->link);
Daniel Stonebc15f682016-11-14 16:57:01 +00001707
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001708 free(state);
Daniel Stone90648872016-10-21 18:08:37 +01001709}
1710
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001711/**
Daniel Stonea08512f2016-11-08 17:46:10 +00001712 * Get output state to disable output
1713 *
1714 * Returns a pointer to an output_state object which can be used to disable
1715 * an output (e.g. DPMS off).
1716 *
1717 * @param pending_state The pending state object owning this update
1718 * @param output The output to disable
1719 * @returns A drm_output_state to disable the output
1720 */
1721static struct drm_output_state *
1722drm_output_get_disable_state(struct drm_pending_state *pending_state,
1723 struct drm_output *output)
1724{
1725 struct drm_output_state *output_state;
1726
1727 output_state = drm_output_state_duplicate(output->state_cur,
1728 pending_state,
1729 DRM_OUTPUT_STATE_CLEAR_PLANES);
1730 output_state->dpms = WESTON_DPMS_OFF;
1731
1732 return output_state;
1733}
1734
1735/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001736 * Allocate a new drm_pending_state
1737 *
1738 * Allocate a new, empty, 'pending state' structure to be used across a
1739 * repaint cycle or similar.
1740 *
1741 * @param backend DRM backend
1742 * @returns Newly-allocated pending state structure
1743 */
1744static struct drm_pending_state *
1745drm_pending_state_alloc(struct drm_backend *backend)
1746{
1747 struct drm_pending_state *ret;
1748
1749 ret = calloc(1, sizeof(*ret));
1750 if (!ret)
1751 return NULL;
1752
1753 ret->backend = backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001754 wl_list_init(&ret->output_list);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001755
1756 return ret;
1757}
1758
1759/**
1760 * Free a drm_pending_state structure
1761 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001762 * Frees a pending_state structure, as well as any output_states connected
1763 * to this pending state.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001764 *
1765 * @param pending_state Pending state structure to free
1766 */
1767static void
1768drm_pending_state_free(struct drm_pending_state *pending_state)
1769{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001770 struct drm_output_state *output_state, *tmp;
1771
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001772 if (!pending_state)
1773 return;
1774
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001775 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1776 link) {
1777 drm_output_state_free(output_state);
1778 }
1779
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001780 free(pending_state);
1781}
1782
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001783/**
1784 * Find an output state in a pending state
1785 *
1786 * Given a pending_state structure, find the output_state for a particular
1787 * output.
1788 *
1789 * @param pending_state Pending state structure to search
1790 * @param output Output to find state for
1791 * @returns Output state if present, or NULL if not
1792 */
1793static struct drm_output_state *
1794drm_pending_state_get_output(struct drm_pending_state *pending_state,
1795 struct drm_output *output)
1796{
1797 struct drm_output_state *output_state;
1798
1799 wl_list_for_each(output_state, &pending_state->output_list, link) {
1800 if (output_state->output == output)
1801 return output_state;
1802 }
1803
1804 return NULL;
1805}
1806
Daniel Stonea08512f2016-11-08 17:46:10 +00001807static int drm_pending_state_apply_sync(struct drm_pending_state *state);
1808
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001809/**
1810 * Mark a drm_output_state (the output's last state) as complete. This handles
1811 * any post-completion actions such as updating the repaint timer, disabling the
1812 * output, and finally freeing the state.
1813 */
1814static void
1815drm_output_update_complete(struct drm_output *output, uint32_t flags,
1816 unsigned int sec, unsigned int usec)
1817{
Daniel Stonea08512f2016-11-08 17:46:10 +00001818 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001819 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001820 struct timespec ts;
1821
1822 /* Stop the pageflip timer instead of rearming it here */
1823 if (output->pageflip_timer)
1824 wl_event_source_timer_update(output->pageflip_timer, 0);
1825
Daniel Stonebc15f682016-11-14 16:57:01 +00001826 wl_list_for_each(ps, &output->state_cur->plane_list, link)
1827 ps->complete = true;
1828
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001829 drm_output_state_free(output->state_last);
1830 output->state_last = NULL;
1831
1832 if (output->destroy_pending) {
Daniel Stonea08512f2016-11-08 17:46:10 +00001833 output->destroy_pending = 0;
1834 output->disable_pending = 0;
1835 output->dpms_off_pending = 0;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001836 drm_output_destroy(&output->base);
1837 return;
1838 } else if (output->disable_pending) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001839 output->disable_pending = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00001840 output->dpms_off_pending = 0;
1841 weston_output_disable(&output->base);
1842 return;
1843 } else if (output->dpms_off_pending) {
1844 struct drm_pending_state *pending = drm_pending_state_alloc(b);
1845 output->dpms_off_pending = 0;
1846 drm_output_get_disable_state(pending, output);
1847 drm_pending_state_apply_sync(pending);
1848 return;
1849 } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
1850 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
1851 /* DPMS can happen to us either in the middle of a repaint
1852 * cycle (when we have painted fresh content, only to throw it
1853 * away for DPMS off), or at any other random point. If the
1854 * latter is true, then we cannot go through finish_frame,
1855 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001856 return;
1857 }
1858
1859 ts.tv_sec = sec;
1860 ts.tv_nsec = usec * 1000;
1861 weston_output_finish_frame(&output->base, &ts, flags);
1862
1863 /* We can't call this from frame_notify, because the output's
1864 * repaint needed flag is cleared just after that */
1865 if (output->recorder)
1866 weston_output_schedule_repaint(&output->base);
1867}
1868
1869/**
1870 * Mark an output state as current on the output, i.e. it has been
1871 * submitted to the kernel. The mode argument determines whether this
1872 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
1873 * or asynchronously (in which case we wait for events to complete).
1874 */
1875static void
1876drm_output_assign_state(struct drm_output_state *state,
1877 enum drm_state_apply_mode mode)
1878{
1879 struct drm_output *output = state->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00001880 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001881 struct drm_plane_state *plane_state;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001882
1883 assert(!output->state_last);
1884
1885 if (mode == DRM_STATE_APPLY_ASYNC)
1886 output->state_last = output->state_cur;
1887 else
1888 drm_output_state_free(output->state_cur);
1889
1890 wl_list_remove(&state->link);
1891 wl_list_init(&state->link);
1892 state->pending_state = NULL;
1893
1894 output->state_cur = state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001895
Daniel Stone598ee9d2016-11-16 11:55:20 +00001896 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC)
1897 output->atomic_complete_pending = 1;
1898
Daniel Stonebc15f682016-11-14 16:57:01 +00001899 /* Replace state_cur on each affected plane with the new state, being
1900 * careful to dispose of orphaned (but only orphaned) previous state.
1901 * If the previous state is not orphaned (still has an output_state
1902 * attached), it will be disposed of by freeing the output_state. */
1903 wl_list_for_each(plane_state, &state->plane_list, link) {
1904 struct drm_plane *plane = plane_state->plane;
1905
1906 if (plane->state_cur && !plane->state_cur->output_state)
1907 drm_plane_state_free(plane->state_cur, true);
1908 plane->state_cur = plane_state;
1909
1910 if (mode != DRM_STATE_APPLY_ASYNC) {
1911 plane_state->complete = true;
1912 continue;
1913 }
1914
Daniel Stone598ee9d2016-11-16 11:55:20 +00001915 if (b->atomic_modeset)
1916 continue;
1917
Daniel Stonebc15f682016-11-14 16:57:01 +00001918 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
1919 output->vblank_pending++;
Daniel Stonee2e80132018-01-16 15:37:33 +00001920 else if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
1921 output->page_flip_pending = 1;
Daniel Stonebc15f682016-11-14 16:57:01 +00001922 }
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001923}
1924
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001925static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001926drm_output_prepare_scanout_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001927 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001928{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001929 struct drm_output *output = output_state->output;
Daniel Stonee2e80132018-01-16 15:37:33 +00001930 struct drm_plane *scanout_plane = output->scanout_plane;
1931 struct drm_plane_state *state;
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001932 struct drm_fb *fb;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001933 pixman_box32_t *extents;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001934
Daniel Stone7cdf2312016-11-16 19:40:29 +00001935 /* Check the view spans exactly the output size, calculated in the
1936 * logical co-ordinate space. */
1937 extents = pixman_region32_extents(&ev->transform.boundingbox);
1938 if (extents->x1 != output->base.x ||
1939 extents->y1 != output->base.y ||
1940 extents->x2 != output->base.x + output->base.width ||
1941 extents->y2 != output->base.y + output->base.height)
Daniel Stone90648872016-10-21 18:08:37 +01001942 return NULL;
1943
1944 if (ev->alpha != 1.0f)
1945 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001946
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001947 fb = drm_fb_get_from_view(output_state, ev);
1948 if (!fb)
1949 return NULL;
1950
1951 /* Can't change formats with just a pageflip */
1952 if (fb->format->format != output->gbm_format) {
1953 drm_fb_unref(fb);
1954 return NULL;
1955 }
1956
Daniel Stonee2e80132018-01-16 15:37:33 +00001957 state = drm_output_state_get_plane(output_state, scanout_plane);
1958 if (state->fb) {
1959 /* If there is already a framebuffer on the scanout plane,
1960 * a client view has already been placed on the scanout
1961 * view. In that case, do not free or put back the state,
1962 * but just leave it in place and quietly exit. */
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001963 drm_fb_unref(fb);
Daniel Stonee2e80132018-01-16 15:37:33 +00001964 return NULL;
1965 }
1966
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001967 state->fb = fb;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001968 state->output = output;
1969 if (!drm_plane_state_coords_for_view(state, ev))
1970 goto err;
1971
1972 /* The legacy API does not let us perform cropping or scaling. */
1973 if (state->src_x != 0 || state->src_y != 0 ||
1974 state->src_w != state->dest_w << 16 ||
1975 state->src_h != state->dest_h << 16 ||
1976 state->dest_x != 0 || state->dest_y != 0 ||
1977 state->dest_w != (unsigned) output->base.current_mode->width ||
1978 state->dest_h != (unsigned) output->base.current_mode->height)
1979 goto err;
1980
Daniel Stonee2e80132018-01-16 15:37:33 +00001981 return &scanout_plane->base;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001982
1983err:
1984 drm_plane_state_put_back(state);
1985 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001986}
1987
Daniel Stone95d48a22017-04-04 17:54:30 +01001988static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001989drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001990{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001991 struct drm_output *output = state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02001992 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001993 struct gbm_bo *bo;
Daniel Stone95d48a22017-04-04 17:54:30 +01001994 struct drm_fb *ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001995
Giulio Camuffo954f1832014-10-11 18:27:30 +03001996 output->base.compositor->renderer->repaint_output(&output->base,
1997 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001998
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001999 bo = gbm_surface_lock_front_buffer(output->gbm_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002000 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +02002001 weston_log("failed to lock front buffer: %m\n");
Daniel Stone95d48a22017-04-04 17:54:30 +01002002 return NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002003 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002004
Daniel Stonedb10df12016-12-08 13:15:58 +00002005 /* The renderer always produces an opaque image. */
2006 ret = drm_fb_get_from_bo(bo, b, true, BUFFER_GBM_SURFACE);
Daniel Stone95d48a22017-04-04 17:54:30 +01002007 if (!ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002008 weston_log("failed to get drm_fb for bo\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01002009 gbm_surface_release_buffer(output->gbm_surface, bo);
Daniel Stone95d48a22017-04-04 17:54:30 +01002010 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002011 }
Daniel Stone95d48a22017-04-04 17:54:30 +01002012 ret->gbm_surface = output->gbm_surface;
2013
2014 return ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002015}
2016
Daniel Stone95d48a22017-04-04 17:54:30 +01002017static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002018drm_output_render_pixman(struct drm_output_state *state,
2019 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002020{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002021 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002022 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002023
2024 output->current_image ^= 1;
2025
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002026 pixman_renderer_output_set_buffer(&output->base,
2027 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +02002028 pixman_renderer_output_set_hw_extra_damage(&output->base,
2029 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002030
Pekka Paalanenacf50c32018-04-23 11:44:56 +02002031 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002032
Pekka Paalanenacf50c32018-04-23 11:44:56 +02002033 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +01002034
2035 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002036}
2037
2038static void
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002039drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002040{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002041 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002042 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +00002043 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +00002044 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02002045 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +01002046 struct drm_fb *fb;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002047
Daniel Stone4e84f7d2017-04-04 17:54:29 +01002048 /* If we already have a client buffer promoted to scanout, then we don't
2049 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +00002050 scanout_state = drm_output_state_get_plane(state,
2051 output->scanout_plane);
2052 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +01002053 return;
2054
Daniel Stonee95169b2016-11-14 17:46:59 +00002055 if (!pixman_region32_not_empty(damage) &&
2056 scanout_plane->state_cur->fb &&
2057 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
2058 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
2059 scanout_plane->state_cur->fb->width ==
2060 output->base.current_mode->width &&
2061 scanout_plane->state_cur->fb->height ==
2062 output->base.current_mode->height) {
2063 fb = drm_fb_ref(scanout_plane->state_cur->fb);
2064 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002065 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00002066 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002067 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00002068 }
Daniel Stone95d48a22017-04-04 17:54:30 +01002069
Daniel Stonee2e80132018-01-16 15:37:33 +00002070 if (!fb) {
2071 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +01002072 return;
Daniel Stonee2e80132018-01-16 15:37:33 +00002073 }
2074
2075 scanout_state->fb = fb;
2076 scanout_state->output = output;
2077
2078 scanout_state->src_x = 0;
2079 scanout_state->src_y = 0;
2080 scanout_state->src_w = output->base.current_mode->width << 16;
2081 scanout_state->src_h = output->base.current_mode->height << 16;
2082
2083 scanout_state->dest_x = 0;
2084 scanout_state->dest_y = 0;
2085 scanout_state->dest_w = scanout_state->src_w >> 16;
2086 scanout_state->dest_h = scanout_state->src_h >> 16;
2087
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002088
Giulio Camuffo954f1832014-10-11 18:27:30 +03002089 pixman_region32_subtract(&c->primary_plane.damage,
2090 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002091}
2092
2093static void
Richard Hughese7299962013-05-01 21:52:12 +01002094drm_output_set_gamma(struct weston_output *output_base,
2095 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
2096{
2097 int rc;
Armin Krezović545dba62016-08-05 15:54:18 +02002098 struct drm_output *output = to_drm_output(output_base);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002099 struct drm_backend *backend =
Armin Krezović545dba62016-08-05 15:54:18 +02002100 to_drm_backend(output->base.compositor);
Richard Hughese7299962013-05-01 21:52:12 +01002101
2102 /* check */
2103 if (output_base->gamma_size != size)
2104 return;
Richard Hughese7299962013-05-01 21:52:12 +01002105
Giulio Camuffo954f1832014-10-11 18:27:30 +03002106 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +01002107 output->crtc_id,
2108 size, r, g, b);
2109 if (rc)
2110 weston_log("set gamma failed: %m\n");
2111}
2112
Bryce Harringtonada4f072015-06-30 13:25:46 -07002113/* Determine the type of vblank synchronization to use for the output.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002114 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07002115 * The pipe parameter indicates which CRTC is in use. Knowing this, we
2116 * can determine which vblank sequence type to use for it. Traditional
2117 * cards had only two CRTCs, with CRTC 0 using no special flags, and
2118 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
2119 * parameter indicates this.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002120 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07002121 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
2122 * 0-31. If this is non-zero it indicates we're dealing with a
2123 * multi-gpu situation and we need to calculate the vblank sync
2124 * using DRM_BLANK_HIGH_CRTC_MASK.
2125 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +03002126static unsigned int
2127drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02002128{
2129 if (output->pipe > 1)
2130 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
2131 DRM_VBLANK_HIGH_CRTC_MASK;
2132 else if (output->pipe > 0)
2133 return DRM_VBLANK_SECONDARY;
2134 else
2135 return 0;
2136}
2137
David Herrmann1edf44c2013-10-22 17:11:26 +02002138static int
Daniel Stone598ee9d2016-11-16 11:55:20 +00002139drm_output_apply_state_legacy(struct drm_output_state *state)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002140{
Daniel Stonea08512f2016-11-08 17:46:10 +00002141 struct drm_output *output = state->output;
2142 struct drm_backend *backend = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00002143 struct drm_plane *scanout_plane = output->scanout_plane;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002144 struct drm_property_info *dpms_prop;
Daniel Stonee2e80132018-01-16 15:37:33 +00002145 struct drm_plane_state *scanout_state;
Daniel Stonebc15f682016-11-14 16:57:01 +00002146 struct drm_plane_state *ps;
Daniel Stone085d2b92015-05-21 00:00:57 +01002147 struct drm_plane *p;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002148 struct drm_mode *mode;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002149 struct drm_head *head;
2150 uint32_t connectors[MAX_CLONED_CONNECTORS];
2151 int n_conn = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00002152 struct timespec now;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002153 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002154
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002155 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2156 assert(n_conn < MAX_CLONED_CONNECTORS);
2157 connectors[n_conn++] = head->connector_id;
2158 }
2159
Derek Foreman2cd87fe2017-04-13 13:48:48 -05002160 /* If disable_planes is set then assign_planes() wasn't
2161 * called for this render, so we could still have a stale
2162 * cursor plane set up.
2163 */
2164 if (output->base.disable_planes) {
2165 output->cursor_view = NULL;
Greg V1f781762018-02-19 17:59:42 +03002166 if (output->cursor_plane) {
2167 output->cursor_plane->base.x = INT32_MIN;
2168 output->cursor_plane->base.y = INT32_MIN;
2169 }
Derek Foreman2cd87fe2017-04-13 13:48:48 -05002170 }
2171
Daniel Stonea08512f2016-11-08 17:46:10 +00002172 if (state->dpms != WESTON_DPMS_ON) {
2173 wl_list_for_each(ps, &state->plane_list, link) {
2174 p = ps->plane;
2175 assert(ps->fb == NULL);
2176 assert(ps->output == NULL);
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002177
Daniel Stonea08512f2016-11-08 17:46:10 +00002178 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2179 continue;
2180
2181 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
2182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2183 if (ret)
2184 weston_log("drmModeSetPlane failed disable: %m\n");
2185 }
2186
2187 if (output->cursor_plane) {
2188 ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
2189 0, 0, 0);
2190 if (ret)
2191 weston_log("drmModeSetCursor failed disable: %m\n");
2192 }
2193
2194 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002195 NULL, 0, NULL);
Daniel Stonea08512f2016-11-08 17:46:10 +00002196 if (ret)
2197 weston_log("drmModeSetCrtc failed disabling: %m\n");
2198
2199 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
2200 weston_compositor_read_presentation_clock(output->base.compositor, &now);
2201 drm_output_update_complete(output,
2202 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
2203 now.tv_sec, now.tv_nsec / 1000);
2204
2205 return 0;
2206 }
2207
2208 scanout_state =
2209 drm_output_state_get_existing_plane(state, scanout_plane);
Daniel Stone087ddf02017-02-14 17:51:30 +00002210
Daniel Stonee2e80132018-01-16 15:37:33 +00002211 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
2212 * legacy PageFlip API doesn't allow us to do clipping either. */
2213 assert(scanout_state->src_x == 0);
2214 assert(scanout_state->src_y == 0);
2215 assert(scanout_state->src_w ==
2216 (unsigned) (output->base.current_mode->width << 16));
2217 assert(scanout_state->src_h ==
2218 (unsigned) (output->base.current_mode->height << 16));
2219 assert(scanout_state->dest_x == 0);
2220 assert(scanout_state->dest_y == 0);
2221 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
2222 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
2223
Daniel Stonecb04cc42016-11-16 11:51:27 +00002224 mode = to_drm_mode(output->base.current_mode);
Daniel Stone8eece0c2016-11-17 17:54:00 +00002225 if (backend->state_invalid ||
2226 !scanout_plane->state_cur->fb ||
2227 scanout_plane->state_cur->fb->strides[0] !=
2228 scanout_state->fb->strides[0]) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002229 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00002230 scanout_state->fb->fb_id,
2231 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002232 connectors, n_conn,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002233 &mode->mode_info);
2234 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002235 weston_log("set mode failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002236 goto err;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002237 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02002238 }
2239
Giulio Camuffo954f1832014-10-11 18:27:30 +03002240 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00002241 scanout_state->fb->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05002242 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002243 weston_log("queueing pageflip failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002244 goto err;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05002245 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002246
Daniel Stone205c0a02017-04-04 17:54:33 +01002247 assert(!output->page_flip_pending);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002248
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002249 if (output->pageflip_timer)
2250 wl_event_source_timer_update(output->pageflip_timer,
2251 backend->pageflip_timeout);
2252
Daniel Stone2ba17f42015-05-19 20:02:41 +01002253 drm_output_set_cursor(state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04002254
Jesse Barnes58ef3792012-02-23 09:45:49 -05002255 /*
2256 * Now, update all the sprite surfaces
2257 */
Daniel Stonebc15f682016-11-14 16:57:01 +00002258 wl_list_for_each(ps, &state->plane_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002259 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002260 drmVBlank vbl = {
2261 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
2262 .request.sequence = 1,
2263 };
2264
Daniel Stonebc15f682016-11-14 16:57:01 +00002265 p = ps->plane;
Daniel Stone085d2b92015-05-21 00:00:57 +01002266 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002267 continue;
2268
Daniel Stonebc15f682016-11-14 16:57:01 +00002269 assert(p->state_cur->complete);
2270 assert(!!p->state_cur->output == !!p->state_cur->fb);
2271 assert(!p->state_cur->output || p->state_cur->output == output);
2272 assert(!ps->complete);
2273 assert(!ps->output || ps->output == output);
2274 assert(!!ps->output == !!ps->fb);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002275
Daniel Stonebc15f682016-11-14 16:57:01 +00002276 if (ps->fb && !backend->sprites_hidden)
2277 fb_id = ps->fb->fb_id;
Daniel Stone085d2b92015-05-21 00:00:57 +01002278
2279 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002280 output->crtc_id, fb_id, flags,
Daniel Stonebc15f682016-11-14 16:57:01 +00002281 ps->dest_x, ps->dest_y,
2282 ps->dest_w, ps->dest_h,
2283 ps->src_x, ps->src_y,
2284 ps->src_w, ps->src_h);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002285 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +02002286 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002287 ret, strerror(errno));
2288
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02002289 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -05002290
Jesse Barnes58ef3792012-02-23 09:45:49 -05002291 /*
2292 * Queue a vblank signal so we know when the surface
2293 * becomes active on the display or has been replaced.
2294 */
Daniel Stonebc15f682016-11-14 16:57:01 +00002295 vbl.request.signal = (unsigned long) ps;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002296 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002297 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002298 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002299 ret, strerror(errno));
2300 }
2301 }
2302
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002303 if (state->dpms != output->state_cur->dpms) {
2304 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2305 dpms_prop = &head->props_conn[WDRM_CONNECTOR_DPMS];
2306 if (dpms_prop->prop_id == 0)
2307 continue;
2308
2309 ret = drmModeConnectorSetProperty(backend->drm.fd,
2310 head->connector_id,
2311 dpms_prop->prop_id,
2312 state->dpms);
2313 if (ret) {
2314 weston_log("DRM: DPMS: failed property set for %s\n",
2315 head->base.name);
2316 }
Daniel Stonea08512f2016-11-08 17:46:10 +00002317 }
2318 }
2319
2320 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
2321
David Herrmann1edf44c2013-10-22 17:11:26 +02002322 return 0;
2323
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002324err:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -08002325 output->cursor_view = NULL;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002326 drm_output_state_free(state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002327 return -1;
2328}
David Herrmann1edf44c2013-10-22 17:11:26 +02002329
Daniel Stone598ee9d2016-11-16 11:55:20 +00002330#ifdef HAVE_DRM_ATOMIC
2331static int
2332crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
2333 enum wdrm_crtc_property prop, uint64_t val)
2334{
2335 struct drm_property_info *info = &output->props_crtc[prop];
2336 int ret;
2337
2338 if (info->prop_id == 0)
2339 return -1;
2340
2341 ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
2342 val);
2343 return (ret <= 0) ? -1 : 0;
2344}
2345
2346static int
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002347connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002348 enum wdrm_connector_property prop, uint64_t val)
2349{
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002350 struct drm_property_info *info = &head->props_conn[prop];
Daniel Stone598ee9d2016-11-16 11:55:20 +00002351 int ret;
2352
2353 if (info->prop_id == 0)
2354 return -1;
2355
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002356 ret = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002357 info->prop_id, val);
2358 return (ret <= 0) ? -1 : 0;
2359}
2360
2361static int
2362plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
2363 enum wdrm_plane_property prop, uint64_t val)
2364{
2365 struct drm_property_info *info = &plane->props[prop];
2366 int ret;
2367
2368 if (info->prop_id == 0)
2369 return -1;
2370
2371 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
2372 val);
2373 return (ret <= 0) ? -1 : 0;
2374}
2375
2376static int
2377drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
2378{
2379 int ret;
2380
2381 if (mode->blob_id)
2382 return 0;
2383
2384 ret = drmModeCreatePropertyBlob(backend->drm.fd,
2385 &mode->mode_info,
2386 sizeof(mode->mode_info),
2387 &mode->blob_id);
2388 if (ret != 0)
2389 weston_log("failed to create mode property blob: %m\n");
2390
2391 return ret;
2392}
2393
2394static int
2395drm_output_apply_state_atomic(struct drm_output_state *state,
2396 drmModeAtomicReq *req,
2397 uint32_t *flags)
2398{
2399 struct drm_output *output = state->output;
2400 struct drm_backend *backend = to_drm_backend(output->base.compositor);
2401 struct drm_plane_state *plane_state;
2402 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002403 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002404 int ret = 0;
2405
2406 if (state->dpms != output->state_cur->dpms)
2407 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2408
2409 if (state->dpms == WESTON_DPMS_ON) {
2410 ret = drm_mode_ensure_blob(backend, current_mode);
2411 if (ret != 0)
2412 return ret;
2413
2414 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
2415 current_mode->blob_id);
2416 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002417
Daniel Stone76255772018-07-06 11:36:49 +01002418 /* No need for the DPMS property, since it is implicit in
2419 * routing and CRTC activity. */
Pekka Paalanen2f661302017-09-12 16:07:32 +03002420 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2421 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
2422 output->crtc_id);
2423 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00002424 } else {
2425 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
2426 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002427
Daniel Stone76255772018-07-06 11:36:49 +01002428 /* No need for the DPMS property, since it is implicit in
2429 * routing and CRTC activity. */
Pekka Paalanen2f661302017-09-12 16:07:32 +03002430 wl_list_for_each(head, &output->base.head_list, base.output_link)
2431 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002432 }
2433
2434 if (ret != 0) {
2435 weston_log("couldn't set atomic CRTC/connector state\n");
2436 return ret;
2437 }
2438
2439 wl_list_for_each(plane_state, &state->plane_list, link) {
2440 struct drm_plane *plane = plane_state->plane;
2441
2442 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
2443 plane_state->fb ? plane_state->fb->fb_id : 0);
2444 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
2445 plane_state->fb ? output->crtc_id : 0);
2446 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
2447 plane_state->src_x);
2448 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
2449 plane_state->src_y);
2450 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
2451 plane_state->src_w);
2452 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
2453 plane_state->src_h);
2454 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
2455 plane_state->dest_x);
2456 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
2457 plane_state->dest_y);
2458 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
2459 plane_state->dest_w);
2460 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
2461 plane_state->dest_h);
2462
2463 if (ret != 0) {
2464 weston_log("couldn't set plane state\n");
2465 return ret;
2466 }
2467 }
2468
2469 return 0;
2470}
2471
2472/**
2473 * Helper function used only by drm_pending_state_apply, with the same
2474 * guarantees and constraints as that function.
2475 */
2476static int
2477drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
2478 enum drm_state_apply_mode mode)
2479{
2480 struct drm_backend *b = pending_state->backend;
2481 struct drm_output_state *output_state, *tmp;
2482 struct drm_plane *plane;
2483 drmModeAtomicReq *req = drmModeAtomicAlloc();
2484 uint32_t flags = 0;
2485 int ret = 0;
2486
2487 if (!req)
2488 return -1;
2489
2490 if (b->state_invalid) {
Pekka Paalaneneacec812017-09-12 13:43:51 +03002491 struct weston_head *head_base;
2492 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002493 uint32_t *unused;
2494 int err;
2495
2496 /* If we need to reset all our state (e.g. because we've
2497 * just started, or just been VT-switched in), explicitly
2498 * disable all the CRTCs and connectors we aren't using. */
Pekka Paalaneneacec812017-09-12 13:43:51 +03002499 wl_list_for_each(head_base,
2500 &b->compositor->head_list, compositor_link) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00002501 struct drm_property_info *info;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002502
Pekka Paalaneneacec812017-09-12 13:43:51 +03002503 if (weston_head_is_enabled(head_base))
Daniel Stone598ee9d2016-11-16 11:55:20 +00002504 continue;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002505
Pekka Paalaneneacec812017-09-12 13:43:51 +03002506 head = to_drm_head(head_base);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002507
Pekka Paalaneneacec812017-09-12 13:43:51 +03002508 info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
2509 err = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002510 info->prop_id, 0);
2511 if (err <= 0)
2512 ret = -1;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002513 }
2514
2515 wl_array_for_each(unused, &b->unused_crtcs) {
2516 struct drm_property_info infos[WDRM_CRTC__COUNT];
2517 struct drm_property_info *info;
2518 drmModeObjectProperties *props;
2519 uint64_t active;
2520
2521 memset(infos, 0, sizeof(infos));
2522
2523 /* We can't emit a disable on a CRTC that's already
2524 * off, as the kernel will refuse to generate an event
2525 * for an off->off state and fail the commit.
2526 */
2527 props = drmModeObjectGetProperties(b->drm.fd,
2528 *unused,
2529 DRM_MODE_OBJECT_CRTC);
2530 if (!props) {
2531 ret = -1;
2532 continue;
2533 }
2534
2535 drm_property_info_populate(b, crtc_props, infos,
2536 WDRM_CRTC__COUNT,
2537 props);
2538
2539 info = &infos[WDRM_CRTC_ACTIVE];
2540 active = drm_property_get_value(info, props, 0);
2541 drmModeFreeObjectProperties(props);
2542 if (active == 0) {
2543 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2544 continue;
2545 }
2546
2547 err = drmModeAtomicAddProperty(req, *unused,
2548 info->prop_id, 0);
2549 if (err <= 0)
2550 ret = -1;
2551
2552 info = &infos[WDRM_CRTC_MODE_ID];
2553 err = drmModeAtomicAddProperty(req, *unused,
2554 info->prop_id, 0);
2555 if (err <= 0)
2556 ret = -1;
2557
2558 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2559 }
2560
2561 /* Disable all the planes; planes which are being used will
2562 * override this state in the output-state application. */
2563 wl_list_for_each(plane, &b->plane_list, link) {
2564 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
2565 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
2566 }
2567
2568 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2569 }
2570
2571 wl_list_for_each(output_state, &pending_state->output_list, link) {
2572 if (mode == DRM_STATE_APPLY_SYNC)
2573 assert(output_state->dpms == WESTON_DPMS_OFF);
2574 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
2575 }
2576
2577 if (ret != 0) {
2578 weston_log("atomic: couldn't compile atomic state\n");
2579 goto out;
2580 }
2581
2582 switch (mode) {
2583 case DRM_STATE_APPLY_SYNC:
2584 break;
2585 case DRM_STATE_APPLY_ASYNC:
2586 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
2587 break;
2588 }
2589
2590 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
2591 if (ret != 0) {
2592 weston_log("atomic: couldn't commit new state: %m\n");
2593 goto out;
2594 }
2595
2596 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2597 link)
2598 drm_output_assign_state(output_state, mode);
2599
2600 b->state_invalid = false;
2601
2602 assert(wl_list_empty(&pending_state->output_list));
2603
2604out:
2605 drmModeAtomicFree(req);
2606 drm_pending_state_free(pending_state);
2607 return ret;
2608}
2609#endif
2610
Daniel Stonea08512f2016-11-08 17:46:10 +00002611/**
2612 * Applies all of a pending_state asynchronously: the primary entry point for
2613 * applying KMS state to a device. Updates the state for all outputs in the
2614 * pending_state, as well as disabling any unclaimed outputs.
2615 *
2616 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2617 */
2618static int
2619drm_pending_state_apply(struct drm_pending_state *pending_state)
2620{
2621 struct drm_backend *b = pending_state->backend;
2622 struct drm_output_state *output_state, *tmp;
2623 uint32_t *unused;
2624
Daniel Stone598ee9d2016-11-16 11:55:20 +00002625#ifdef HAVE_DRM_ATOMIC
2626 if (b->atomic_modeset)
2627 return drm_pending_state_apply_atomic(pending_state,
2628 DRM_STATE_APPLY_ASYNC);
2629#endif
2630
Daniel Stonea08512f2016-11-08 17:46:10 +00002631 if (b->state_invalid) {
2632 /* If we need to reset all our state (e.g. because we've
2633 * just started, or just been VT-switched in), explicitly
2634 * disable all the CRTCs we aren't using. This also disables
2635 * all connectors on these CRTCs, so we don't need to do that
2636 * separately with the pre-atomic API. */
2637 wl_array_for_each(unused, &b->unused_crtcs)
2638 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2639 NULL);
2640 }
2641
2642 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2643 link) {
2644 struct drm_output *output = output_state->output;
2645 int ret;
2646
Daniel Stone598ee9d2016-11-16 11:55:20 +00002647 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002648 if (ret != 0) {
2649 weston_log("Couldn't apply state for output %s\n",
2650 output->base.name);
2651 }
2652 }
2653
2654 b->state_invalid = false;
2655
2656 assert(wl_list_empty(&pending_state->output_list));
2657
2658 drm_pending_state_free(pending_state);
2659
2660 return 0;
2661}
2662
2663/**
2664 * The synchronous version of drm_pending_state_apply. May only be used to
2665 * disable outputs. Does so synchronously: the request is guaranteed to have
2666 * completed on return, and the output will not be touched afterwards.
2667 *
2668 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2669 */
2670static int
2671drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
2672{
2673 struct drm_backend *b = pending_state->backend;
2674 struct drm_output_state *output_state, *tmp;
2675 uint32_t *unused;
2676
Daniel Stone598ee9d2016-11-16 11:55:20 +00002677#ifdef HAVE_DRM_ATOMIC
2678 if (b->atomic_modeset)
2679 return drm_pending_state_apply_atomic(pending_state,
2680 DRM_STATE_APPLY_SYNC);
2681#endif
2682
Daniel Stonea08512f2016-11-08 17:46:10 +00002683 if (b->state_invalid) {
2684 /* If we need to reset all our state (e.g. because we've
2685 * just started, or just been VT-switched in), explicitly
2686 * disable all the CRTCs we aren't using. This also disables
2687 * all connectors on these CRTCs, so we don't need to do that
2688 * separately with the pre-atomic API. */
2689 wl_array_for_each(unused, &b->unused_crtcs)
2690 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2691 NULL);
2692 }
2693
2694 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2695 link) {
2696 int ret;
2697
2698 assert(output_state->dpms == WESTON_DPMS_OFF);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002699 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002700 if (ret != 0) {
2701 weston_log("Couldn't apply state for output %s\n",
2702 output_state->output->base.name);
2703 }
2704 }
2705
2706 b->state_invalid = false;
2707
2708 assert(wl_list_empty(&pending_state->output_list));
2709
2710 drm_pending_state_free(pending_state);
2711
2712 return 0;
2713}
2714
2715static int
2716drm_output_repaint(struct weston_output *output_base,
2717 pixman_region32_t *damage,
2718 void *repaint_data)
2719{
2720 struct drm_pending_state *pending_state = repaint_data;
2721 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00002722 struct drm_output_state *state = NULL;
2723 struct drm_plane_state *scanout_state;
2724
2725 if (output->disable_pending || output->destroy_pending)
2726 goto err;
2727
2728 assert(!output->state_last);
2729
2730 /* If planes have been disabled in the core, we might not have
2731 * hit assign_planes at all, so might not have valid output state
2732 * here. */
2733 state = drm_pending_state_get_output(pending_state, output);
2734 if (!state)
2735 state = drm_output_state_duplicate(output->state_cur,
2736 pending_state,
2737 DRM_OUTPUT_STATE_CLEAR_PLANES);
2738 state->dpms = WESTON_DPMS_ON;
2739
2740 drm_output_render(state, damage);
2741 scanout_state = drm_output_state_get_plane(state,
2742 output->scanout_plane);
2743 if (!scanout_state || !scanout_state->fb)
2744 goto err;
2745
Daniel Stonea08512f2016-11-08 17:46:10 +00002746 return 0;
2747
2748err:
2749 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +02002750 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002751}
2752
2753static void
Jonas Ådahle5a12252013-04-05 23:07:11 +02002754drm_output_start_repaint_loop(struct weston_output *output_base)
2755{
Armin Krezović545dba62016-08-05 15:54:18 +02002756 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +00002757 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +00002758 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02002759 struct drm_backend *backend =
2760 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002761 struct timespec ts, tnow;
2762 struct timespec vbl2now;
2763 int64_t refresh_nsec;
2764 int ret;
2765 drmVBlank vbl = {
2766 .request.type = DRM_VBLANK_RELATIVE,
2767 .request.sequence = 0,
2768 .request.signal = 0,
2769 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002770
Armin Krezović08368132016-09-30 14:11:05 +02002771 if (output->disable_pending || output->destroy_pending)
Xiong Zhangabd5d472013-10-11 14:43:07 +08002772 return;
2773
Daniel Stonee2e80132018-01-16 15:37:33 +00002774 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002775 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +02002776 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002777 }
2778
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002779 /* Need to smash all state in from scratch; current timings might not
2780 * be what we want, page flip might not work, etc.
2781 */
Daniel Stone6020f472018-02-05 15:46:20 +00002782 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002783 goto finish_frame;
2784
Daniel Stonee2e80132018-01-16 15:37:33 +00002785 assert(scanout_plane->state_cur->output == output);
2786
Mario Kleinerf507ec32015-06-21 21:25:14 +02002787 /* Try to get current msc and timestamp via instant query */
2788 vbl.request.type |= drm_waitvblank_pipe(output);
2789 ret = drmWaitVBlank(backend->drm.fd, &vbl);
2790
2791 /* Error ret or zero timestamp means failure to get valid timestamp */
2792 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
2793 ts.tv_sec = vbl.reply.tval_sec;
2794 ts.tv_nsec = vbl.reply.tval_usec * 1000;
2795
2796 /* Valid timestamp for most recent vblank - not stale?
2797 * Stale ts could happen on Linux 3.17+, so make sure it
2798 * is not older than 1 refresh duration since now.
2799 */
2800 weston_compositor_read_presentation_clock(backend->compositor,
2801 &tnow);
2802 timespec_sub(&vbl2now, &tnow, &ts);
2803 refresh_nsec =
2804 millihz_to_nsec(output->base.current_mode->refresh);
2805 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
2806 drm_output_update_msc(output, vbl.reply.sequence);
2807 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002808 WP_PRESENTATION_FEEDBACK_INVALID);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002809 return;
2810 }
2811 }
2812
2813 /* Immediate query didn't provide valid timestamp.
2814 * Use pageflip fallback.
2815 */
Jonas Ådahle5a12252013-04-05 23:07:11 +02002816
Daniel Stone205c0a02017-04-04 17:54:33 +01002817 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002818 assert(!output->state_last);
2819
2820 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +00002821 drm_output_state_duplicate(output->state_cur, pending_state,
2822 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +01002823
Daniel Stone8747f952016-11-29 20:17:32 +00002824 ret = drm_pending_state_apply(pending_state);
2825 if (ret != 0) {
2826 weston_log("applying repaint-start state failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +02002827 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +02002828 }
David Herrmann3c688c52013-10-22 17:11:25 +02002829
2830 return;
2831
2832finish_frame:
2833 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +00002834 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002835 WP_PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002836}
2837
2838static void
Pekka Paalanen641307c2014-09-23 22:08:47 -04002839drm_output_update_msc(struct drm_output *output, unsigned int seq)
2840{
2841 uint64_t msc_hi = output->base.msc >> 32;
2842
2843 if (seq < (output->base.msc & 0xffffffff))
2844 msc_hi++;
2845
2846 output->base.msc = (msc_hi << 32) + seq;
2847}
2848
2849static void
Jesse Barnes58ef3792012-02-23 09:45:49 -05002850vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
2851 void *data)
2852{
Daniel Stonebc15f682016-11-14 16:57:01 +00002853 struct drm_plane_state *ps = (struct drm_plane_state *) data;
2854 struct drm_output_state *os = ps->output_state;
2855 struct drm_output *output = os->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002856 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002857 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2858 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002859
Daniel Stone598ee9d2016-11-16 11:55:20 +00002860 assert(!b->atomic_modeset);
2861
Pekka Paalanen641307c2014-09-23 22:08:47 -04002862 drm_output_update_msc(output, frame);
Daniel Stone65d87d02017-04-04 17:54:32 +01002863 output->vblank_pending--;
2864 assert(output->vblank_pending >= 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002865
Daniel Stonebc15f682016-11-14 16:57:01 +00002866 assert(ps->fb);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002867
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002868 if (output->page_flip_pending || output->vblank_pending)
2869 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002870
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002871 drm_output_update_complete(output, flags, sec, usec);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002872}
2873
2874static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002875page_flip_handler(int fd, unsigned int frame,
2876 unsigned int sec, unsigned int usec, void *data)
2877{
Armin Krezović545dba62016-08-05 15:54:18 +02002878 struct drm_output *output = data;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002879 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002880 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2881 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2882 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002883
Pekka Paalanen641307c2014-09-23 22:08:47 -04002884 drm_output_update_msc(output, frame);
2885
Daniel Stone598ee9d2016-11-16 11:55:20 +00002886 assert(!b->atomic_modeset);
Daniel Stone205c0a02017-04-04 17:54:33 +01002887 assert(output->page_flip_pending);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002888 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002889
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002890 if (output->vblank_pending)
2891 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002892
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002893 drm_output_update_complete(output, flags, sec, usec);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02002894}
2895
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002896/**
2897 * Begin a new repaint cycle
2898 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002899 * Called by the core compositor at the beginning of a repaint cycle. Creates
2900 * a new pending_state structure to own any output state created by individual
2901 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002902 */
2903static void *
2904drm_repaint_begin(struct weston_compositor *compositor)
2905{
2906 struct drm_backend *b = to_drm_backend(compositor);
2907 struct drm_pending_state *ret;
2908
2909 ret = drm_pending_state_alloc(b);
2910 b->repaint_data = ret;
2911
2912 return ret;
2913}
2914
2915/**
2916 * Flush a repaint set
2917 *
2918 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002919 * and should be flushed. Frees the pending state, transitioning ownership
2920 * of the output state from the pending state, to the update itself. When
2921 * the update completes (see drm_output_update_complete), the output
2922 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002923 */
2924static void
2925drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
2926{
2927 struct drm_backend *b = to_drm_backend(compositor);
2928 struct drm_pending_state *pending_state = repaint_data;
Daniel Stone6020f472018-02-05 15:46:20 +00002929
Daniel Stonea08512f2016-11-08 17:46:10 +00002930 drm_pending_state_apply(pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002931 b->repaint_data = NULL;
2932}
2933
2934/**
2935 * Cancel a repaint set
2936 *
2937 * Called by the core compositor when a repaint has finished, so the data
2938 * held across the repaint cycle should be discarded.
2939 */
2940static void
2941drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
2942{
2943 struct drm_backend *b = to_drm_backend(compositor);
2944 struct drm_pending_state *pending_state = repaint_data;
2945
2946 drm_pending_state_free(pending_state);
2947 b->repaint_data = NULL;
2948}
2949
Daniel Stone598ee9d2016-11-16 11:55:20 +00002950#ifdef HAVE_DRM_ATOMIC
2951static void
2952atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
2953 unsigned int usec, unsigned int crtc_id, void *data)
2954{
2955 struct drm_backend *b = data;
2956 struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
2957 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2958 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2959 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
2960
2961 /* During the initial modeset, we can disable CRTCs which we don't
2962 * actually handle during normal operation; this will give us events
2963 * for unknown outputs. Ignore them. */
2964 if (!output || !output->base.enabled)
2965 return;
2966
2967 drm_output_update_msc(output, frame);
2968
2969 assert(b->atomic_modeset);
2970 assert(output->atomic_complete_pending);
2971 output->atomic_complete_pending = 0;
2972
2973 drm_output_update_complete(output, flags, sec, usec);
2974}
2975#endif
2976
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002977static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002978drm_output_prepare_overlay_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002979 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002980{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002981 struct drm_output *output = output_state->output;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002982 struct weston_compositor *ec = output->base.compositor;
Daniel Stoned6e2a762016-11-16 19:33:20 +00002983 struct drm_backend *b = to_drm_backend(ec);
Daniel Stone08d4edf2017-04-04 17:54:34 +01002984 struct drm_plane *p;
Daniel Stonebc15f682016-11-14 16:57:01 +00002985 struct drm_plane_state *state = NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00002986 struct drm_fb *fb;
Daniel Stonedb10df12016-12-08 13:15:58 +00002987 unsigned int i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002988
Giulio Camuffo954f1832014-10-11 18:27:30 +03002989 if (b->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002990 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -05002991
Daniel Stonef11ec022016-11-17 17:32:42 +00002992 fb = drm_fb_get_from_view(output_state, ev);
2993 if (!fb)
Daniel Stone296d7a92016-10-21 18:05:37 +01002994 return NULL;
2995
Daniel Stone085d2b92015-05-21 00:00:57 +01002996 wl_list_for_each(p, &b->plane_list, link) {
2997 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2998 continue;
2999
Daniel Stone5ff289a2017-10-07 12:59:02 +01003000 if (!drm_plane_is_available(p, output))
Daniel Stonebc15f682016-11-14 16:57:01 +00003001 continue;
3002
Daniel Stonef11ec022016-11-17 17:32:42 +00003003 /* Check whether the format is supported */
3004 for (i = 0; i < p->count_formats; i++) {
3005 if (p->formats[i] == fb->format->format)
3006 break;
3007 }
3008 if (i == p->count_formats)
3009 continue;
3010
Daniel Stonebc15f682016-11-14 16:57:01 +00003011 state = drm_output_state_get_plane(output_state, p);
3012 if (state->fb) {
3013 state = NULL;
3014 continue;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003015 }
Daniel Stonebc15f682016-11-14 16:57:01 +00003016
3017 break;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003018 }
3019
3020 /* No sprites available */
Daniel Stonef11ec022016-11-17 17:32:42 +00003021 if (!state) {
3022 drm_fb_unref(fb);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003023 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00003024 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05003025
Daniel Stonef11ec022016-11-17 17:32:42 +00003026 state->fb = fb;
Daniel Stonece137472016-11-16 19:35:03 +00003027 state->output = output;
Daniel Stonef11ec022016-11-17 17:32:42 +00003028
Daniel Stonece137472016-11-16 19:35:03 +00003029 if (!drm_plane_state_coords_for_view(state, ev))
3030 goto err;
3031
3032 if (state->src_w != state->dest_w << 16 ||
3033 state->src_h != state->dest_h << 16)
3034 goto err;
3035
Daniel Stone08d4edf2017-04-04 17:54:34 +01003036 return &p->base;
Daniel Stonebc15f682016-11-14 16:57:01 +00003037
3038err:
Daniel Stonedb10df12016-12-08 13:15:58 +00003039 drm_plane_state_put_back(state);
Daniel Stonebc15f682016-11-14 16:57:01 +00003040 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003041}
3042
Pekka Paalanend0ead482014-06-16 12:05:40 +03003043/**
3044 * Update the image for the current cursor surface
3045 *
Daniel Stone9b560382016-11-16 19:46:35 +00003046 * @param plane_state DRM cursor plane state
3047 * @param ev Source view for cursor
Pekka Paalanend0ead482014-06-16 12:05:40 +03003048 */
3049static void
Daniel Stone9b560382016-11-16 19:46:35 +00003050cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
Pekka Paalanend0ead482014-06-16 12:05:40 +03003051{
Daniel Stone9b560382016-11-16 19:46:35 +00003052 struct drm_backend *b = plane_state->plane->backend;
3053 struct gbm_bo *bo = plane_state->fb->bo;
Pekka Paalanend0ead482014-06-16 12:05:40 +03003054 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
3055 uint32_t buf[b->cursor_width * b->cursor_height];
3056 int32_t stride;
3057 uint8_t *s;
3058 int i;
3059
3060 assert(buffer && buffer->shm_buffer);
3061 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
Daniel Stone9b560382016-11-16 19:46:35 +00003062 assert(buffer->width <= b->cursor_width);
3063 assert(buffer->height <= b->cursor_height);
Pekka Paalanend0ead482014-06-16 12:05:40 +03003064
3065 memset(buf, 0, sizeof buf);
3066 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
3067 s = wl_shm_buffer_get_data(buffer->shm_buffer);
3068
3069 wl_shm_buffer_begin_access(buffer->shm_buffer);
Daniel Stone9b560382016-11-16 19:46:35 +00003070 for (i = 0; i < buffer->height; i++)
Pekka Paalanend0ead482014-06-16 12:05:40 +03003071 memcpy(buf + i * b->cursor_width,
3072 s + i * stride,
Daniel Stone9b560382016-11-16 19:46:35 +00003073 buffer->width * 4);
Pekka Paalanend0ead482014-06-16 12:05:40 +03003074 wl_shm_buffer_end_access(buffer->shm_buffer);
3075
3076 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
3077 weston_log("failed update cursor: %m\n");
3078}
3079
Daniel Stone2ba17f42015-05-19 20:02:41 +01003080static struct weston_plane *
3081drm_output_prepare_cursor_view(struct drm_output_state *output_state,
3082 struct weston_view *ev)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04003083{
Daniel Stone2ba17f42015-05-19 20:02:41 +01003084 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02003085 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stone2ba17f42015-05-19 20:02:41 +01003086 struct drm_plane *plane = output->cursor_plane;
3087 struct drm_plane_state *plane_state;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003088 struct wl_shm_buffer *shmbuf;
3089 bool needs_update = false;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003090
Daniel Stone2ba17f42015-05-19 20:02:41 +01003091 if (!plane)
3092 return NULL;
3093
3094 if (b->cursors_are_broken)
3095 return NULL;
3096
3097 if (!plane->state_cur->complete)
3098 return NULL;
3099
3100 if (plane->state_cur->output && plane->state_cur->output != output)
3101 return NULL;
3102
3103 /* Don't import buffers which span multiple outputs. */
3104 if (ev->output_mask != (1u << output->base.id))
3105 return NULL;
3106
3107 /* We use GBM to import SHM buffers. */
3108 if (b->gbm == NULL)
3109 return NULL;
3110
3111 if (ev->surface->buffer_ref.buffer == NULL)
3112 return NULL;
3113 shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
3114 if (!shmbuf)
3115 return NULL;
3116 if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)
3117 return NULL;
3118
Daniel Stone2ba17f42015-05-19 20:02:41 +01003119 plane_state =
3120 drm_output_state_get_plane(output_state, output->cursor_plane);
3121
3122 if (plane_state && plane_state->fb)
3123 return NULL;
3124
Daniel Stone9b560382016-11-16 19:46:35 +00003125 /* We can't scale with the legacy API, and we don't try to account for
3126 * simple cropping/translation in cursor_bo_update. */
3127 plane_state->output = output;
3128 if (!drm_plane_state_coords_for_view(plane_state, ev))
3129 goto err;
3130
3131 if (plane_state->src_x != 0 || plane_state->src_y != 0 ||
3132 plane_state->src_w > (unsigned) b->cursor_width << 16 ||
3133 plane_state->src_h > (unsigned) b->cursor_height << 16 ||
3134 plane_state->src_w != plane_state->dest_w << 16 ||
3135 plane_state->src_h != plane_state->dest_h << 16)
3136 goto err;
3137
Daniel Stone2ba17f42015-05-19 20:02:41 +01003138 /* Since we're setting plane state up front, we need to work out
3139 * whether or not we need to upload a new cursor. We can't use the
3140 * plane damage, since the planes haven't actually been calculated
3141 * yet: instead try to figure it out directly. KMS cursor planes are
3142 * pretty unique here, in that they lie partway between a Weston plane
3143 * (direct scanout) and a renderer. */
3144 if (ev != output->cursor_view ||
3145 pixman_region32_not_empty(&ev->surface->damage)) {
3146 output->current_cursor++;
3147 output->current_cursor =
3148 output->current_cursor %
3149 ARRAY_LENGTH(output->gbm_cursor_fb);
3150 needs_update = true;
3151 }
3152
3153 output->cursor_view = ev;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003154
3155 plane_state->fb =
3156 drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
Daniel Stone9b560382016-11-16 19:46:35 +00003157
3158 if (needs_update)
3159 cursor_bo_update(plane_state, ev);
3160
3161 /* The cursor API is somewhat special: in cursor_bo_update(), we upload
3162 * a buffer which is always cursor_width x cursor_height, even if the
3163 * surface we want to promote is actually smaller than this. Manually
3164 * mangle the plane state to deal with this. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01003165 plane_state->src_w = b->cursor_width << 16;
3166 plane_state->src_h = b->cursor_height << 16;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003167 plane_state->dest_w = b->cursor_width;
3168 plane_state->dest_h = b->cursor_height;
3169
Daniel Stone2ba17f42015-05-19 20:02:41 +01003170 return &plane->base;
Daniel Stone9b560382016-11-16 19:46:35 +00003171
3172err:
3173 drm_plane_state_put_back(plane_state);
3174 return NULL;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003175}
3176
3177static void
3178drm_output_set_cursor(struct drm_output_state *output_state)
3179{
3180 struct drm_output *output = output_state->output;
3181 struct drm_backend *b = to_drm_backend(output->base.compositor);
3182 struct drm_plane *plane = output->cursor_plane;
3183 struct drm_plane_state *state;
3184 EGLint handle;
3185 struct gbm_bo *bo;
3186
3187 if (!plane)
3188 return;
3189
3190 state = drm_output_state_get_existing_plane(output_state, plane);
3191 if (!state)
3192 return;
3193
3194 if (!state->fb) {
3195 pixman_region32_fini(&plane->base.damage);
3196 pixman_region32_init(&plane->base.damage);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003197 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04003198 return;
3199 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003200
Daniel Stone2ba17f42015-05-19 20:02:41 +01003201 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
3202 assert(!plane->state_cur->output || plane->state_cur->output == output);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003203
Daniel Stone2ba17f42015-05-19 20:02:41 +01003204 if (plane->state_cur->fb != state->fb) {
3205 bo = state->fb->bo;
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04003206 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03003207 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
Daniel Stone2ba17f42015-05-19 20:02:41 +01003208 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03003209 weston_log("failed to set cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01003210 goto err;
Rob Clarkab5b1e32012-08-09 13:24:45 -05003211 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003212 }
3213
Daniel Stone2ba17f42015-05-19 20:02:41 +01003214 pixman_region32_fini(&plane->base.damage);
3215 pixman_region32_init(&plane->base.damage);
Pekka Paalanen7eaed402015-11-27 14:20:58 +02003216
Daniel Stone2ba17f42015-05-19 20:02:41 +01003217 if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
3218 state->dest_x, state->dest_y)) {
Daniel Stonea7cba1d2017-04-04 17:54:21 +01003219 weston_log("failed to move cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01003220 goto err;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003221 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003222
3223 return;
3224
3225err:
3226 b->cursors_are_broken = 1;
3227 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003228}
3229
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303230/*
3231 * Get the aspect-ratio from drmModeModeInfo mode flags.
3232 *
3233 * @param drm_mode_flags- flags from drmModeModeInfo structure.
3234 * @returns aspect-ratio as encoded in enum 'weston_mode_aspect_ratio'.
3235 */
3236static enum weston_mode_aspect_ratio
3237drm_to_weston_mode_aspect_ratio(uint32_t drm_mode_flags)
3238{
3239 return (drm_mode_flags & DRM_MODE_FLAG_PIC_AR_MASK) >>
3240 DRM_MODE_FLAG_PIC_AR_BITS_POS;
3241}
3242
3243static const char *
3244aspect_ratio_to_string(enum weston_mode_aspect_ratio ratio)
3245{
3246 if (ratio < 0 || ratio >= ARRAY_LENGTH(aspect_ratio_as_string) ||
3247 !aspect_ratio_as_string[ratio])
3248 return " (unknown aspect ratio)";
3249
3250 return aspect_ratio_as_string[ratio];
3251}
3252
Jesse Barnes58ef3792012-02-23 09:45:49 -05003253static void
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003254drm_assign_planes(struct weston_output *output_base, void *repaint_data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05003255{
Armin Krezović545dba62016-08-05 15:54:18 +02003256 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003257 struct drm_pending_state *pending_state = repaint_data;
Armin Krezović545dba62016-08-05 15:54:18 +02003258 struct drm_output *output = to_drm_output(output_base);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003259 struct drm_output_state *state;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003260 struct drm_plane_state *plane_state;
Daniel Stonec3fcb5b2016-12-01 12:33:54 +00003261 struct weston_view *ev;
Daniel Stone115ed2c2016-11-08 21:19:22 +00003262 pixman_region32_t surface_overlap, renderer_region;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003263 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003264
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003265 assert(!output->state_last);
3266 state = drm_output_state_duplicate(output->state_cur,
3267 pending_state,
3268 DRM_OUTPUT_STATE_CLEAR_PLANES);
3269
Jesse Barnes58ef3792012-02-23 09:45:49 -05003270 /*
3271 * Find a surface for each sprite in the output using some heuristics:
3272 * 1) size
3273 * 2) frequency of update
3274 * 3) opacity (though some hw might support alpha blending)
3275 * 4) clipping (this can be fixed with color keys)
3276 *
3277 * The idea is to save on blitting since this should save power.
3278 * If we can get a large video surface on the sprite for example,
3279 * the main display surface may not need to update at all, and
3280 * the client buffer can be used directly for the sprite surface
3281 * as we do for flipping full screen surfaces.
3282 */
Daniel Stone115ed2c2016-11-08 21:19:22 +00003283 pixman_region32_init(&renderer_region);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003284 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003285
Daniel Stonec3fcb5b2016-12-01 12:33:54 +00003286 wl_list_for_each(ev, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02003287 struct weston_surface *es = ev->surface;
3288
3289 /* Test whether this buffer can ever go into a plane:
3290 * non-shm, or small enough to be a cursor.
3291 *
3292 * Also, keep a reference when using the pixman renderer.
3293 * That makes it possible to do a seamless switch to the GL
3294 * renderer and since the pixman renderer keeps a reference
3295 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02003296 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003297 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02003298 (es->buffer_ref.buffer &&
3299 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Derek Foreman87430472015-10-15 10:24:48 -05003300 (ev->surface->width <= b->cursor_width &&
3301 ev->surface->height <= b->cursor_height))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05003302 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02003303 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05003304 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02003305
Jesse Barnes58ef3792012-02-23 09:45:49 -05003306 pixman_region32_init(&surface_overlap);
Daniel Stone115ed2c2016-11-08 21:19:22 +00003307 pixman_region32_intersect(&surface_overlap, &renderer_region,
Jason Ekstranda7af7042013-10-12 22:38:11 -05003308 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003309
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003310 next_plane = NULL;
Daniel Stonef9bd5462018-05-15 17:09:53 +01003311 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003312 next_plane = primary;
3313 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003314 next_plane = drm_output_prepare_cursor_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05003315
Daniel Stonef9bd5462018-05-15 17:09:53 +01003316 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003317 next_plane = drm_output_prepare_scanout_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05003318
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003319 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003320 next_plane = drm_output_prepare_overlay_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05003321
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003322 if (next_plane == NULL)
3323 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003324
Jason Ekstranda7af7042013-10-12 22:38:11 -05003325 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003326
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003327 if (next_plane == primary)
Daniel Stone115ed2c2016-11-08 21:19:22 +00003328 pixman_region32_union(&renderer_region,
3329 &renderer_region,
Jason Ekstranda7af7042013-10-12 22:38:11 -05003330 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04003331
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003332 if (next_plane == primary ||
Daniel Stone2ba17f42015-05-19 20:02:41 +01003333 (output->cursor_plane &&
3334 next_plane == &output->cursor_plane->base)) {
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003335 /* cursor plane involves a copy */
3336 ev->psf_flags = 0;
3337 } else {
3338 /* All other planes are a direct scanout of a
3339 * single client buffer.
3340 */
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02003341 ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003342 }
3343
Jesse Barnes58ef3792012-02-23 09:45:49 -05003344 pixman_region32_fini(&surface_overlap);
3345 }
Daniel Stone115ed2c2016-11-08 21:19:22 +00003346 pixman_region32_fini(&renderer_region);
Daniel Stone2ba17f42015-05-19 20:02:41 +01003347
3348 /* We rely on output->cursor_view being both an accurate reflection of
3349 * the cursor plane's state, but also being maintained across repaints
3350 * to avoid unnecessary damage uploads, per the comment in
3351 * drm_output_prepare_cursor_view. In the event that we go from having
3352 * a cursor view to not having a cursor view, we need to clear it. */
3353 if (output->cursor_view) {
3354 plane_state =
3355 drm_output_state_get_existing_plane(state,
3356 output->cursor_plane);
3357 if (!plane_state || !plane_state->fb)
3358 output->cursor_view = NULL;
3359 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05003360}
3361
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003362/**
3363 * Find the closest-matching mode for a given target
3364 *
3365 * Given a target mode, find the most suitable mode amongst the output's
3366 * current mode list to use, preferring the current mode if possible, to
3367 * avoid an expensive mode switch.
3368 *
3369 * @param output DRM output
3370 * @param target_mode Mode to attempt to match
3371 * @returns Pointer to a mode from the output's mode list
3372 */
Alex Wub7b8bda2012-04-17 17:20:48 +08003373static struct drm_mode *
3374choose_mode (struct drm_output *output, struct weston_mode *target_mode)
3375{
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303376 struct drm_mode *tmp_mode = NULL, *mode_fall_back = NULL, *mode;
3377 enum weston_mode_aspect_ratio src_aspect = WESTON_MODE_PIC_AR_NONE;
3378 enum weston_mode_aspect_ratio target_aspect = WESTON_MODE_PIC_AR_NONE;
3379 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08003380
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303381 b = to_drm_backend(output->base.compositor);
3382 target_aspect = target_mode->aspect_ratio;
3383 src_aspect = output->base.current_mode->aspect_ratio;
Hardeningff39efa2013-09-18 23:56:35 +02003384 if (output->base.current_mode->width == target_mode->width &&
3385 output->base.current_mode->height == target_mode->height &&
3386 (output->base.current_mode->refresh == target_mode->refresh ||
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303387 target_mode->refresh == 0)) {
3388 if (!b->aspect_ratio_supported || src_aspect == target_aspect)
3389 return to_drm_mode(output->base.current_mode);
3390 }
Alex Wub7b8bda2012-04-17 17:20:48 +08003391
3392 wl_list_for_each(mode, &output->base.mode_list, base.link) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303393
3394 src_aspect = mode->base.aspect_ratio;
Alex Wub7b8bda2012-04-17 17:20:48 +08003395 if (mode->mode_info.hdisplay == target_mode->width &&
3396 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02003397 if (mode->base.refresh == target_mode->refresh ||
3398 target_mode->refresh == 0) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303399 if (!b->aspect_ratio_supported ||
3400 src_aspect == target_aspect)
3401 return mode;
3402 else if (!mode_fall_back)
3403 mode_fall_back = mode;
3404 } else if (!tmp_mode) {
Alex Wub7b8bda2012-04-17 17:20:48 +08003405 tmp_mode = mode;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303406 }
Alex Wub7b8bda2012-04-17 17:20:48 +08003407 }
3408 }
3409
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303410 if (mode_fall_back)
3411 return mode_fall_back;
3412
Alex Wub7b8bda2012-04-17 17:20:48 +08003413 return tmp_mode;
3414}
3415
3416static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003417drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003418static void
3419drm_output_fini_egl(struct drm_output *output);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003420static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003421drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003422static void
3423drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003424
3425static int
Alex Wub7b8bda2012-04-17 17:20:48 +08003426drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
3427{
Daniel Stone02d487a2017-10-07 14:01:45 +01003428 struct drm_output *output = to_drm_output(output_base);
3429 struct drm_backend *b = to_drm_backend(output_base->compositor);
3430 struct drm_mode *drm_mode = choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +08003431
3432 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +01003433 weston_log("%s: invalid resolution %dx%d\n",
3434 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08003435 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003436 }
3437
Hardeningff39efa2013-09-18 23:56:35 +02003438 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08003439 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003440
Hardeningff39efa2013-09-18 23:56:35 +02003441 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003442
Hardeningff39efa2013-09-18 23:56:35 +02003443 output->base.current_mode = &drm_mode->base;
3444 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08003445 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
3446
Daniel Stonef30a18c2017-04-04 17:54:31 +01003447 /* XXX: This drops our current buffer too early, before we've started
3448 * displaying it. Ideally this should be much more atomic and
3449 * integrated with a full repaint cycle, rather than doing a
3450 * sledgehammer modeswitch first, and only later showing new
3451 * content.
3452 */
Daniel Stone6020f472018-02-05 15:46:20 +00003453 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +08003454
Giulio Camuffo954f1832014-10-11 18:27:30 +03003455 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003456 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003457 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003458 weston_log("failed to init output pixman state with "
3459 "new mode\n");
3460 return -1;
3461 }
3462 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +00003463 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003464 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003465 weston_log("failed to init output egl state with "
3466 "new mode");
3467 return -1;
3468 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003469 }
3470
Alex Wub7b8bda2012-04-17 17:20:48 +08003471 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003472}
3473
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003474static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003475on_drm_input(int fd, uint32_t mask, void *data)
3476{
Daniel Stone598ee9d2016-11-16 11:55:20 +00003477#ifdef HAVE_DRM_ATOMIC
3478 struct drm_backend *b = data;
3479#endif
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003480 drmEventContext evctx;
3481
3482 memset(&evctx, 0, sizeof evctx);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003483#ifndef HAVE_DRM_ATOMIC
Emil Velikov863e66b2017-04-04 18:07:34 +01003484 evctx.version = 2;
Daniel Stone598ee9d2016-11-16 11:55:20 +00003485#else
3486 evctx.version = 3;
3487 if (b->atomic_modeset)
3488 evctx.page_flip_handler2 = atomic_flip_handler;
3489 else
3490#endif
3491 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003492 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003493 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003494
3495 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003496}
3497
3498static int
Daniel Stoneefa504f2016-12-19 16:48:20 +00003499init_kms_caps(struct drm_backend *b)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003500{
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003501 uint64_t cap;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003502 int ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003503 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003504
Daniel Stoneefa504f2016-12-19 16:48:20 +00003505 weston_log("using %s\n", b->drm.filename);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003506
Daniel Stoneefa504f2016-12-19 16:48:20 +00003507 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003508 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003509 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003510 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003511 clk_id = CLOCK_REALTIME;
3512
Giulio Camuffo954f1832014-10-11 18:27:30 +03003513 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003514 weston_log("Error: failed to set presentation clock %d.\n",
3515 clk_id);
3516 return -1;
3517 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02003518
Daniel Stoneefa504f2016-12-19 16:48:20 +00003519 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003520 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003521 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003522 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003523 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003524
Daniel Stoneefa504f2016-12-19 16:48:20 +00003525 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003526 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003527 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003528 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003529 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003530
Daniel Stonebe1090b2017-09-06 17:29:57 +01003531 if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
3532 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
3533 b->universal_planes = (ret == 0);
3534 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003535 weston_log("DRM: %s universal planes\n",
3536 b->universal_planes ? "supports" : "does not support");
3537
Pekka Paalanencd011a62016-11-15 22:07:49 +00003538#ifdef HAVE_DRM_ATOMIC
3539 if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00003540 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
3541 if (ret != 0)
3542 cap = 0;
Pekka Paalanencd011a62016-11-15 22:07:49 +00003543 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003544 b->atomic_modeset = ((ret == 0) && (cap == 1));
Pekka Paalanencd011a62016-11-15 22:07:49 +00003545 }
3546#endif
3547 weston_log("DRM: %s atomic modesetting\n",
3548 b->atomic_modeset ? "supports" : "does not support");
3549
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303550 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
3551 b->aspect_ratio_supported = (ret == 0);
3552 weston_log("DRM: %s picture aspect ratio\n",
3553 b->aspect_ratio_supported ? "supports" : "does not support");
3554
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003555 return 0;
3556}
3557
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003558static struct gbm_device *
3559create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003560{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003561 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01003562
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003563 gl_renderer = weston_load_module("gl-renderer.so",
3564 "gl_renderer_interface");
3565 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003566 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003567
3568 /* GBM will load a dri driver, but even though they need symbols from
3569 * libglapi, in some version of Mesa they are not linked to it. Since
3570 * only the gl-renderer module links to it, the call above won't make
3571 * these symbols globally available, and loading the DRI driver fails.
3572 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
3573 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
3574
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003575 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003576
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003577 return gbm;
3578}
3579
Bryce Harringtonc056a982015-05-19 15:25:18 -07003580/* When initializing EGL, if the preferred buffer format isn't available
Bryce Harringtonb9939982016-04-15 20:28:26 -07003581 * we may be able to substitute an ARGB format for an XRGB one.
Derek Foremanc4cfe852015-05-15 12:12:40 -05003582 *
3583 * This returns 0 if substitution isn't possible, but 0 might be a
3584 * legitimate format for other EGL platforms, so the caller is
3585 * responsible for checking for 0 before calling gl_renderer->create().
3586 *
3587 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
3588 * but it's entirely possible we'll see this again on other implementations.
3589 */
3590static int
3591fallback_format_for(uint32_t format)
3592{
3593 switch (format) {
3594 case GBM_FORMAT_XRGB8888:
3595 return GBM_FORMAT_ARGB8888;
3596 case GBM_FORMAT_XRGB2101010:
3597 return GBM_FORMAT_ARGB2101010;
3598 default:
3599 return 0;
3600 }
3601}
3602
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003603static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003604drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003605{
Derek Foreman6d556372015-11-04 14:47:33 -06003606 EGLint format[3] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01003607 b->gbm_format,
3608 fallback_format_for(b->gbm_format),
Derek Foreman6d556372015-11-04 14:47:33 -06003609 0,
Derek Foremanc4cfe852015-05-15 12:12:40 -05003610 };
Derek Foreman6d556372015-11-04 14:47:33 -06003611 int n_formats = 2;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01003612
Derek Foremanc4cfe852015-05-15 12:12:40 -05003613 if (format[1])
Derek Foreman6d556372015-11-04 14:47:33 -06003614 n_formats = 3;
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003615 if (gl_renderer->display_create(b->compositor,
3616 EGL_PLATFORM_GBM_KHR,
3617 (void *)b->gbm,
Miguel A. Vico41700e32016-05-18 17:47:59 +02003618 NULL,
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003619 gl_renderer->opaque_attribs,
3620 format,
3621 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003622 return -1;
3623 }
3624
3625 return 0;
3626}
3627
3628static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003629init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003630{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003631 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003632
Giulio Camuffo954f1832014-10-11 18:27:30 +03003633 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003634 return -1;
3635
Giulio Camuffo954f1832014-10-11 18:27:30 +03003636 if (drm_backend_create_gl_renderer(b) < 0) {
3637 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003638 return -1;
3639 }
3640
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003641 return 0;
3642}
3643
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003644static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003645init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003646{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003647 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003648}
3649
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003650/**
Pekka Paalanenec272712014-06-05 11:22:25 +03003651 * Create a drm_plane for a hardware plane
3652 *
3653 * Creates one drm_plane structure for a hardware plane, and initialises its
3654 * properties and formats.
3655 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003656 * In the absence of universal plane support, where KMS does not explicitly
3657 * expose the primary and cursor planes to userspace, this may also create
3658 * an 'internal' plane for internal management.
3659 *
Pekka Paalanenec272712014-06-05 11:22:25 +03003660 * This function does not add the plane to the list of usable planes in Weston
3661 * itself; the caller is responsible for this.
3662 *
3663 * Call drm_plane_destroy to clean up the plane.
3664 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003665 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +03003666 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +01003667 * @param kplane DRM plane to create, or NULL if creating internal plane
3668 * @param output Output to create internal plane for, or NULL
3669 * @param type Type to use when creating internal plane, or invalid
3670 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +03003671 */
3672static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003673drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
3674 struct drm_output *output, enum wdrm_plane_type type,
3675 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +03003676{
3677 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003678 drmModeObjectProperties *props;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003679 int num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003680
Daniel Stone2ba17f42015-05-19 20:02:41 +01003681 plane = zalloc(sizeof(*plane) +
3682 (sizeof(uint32_t) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +03003683 if (!plane) {
3684 weston_log("%s: out of memory\n", __func__);
3685 return NULL;
3686 }
3687
3688 plane->backend = b;
Daniel Stonebc15f682016-11-14 16:57:01 +00003689 plane->state_cur = drm_plane_state_alloc(NULL, plane);
3690 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +03003691
Daniel Stone2ba17f42015-05-19 20:02:41 +01003692 if (kplane) {
3693 plane->possible_crtcs = kplane->possible_crtcs;
3694 plane->plane_id = kplane->plane_id;
3695 plane->count_formats = kplane->count_formats;
3696 memcpy(plane->formats, kplane->formats,
3697 kplane->count_formats * sizeof(kplane->formats[0]));
3698
3699 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
3700 DRM_MODE_OBJECT_PLANE);
3701 if (!props) {
3702 weston_log("couldn't get plane properties\n");
3703 goto err;
3704 }
3705 drm_property_info_populate(b, plane_props, plane->props,
3706 WDRM_PLANE__COUNT, props);
3707 plane->type =
3708 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
3709 props,
3710 WDRM_PLANE_TYPE__COUNT);
3711 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003712 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003713 else {
3714 plane->possible_crtcs = (1 << output->pipe);
3715 plane->plane_id = 0;
3716 plane->count_formats = 1;
3717 plane->formats[0] = format;
3718 plane->type = type;
3719 }
3720
3721 if (plane->type == WDRM_PLANE_TYPE__COUNT)
3722 goto err_props;
3723
3724 /* With universal planes, everything is a DRM plane; without
3725 * universal planes, the only DRM planes are overlay planes.
3726 * Everything else is a fake plane. */
3727 if (b->universal_planes) {
3728 assert(kplane);
3729 } else {
3730 if (kplane)
3731 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
3732 else
3733 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
3734 output);
3735 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003736
Pekka Paalanenec272712014-06-05 11:22:25 +03003737 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01003738 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +03003739
3740 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003741
3742err_props:
3743 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
3744err:
3745 drm_plane_state_free(plane->state_cur, true);
3746 free(plane);
3747 return NULL;
3748}
3749
3750/**
3751 * Find, or create, a special-purpose plane
3752 *
3753 * Primary and cursor planes are a special case, in that before universal
3754 * planes, they are driven by non-plane API calls. Without universal plane
3755 * support, the only way to configure a primary plane is via drmModeSetCrtc,
3756 * and the only way to configure a cursor plane is drmModeSetCursor2.
3757 *
3758 * Although they may actually be regular planes in the hardware, without
3759 * universal plane support, these planes are not actually exposed to
3760 * userspace in the regular plane list.
3761 *
3762 * However, for ease of internal tracking, we want to manage all planes
3763 * through the same drm_plane structures. Therefore, when we are running
3764 * without universal plane support, we create fake drm_plane structures
3765 * to track these planes.
3766 *
3767 * @param b DRM backend
3768 * @param output Output to use for plane
3769 * @param type Type of plane
3770 */
3771static struct drm_plane *
3772drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
3773 enum wdrm_plane_type type)
3774{
3775 struct drm_plane *plane;
3776
3777 if (!b->universal_planes) {
3778 uint32_t format;
3779
3780 switch (type) {
3781 case WDRM_PLANE_TYPE_CURSOR:
3782 format = GBM_FORMAT_ARGB8888;
3783 break;
Daniel Stonee2e80132018-01-16 15:37:33 +00003784 case WDRM_PLANE_TYPE_PRIMARY:
3785 /* We don't know what formats the primary plane supports
3786 * before universal planes, so we just assume that the
3787 * GBM format works; however, this isn't set until after
3788 * the output is created. */
3789 format = 0;
3790 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003791 default:
3792 assert(!"invalid type in drm_output_find_special_plane");
3793 break;
3794 }
3795
3796 return drm_plane_create(b, NULL, output, type, format);
3797 }
3798
3799 wl_list_for_each(plane, &b->plane_list, link) {
3800 struct drm_output *tmp;
3801 bool found_elsewhere = false;
3802
3803 if (plane->type != type)
3804 continue;
3805 if (!drm_plane_is_available(plane, output))
3806 continue;
3807
3808 /* On some platforms, primary/cursor planes can roam
3809 * between different CRTCs, so make sure we don't claim the
3810 * same plane for two outputs. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01003811 wl_list_for_each(tmp, &b->compositor->output_list,
3812 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +00003813 if (tmp->cursor_plane == plane ||
3814 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +01003815 found_elsewhere = true;
3816 break;
3817 }
3818 }
3819
3820 if (found_elsewhere)
3821 continue;
3822
3823 plane->possible_crtcs = (1 << output->pipe);
3824 return plane;
3825 }
3826
3827 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +03003828}
3829
3830/**
3831 * Destroy one DRM plane
3832 *
3833 * Destroy a DRM plane, removing it from screen and releasing its retained
3834 * buffers in the process. The counterpart to drm_plane_create.
3835 *
3836 * @param plane Plane to deallocate (will be freed)
3837 */
3838static void
3839drm_plane_destroy(struct drm_plane *plane)
3840{
Daniel Stone2ba17f42015-05-19 20:02:41 +01003841 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
3842 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
3843 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +00003844 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003845 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +03003846 weston_plane_release(&plane->base);
3847 wl_list_remove(&plane->link);
3848 free(plane);
3849}
3850
3851/**
3852 * Initialise sprites (overlay planes)
3853 *
3854 * Walk the list of provided DRM planes, and add overlay planes.
3855 *
3856 * Call destroy_sprites to free these planes.
3857 *
3858 * @param b DRM compositor backend
3859 */
3860static void
3861create_sprites(struct drm_backend *b)
3862{
3863 drmModePlaneRes *kplane_res;
3864 drmModePlane *kplane;
3865 struct drm_plane *drm_plane;
3866 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +03003867 kplane_res = drmModeGetPlaneResources(b->drm.fd);
3868 if (!kplane_res) {
3869 weston_log("failed to get plane resources: %s\n",
3870 strerror(errno));
3871 return;
3872 }
3873
3874 for (i = 0; i < kplane_res->count_planes; i++) {
3875 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
3876 if (!kplane)
3877 continue;
3878
Daniel Stone2ba17f42015-05-19 20:02:41 +01003879 drm_plane = drm_plane_create(b, kplane, NULL,
3880 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +03003881 drmModeFreePlane(kplane);
3882 if (!drm_plane)
3883 continue;
3884
Daniel Stone085d2b92015-05-21 00:00:57 +01003885 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
3886 weston_compositor_stack_plane(b->compositor,
3887 &drm_plane->base,
3888 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +03003889 }
3890
3891 drmModeFreePlaneResources(kplane_res);
3892}
3893
3894/**
3895 * Clean up sprites (overlay planes)
3896 *
3897 * The counterpart to create_sprites.
3898 *
3899 * @param b DRM compositor backend
3900 */
3901static void
3902destroy_sprites(struct drm_backend *b)
3903{
3904 struct drm_plane *plane, *next;
3905
Daniel Stone085d2b92015-05-21 00:00:57 +01003906 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03003907 drm_plane_destroy(plane);
3908}
3909
Pekka Paalanendc14fd42017-11-10 15:31:39 +02003910static uint32_t
3911drm_refresh_rate_mHz(const drmModeModeInfo *info)
3912{
3913 uint64_t refresh;
3914
3915 /* Calculate higher precision (mHz) refresh rate */
3916 refresh = (info->clock * 1000000LL / info->htotal +
3917 info->vtotal / 2) / info->vtotal;
3918
3919 if (info->flags & DRM_MODE_FLAG_INTERLACE)
3920 refresh *= 2;
3921 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
3922 refresh /= 2;
3923 if (info->vscan > 1)
3924 refresh /= info->vscan;
3925
3926 return refresh;
3927}
3928
Pekka Paalanenec272712014-06-05 11:22:25 +03003929/**
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003930 * Add a mode to output's mode list
3931 *
3932 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
3933 * output's mode list.
3934 *
3935 * @param output DRM output to add mode to
3936 * @param info DRM mode structure to add
3937 * @returns Newly-allocated Weston/DRM mode structure
3938 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003939static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003940drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003941{
3942 struct drm_mode *mode;
3943
3944 mode = malloc(sizeof *mode);
3945 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003946 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003947
3948 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02003949 mode->base.width = info->hdisplay;
3950 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04003951
Pekka Paalanendc14fd42017-11-10 15:31:39 +02003952 mode->base.refresh = drm_refresh_rate_mHz(info);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003953 mode->mode_info = *info;
Daniel Stoned5526cb2016-11-16 10:54:10 +00003954 mode->blob_id = 0;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003955
3956 if (info->type & DRM_MODE_TYPE_PREFERRED)
3957 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
3958
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303959 mode->base.aspect_ratio = drm_to_weston_mode_aspect_ratio(info->flags);
3960
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003961 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
3962
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003963 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003964}
3965
Daniel Stoned5526cb2016-11-16 10:54:10 +00003966/**
3967 * Destroys a mode, and removes it from the list.
3968 */
3969static void
3970drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
3971{
3972 if (mode->blob_id)
3973 drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
3974 wl_list_remove(&mode->base.link);
3975 free(mode);
3976}
3977
Pekka Paalanen383b3af2017-09-11 14:40:48 +03003978/** Destroy a list of drm_modes
3979 *
3980 * @param backend The backend for releasing mode property blobs.
3981 * @param mode_list The list linked by drm_mode::base.link.
3982 */
3983static void
3984drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
3985{
3986 struct drm_mode *mode, *next;
3987
3988 wl_list_for_each_safe(mode, next, mode_list, base.link)
3989 drm_output_destroy_mode(backend, mode);
3990}
3991
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003992static int
3993drm_subpixel_to_wayland(int drm_value)
3994{
3995 switch (drm_value) {
3996 default:
3997 case DRM_MODE_SUBPIXEL_UNKNOWN:
3998 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
3999 case DRM_MODE_SUBPIXEL_NONE:
4000 return WL_OUTPUT_SUBPIXEL_NONE;
4001 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
4002 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
4003 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
4004 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
4005 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
4006 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
4007 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
4008 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
4009 }
4010}
4011
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004012/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004013static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +03004014drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004015{
4016 long brightness, max_brightness, norm;
4017
Pekka Paalanence724242017-09-04 12:21:24 +03004018 brightness = backlight_get_brightness(head->backlight);
4019 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004020
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004021 /* convert it on a scale of 0 to 255 */
4022 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004023
4024 return (uint32_t) norm;
4025}
4026
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004027/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004028static void
4029drm_set_backlight(struct weston_output *output_base, uint32_t value)
4030{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004031 struct drm_output *output = to_drm_output(output_base);
4032 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004033 long max_brightness, new_brightness;
4034
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04004035 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004036 return;
4037
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004038 wl_list_for_each(head, &output->base.head_list, base.output_link) {
4039 if (!head->backlight)
4040 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004041
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004042 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004043
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004044 /* get denormalized value */
4045 new_brightness = (value * max_brightness) / 255;
4046
4047 backlight_set_brightness(head->backlight, new_brightness);
4048 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004049}
4050
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02004051static void
4052drm_output_init_backlight(struct drm_output *output)
4053{
4054 struct weston_head *base;
4055 struct drm_head *head;
4056
4057 output->base.set_backlight = NULL;
4058
4059 wl_list_for_each(base, &output->base.head_list, output_link) {
4060 head = to_drm_head(base);
4061
4062 if (head->backlight) {
4063 weston_log("Initialized backlight for head '%s', device %s\n",
4064 head->base.name, head->backlight->path);
4065
4066 if (!output->base.set_backlight) {
4067 output->base.set_backlight = drm_set_backlight;
4068 output->base.backlight_current =
4069 drm_get_backlight(head);
4070 }
4071 }
4072 }
4073
4074 if (!output->base.set_backlight) {
4075 weston_log("No backlight control for output '%s'\n",
4076 output->base.name);
4077 }
4078}
4079
Daniel Stonea08512f2016-11-08 17:46:10 +00004080/**
4081 * Power output on or off
4082 *
4083 * The DPMS/power level of an output is used to switch it on or off. This
4084 * is DRM's hook for doing so, which can called either as part of repaint,
4085 * or independently of the repaint loop.
4086 *
4087 * If we are called as part of repaint, we simply set the relevant bit in
4088 * state and return.
4089 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004090static void
4091drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
4092{
Armin Krezović545dba62016-08-05 15:54:18 +02004093 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00004094 struct drm_backend *b = to_drm_backend(output_base->compositor);
4095 struct drm_pending_state *pending_state = b->repaint_data;
4096 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01004097 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004098
Daniel Stonea08512f2016-11-08 17:46:10 +00004099 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004100 return;
4101
Daniel Stonea08512f2016-11-08 17:46:10 +00004102 /* If we're being called during the repaint loop, then this is
4103 * simple: discard any previously-generated state, and create a new
4104 * state where we disable everything. When we come to flush, this
4105 * will be applied.
4106 *
4107 * However, we need to be careful: we can be called whilst another
4108 * output is in its repaint cycle (pending_state exists), but our
4109 * output still has an incomplete state application outstanding.
4110 * In that case, we need to wait until that completes. */
4111 if (pending_state && !output->state_last) {
4112 /* The repaint loop already sets DPMS on; we don't need to
4113 * explicitly set it on here, as it will already happen
4114 * whilst applying the repaint state. */
4115 if (level == WESTON_DPMS_ON)
4116 return;
4117
4118 state = drm_pending_state_get_output(pending_state, output);
4119 if (state)
4120 drm_output_state_free(state);
4121 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01004122 return;
4123 }
4124
Daniel Stonea08512f2016-11-08 17:46:10 +00004125 /* As we throw everything away when disabling, just send us back through
4126 * a repaint cycle. */
4127 if (level == WESTON_DPMS_ON) {
4128 if (output->dpms_off_pending)
4129 output->dpms_off_pending = 0;
4130 weston_output_schedule_repaint(output_base);
4131 return;
4132 }
4133
4134 /* If we've already got a request in the pipeline, then we need to
4135 * park our DPMS request until that request has quiesced. */
4136 if (output->state_last) {
4137 output->dpms_off_pending = 1;
4138 return;
4139 }
4140
4141 pending_state = drm_pending_state_alloc(b);
4142 drm_output_get_disable_state(pending_state, output);
4143 ret = drm_pending_state_apply_sync(pending_state);
4144 if (ret != 0)
4145 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004146}
4147
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004148static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004149 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
4150 [DRM_MODE_CONNECTOR_VGA] = "VGA",
4151 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
4152 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
4153 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
4154 [DRM_MODE_CONNECTOR_Composite] = "Composite",
4155 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
4156 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
4157 [DRM_MODE_CONNECTOR_Component] = "Component",
4158 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
4159 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
4160 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
4161 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
4162 [DRM_MODE_CONNECTOR_TV] = "TV",
4163 [DRM_MODE_CONNECTOR_eDP] = "eDP",
Pekka Paalanenab81f152015-08-24 14:27:07 +03004164#ifdef DRM_MODE_CONNECTOR_DSI
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004165 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
4166 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Pekka Paalanenab81f152015-08-24 14:27:07 +03004167#endif
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04004168};
4169
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004170/** Create a name given a DRM connector
4171 *
4172 * \param con The DRM connector whose type and id form the name.
4173 * \return A newly allocate string, or NULL on error. Must be free()'d
4174 * after use.
4175 *
4176 * The name does not identify the DRM display device.
4177 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004178static char *
4179make_connector_name(const drmModeConnector *con)
4180{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004181 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004182 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004183 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004184
4185 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
4186 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004187
4188 if (!type_name)
4189 type_name = "UNNAMED";
4190
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004191 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
4192 if (ret < 0)
4193 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004194
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004195 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004196}
4197
Daniel Stonee4256832017-04-04 17:54:27 +01004198static void drm_output_fini_cursor_egl(struct drm_output *output)
4199{
4200 unsigned int i;
4201
4202 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
4203 drm_fb_unref(output->gbm_cursor_fb[i]);
4204 output->gbm_cursor_fb[i] = NULL;
4205 }
4206}
4207
4208static int
4209drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
4210{
4211 unsigned int i;
4212
Daniel Stone2ba17f42015-05-19 20:02:41 +01004213 /* No point creating cursors if we don't have a plane for them. */
4214 if (!output->cursor_plane)
4215 return 0;
4216
Daniel Stonee4256832017-04-04 17:54:27 +01004217 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
4218 struct gbm_bo *bo;
4219
4220 bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
4221 GBM_FORMAT_ARGB8888,
4222 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
4223 if (!bo)
4224 goto err;
4225
4226 output->gbm_cursor_fb[i] =
Daniel Stonedb10df12016-12-08 13:15:58 +00004227 drm_fb_get_from_bo(bo, b, false, BUFFER_CURSOR);
Daniel Stonee4256832017-04-04 17:54:27 +01004228 if (!output->gbm_cursor_fb[i]) {
4229 gbm_bo_destroy(bo);
4230 goto err;
4231 }
4232 }
4233
4234 return 0;
4235
4236err:
4237 weston_log("cursor buffers unavailable, using gl cursors\n");
4238 b->cursors_are_broken = 1;
4239 drm_output_fini_cursor_egl(output);
4240 return -1;
4241}
4242
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004243/* Init output state that depends on gl or gbm */
4244static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004245drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004246{
Derek Foremanc4cfe852015-05-15 12:12:40 -05004247 EGLint format[2] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004248 output->gbm_format,
4249 fallback_format_for(output->gbm_format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05004250 };
Daniel Stonee4256832017-04-04 17:54:27 +01004251 int n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004252
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004253 output->gbm_surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02004254 output->base.current_mode->width,
4255 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05004256 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004257 GBM_BO_USE_SCANOUT |
4258 GBM_BO_USE_RENDERING);
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004259 if (!output->gbm_surface) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004260 weston_log("failed to create gbm surface\n");
4261 return -1;
4262 }
4263
Derek Foremanc4cfe852015-05-15 12:12:40 -05004264 if (format[1])
4265 n_formats = 2;
Miguel A. Vicoc095cde2016-05-18 17:43:00 +02004266 if (gl_renderer->output_window_create(&output->base,
4267 (EGLNativeWindowType)output->gbm_surface,
4268 output->gbm_surface,
4269 gl_renderer->opaque_attribs,
4270 format,
4271 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004272 weston_log("failed to create gl renderer output state\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004273 gbm_surface_destroy(output->gbm_surface);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004274 return -1;
4275 }
4276
Daniel Stonee4256832017-04-04 17:54:27 +01004277 drm_output_init_cursor_egl(output, b);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004278
4279 return 0;
4280}
4281
Daniel Stone3e661f72016-11-04 17:24:06 +00004282static void
4283drm_output_fini_egl(struct drm_output *output)
4284{
Daniel Stonee2e80132018-01-16 15:37:33 +00004285 struct drm_backend *b = to_drm_backend(output->base.compositor);
4286
4287 /* Destroying the GBM surface will destroy all our GBM buffers,
4288 * regardless of refcount. Ensure we destroy them here. */
4289 if (!b->shutting_down &&
4290 output->scanout_plane->state_cur->fb &&
4291 output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
4292 drm_plane_state_free(output->scanout_plane->state_cur, true);
4293 output->scanout_plane->state_cur =
4294 drm_plane_state_alloc(NULL, output->scanout_plane);
4295 output->scanout_plane->state_cur->complete = true;
4296 }
4297
Daniel Stone3e661f72016-11-04 17:24:06 +00004298 gl_renderer->output_destroy(&output->base);
4299 gbm_surface_destroy(output->gbm_surface);
Daniel Stonee4256832017-04-04 17:54:27 +01004300 drm_output_fini_cursor_egl(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00004301}
4302
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04004303static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004304drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004305{
Hardeningff39efa2013-09-18 23:56:35 +02004306 int w = output->base.current_mode->width;
4307 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004308 uint32_t format = output->gbm_format;
4309 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004310 unsigned int i;
Pekka Paalanendee412d2018-04-23 11:44:58 +02004311 uint32_t flags = 0;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004312
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004313 switch (format) {
4314 case GBM_FORMAT_XRGB8888:
4315 pixman_format = PIXMAN_x8r8g8b8;
4316 break;
4317 case GBM_FORMAT_RGB565:
4318 pixman_format = PIXMAN_r5g6b5;
4319 break;
4320 default:
4321 weston_log("Unsupported pixman format 0x%x\n", format);
4322 return -1;
4323 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004324
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004325 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004326 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004327 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004328 if (!output->dumb[i])
4329 goto err;
4330
4331 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004332 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004333 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00004334 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004335 if (!output->image[i])
4336 goto err;
4337 }
4338
Pekka Paalanendee412d2018-04-23 11:44:58 +02004339 if (b->use_pixman_shadow)
4340 flags |= PIXMAN_RENDERER_OUTPUT_USE_SHADOW;
4341
4342 if (pixman_renderer_output_create(&output->base, flags) < 0)
4343 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304344
Pekka Paalanendee412d2018-04-23 11:44:58 +02004345 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
4346 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004347
4348 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02004349 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004350
4351 return 0;
4352
4353err:
4354 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
4355 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01004356 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004357 if (output->image[i])
4358 pixman_image_unref(output->image[i]);
4359
4360 output->dumb[i] = NULL;
4361 output->image[i] = NULL;
4362 }
4363
4364 return -1;
4365}
4366
4367static void
4368drm_output_fini_pixman(struct drm_output *output)
4369{
Daniel Stonee2e80132018-01-16 15:37:33 +00004370 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004371 unsigned int i;
4372
Daniel Stonee2e80132018-01-16 15:37:33 +00004373 /* Destroying the Pixman surface will destroy all our buffers,
4374 * regardless of refcount. Ensure we destroy them here. */
4375 if (!b->shutting_down &&
4376 output->scanout_plane->state_cur->fb &&
4377 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
4378 drm_plane_state_free(output->scanout_plane->state_cur, true);
4379 output->scanout_plane->state_cur =
4380 drm_plane_state_alloc(NULL, output->scanout_plane);
4381 output->scanout_plane->state_cur->complete = true;
4382 }
4383
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004384 pixman_renderer_output_destroy(&output->base);
4385 pixman_region32_fini(&output->previous_damage);
4386
4387 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004388 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01004389 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004390 output->dumb[i] = NULL;
4391 output->image[i] = NULL;
4392 }
4393}
4394
Richard Hughes2b2092a2013-04-24 14:58:02 +01004395static void
4396edid_parse_string(const uint8_t *data, char text[])
4397{
4398 int i;
4399 int replaced = 0;
4400
4401 /* this is always 12 bytes, but we can't guarantee it's null
4402 * terminated or not junk. */
4403 strncpy(text, (const char *) data, 12);
4404
Bryce Harrington9c7de162015-08-28 13:04:26 -07004405 /* guarantee our new string is null-terminated */
4406 text[12] = '\0';
4407
Richard Hughes2b2092a2013-04-24 14:58:02 +01004408 /* remove insane chars */
4409 for (i = 0; text[i] != '\0'; i++) {
4410 if (text[i] == '\n' ||
4411 text[i] == '\r') {
4412 text[i] = '\0';
4413 break;
4414 }
4415 }
4416
4417 /* ensure string is printable */
4418 for (i = 0; text[i] != '\0'; i++) {
4419 if (!isprint(text[i])) {
4420 text[i] = '-';
4421 replaced++;
4422 }
4423 }
4424
4425 /* if the string is random junk, ignore the string */
4426 if (replaced > 4)
4427 text[0] = '\0';
4428}
4429
4430#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
4431#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
4432#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
4433#define EDID_OFFSET_DATA_BLOCKS 0x36
4434#define EDID_OFFSET_LAST_BLOCK 0x6c
4435#define EDID_OFFSET_PNPID 0x08
4436#define EDID_OFFSET_SERIAL 0x0c
4437
4438static int
4439edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
4440{
4441 int i;
4442 uint32_t serial_number;
4443
4444 /* check header */
4445 if (length < 128)
4446 return -1;
4447 if (data[0] != 0x00 || data[1] != 0xff)
4448 return -1;
4449
4450 /* decode the PNP ID from three 5 bit words packed into 2 bytes
4451 * /--08--\/--09--\
4452 * 7654321076543210
4453 * |\---/\---/\---/
4454 * R C1 C2 C3 */
4455 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
4456 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
4457 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
4458 edid->pnp_id[3] = '\0';
4459
4460 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
4461 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
4462 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
4463 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
4464 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
4465 if (serial_number > 0)
4466 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
4467
4468 /* parse EDID data */
4469 for (i = EDID_OFFSET_DATA_BLOCKS;
4470 i <= EDID_OFFSET_LAST_BLOCK;
4471 i += 18) {
4472 /* ignore pixel clock data */
4473 if (data[i] != 0)
4474 continue;
4475 if (data[i+2] != 0)
4476 continue;
4477
4478 /* any useful blocks? */
4479 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
4480 edid_parse_string(&data[i+5],
4481 edid->monitor_name);
4482 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
4483 edid_parse_string(&data[i+5],
4484 edid->serial_number);
4485 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
4486 edid_parse_string(&data[i+5],
4487 edid->eisa_id);
4488 }
4489 }
4490 return 0;
4491}
4492
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004493/** Parse monitor make, model and serial from EDID
4494 *
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004495 * \param head The head whose \c drm_edid to fill in.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004496 * \param props The DRM connector properties to get the EDID from.
4497 * \param make[out] The monitor make (PNP ID).
4498 * \param model[out] The monitor model (name).
4499 * \param serial_number[out] The monitor serial number.
4500 *
4501 * Each of \c *make, \c *model and \c *serial_number are set only if the
4502 * information is found in the EDID. The pointers they are set to must not
4503 * be free()'d explicitly, instead they get implicitly freed when the
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004504 * \c drm_head is destroyed.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004505 */
Richard Hughes2b2092a2013-04-24 14:58:02 +01004506static void
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004507find_and_parse_output_edid(struct drm_head *head,
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004508 drmModeObjectPropertiesPtr props,
4509 const char **make,
4510 const char **model,
4511 const char **serial_number)
Richard Hughes2b2092a2013-04-24 14:58:02 +01004512{
4513 drmModePropertyBlobPtr edid_blob = NULL;
Daniel Stone02cf4662017-03-03 16:19:39 +00004514 uint32_t blob_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004515 int rc;
4516
Daniel Stone02cf4662017-03-03 16:19:39 +00004517 blob_id =
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004518 drm_property_get_value(&head->props_conn[WDRM_CONNECTOR_EDID],
Daniel Stone02cf4662017-03-03 16:19:39 +00004519 props, 0);
4520 if (!blob_id)
4521 return;
4522
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004523 edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id);
Richard Hughes2b2092a2013-04-24 14:58:02 +01004524 if (!edid_blob)
4525 return;
4526
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004527 rc = edid_parse(&head->edid,
Richard Hughes2b2092a2013-04-24 14:58:02 +01004528 edid_blob->data,
4529 edid_blob->length);
4530 if (!rc) {
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004531 if (head->edid.pnp_id[0] != '\0')
4532 *make = head->edid.pnp_id;
4533 if (head->edid.monitor_name[0] != '\0')
4534 *model = head->edid.monitor_name;
4535 if (head->edid.serial_number[0] != '\0')
4536 *serial_number = head->edid.serial_number;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004537 }
4538 drmModeFreePropertyBlob(edid_blob);
4539}
4540
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004541static int
4542parse_modeline(const char *s, drmModeModeInfo *mode)
4543{
4544 char hsync[16];
4545 char vsync[16];
4546 float fclock;
4547
Pekka Paalanendc4e3c62017-12-05 15:37:41 +02004548 memset(mode, 0, sizeof *mode);
4549
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004550 mode->type = DRM_MODE_TYPE_USERDEF;
4551 mode->hskew = 0;
4552 mode->vscan = 0;
4553 mode->vrefresh = 0;
4554 mode->flags = 0;
4555
Rob Bradford307e09e2013-07-26 16:29:40 +01004556 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004557 &fclock,
4558 &mode->hdisplay,
4559 &mode->hsync_start,
4560 &mode->hsync_end,
4561 &mode->htotal,
4562 &mode->vdisplay,
4563 &mode->vsync_start,
4564 &mode->vsync_end,
4565 &mode->vtotal, hsync, vsync) != 11)
4566 return -1;
4567
4568 mode->clock = fclock * 1000;
Guido Günther92278e02018-06-26 20:40:08 +02004569 if (strcasecmp(hsync, "+hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004570 mode->flags |= DRM_MODE_FLAG_PHSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02004571 else if (strcasecmp(hsync, "-hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004572 mode->flags |= DRM_MODE_FLAG_NHSYNC;
4573 else
4574 return -1;
4575
Guido Günther92278e02018-06-26 20:40:08 +02004576 if (strcasecmp(vsync, "+vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004577 mode->flags |= DRM_MODE_FLAG_PVSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02004578 else if (strcasecmp(vsync, "-vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004579 mode->flags |= DRM_MODE_FLAG_NVSYNC;
4580 else
4581 return -1;
4582
Emmanuel Gil Peyrota62138b2016-05-02 22:40:11 +01004583 snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
4584 mode->hdisplay, mode->vdisplay, fclock);
4585
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004586 return 0;
4587}
4588
Rob Bradford66bd9f52013-06-25 18:56:42 +01004589static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03004590setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01004591 struct weston_output *output,
4592 const char *s)
4593{
4594 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05004595 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004596 struct udev_seat *seat;
4597
Giulio Camuffo954f1832014-10-11 18:27:30 +03004598 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05004599 if (!seat)
4600 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004601
Derek Foreman0720ea32015-07-15 13:00:35 -05004602 seat->base.output = output;
4603
Derek Foreman1281a362015-07-31 16:55:32 -05004604 pointer = weston_seat_get_pointer(&seat->base);
4605 if (pointer)
4606 weston_pointer_clamp(pointer,
4607 &pointer->x,
4608 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01004609 }
4610}
4611
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004612static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03004613drm_output_attach_head(struct weston_output *output_base,
4614 struct weston_head *head_base)
4615{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004616 struct drm_backend *b = to_drm_backend(output_base->compositor);
4617
Pekka Paalanenc112f002017-08-28 16:27:20 +03004618 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
4619 return -1;
4620
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004621 if (!output_base->enabled)
4622 return 0;
4623
4624 /* XXX: ensure the configuration will work.
4625 * This is actually impossible without major infrastructure
4626 * work. */
4627
4628 /* Need to go through modeset to add connectors. */
4629 /* XXX: Ideally we'd do this per-output, not globally. */
4630 /* XXX: Doing it globally, what guarantees another output's update
4631 * will not clear the flag before this output is updated?
4632 */
4633 b->state_invalid = true;
4634
4635 weston_output_schedule_repaint(output_base);
4636
Pekka Paalanenc112f002017-08-28 16:27:20 +03004637 return 0;
4638}
4639
Pekka Paalanen7f853792017-11-29 14:33:33 +02004640static void
4641drm_output_detach_head(struct weston_output *output_base,
4642 struct weston_head *head_base)
4643{
4644 struct drm_backend *b = to_drm_backend(output_base->compositor);
4645
4646 if (!output_base->enabled)
4647 return;
4648
4649 /* Need to go through modeset to drop connectors that should no longer
4650 * be driven. */
4651 /* XXX: Ideally we'd do this per-output, not globally. */
4652 b->state_invalid = true;
4653
4654 weston_output_schedule_repaint(output_base);
4655}
4656
Pekka Paalanenc112f002017-08-28 16:27:20 +03004657static int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004658parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004659{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004660 int ret = 0;
4661
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004662 if (s == NULL)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004663 *gbm_format = default_value;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004664 else if (strcmp(s, "xrgb8888") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004665 *gbm_format = GBM_FORMAT_XRGB8888;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004666 else if (strcmp(s, "rgb565") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004667 *gbm_format = GBM_FORMAT_RGB565;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004668 else if (strcmp(s, "xrgb2101010") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004669 *gbm_format = GBM_FORMAT_XRGB2101010;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004670 else {
4671 weston_log("fatal: unrecognized pixel format: %s\n", s);
4672 ret = -1;
4673 }
4674
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004675 return ret;
4676}
4677
Pekka Paalanenf005f252017-11-10 16:34:39 +02004678static uint32_t
4679u32distance(uint32_t a, uint32_t b)
4680{
4681 if (a < b)
4682 return b - a;
4683 else
4684 return a - b;
4685}
4686
4687/** Choose equivalent mode
4688 *
4689 * If the two modes are not equivalent, return NULL.
4690 * Otherwise return the mode that is more likely to work in place of both.
4691 *
4692 * None of the fuzzy matching criteria in this function have any justification.
4693 *
4694 * typedef struct _drmModeModeInfo {
4695 * uint32_t clock;
4696 * uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
4697 * uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
4698 *
4699 * uint32_t vrefresh;
4700 *
4701 * uint32_t flags;
4702 * uint32_t type;
4703 * char name[DRM_DISPLAY_MODE_LEN];
4704 * } drmModeModeInfo, *drmModeModeInfoPtr;
4705 */
4706static const drmModeModeInfo *
4707drm_mode_pick_equivalent(const drmModeModeInfo *a, const drmModeModeInfo *b)
4708{
4709 uint32_t refresh_a, refresh_b;
4710
4711 if (a->hdisplay != b->hdisplay || a->vdisplay != b->vdisplay)
4712 return NULL;
4713
4714 if (a->flags != b->flags)
4715 return NULL;
4716
4717 /* kHz */
4718 if (u32distance(a->clock, b->clock) > 500)
4719 return NULL;
4720
4721 refresh_a = drm_refresh_rate_mHz(a);
4722 refresh_b = drm_refresh_rate_mHz(b);
4723 if (u32distance(refresh_a, refresh_b) > 50)
4724 return NULL;
4725
4726 if ((a->type ^ b->type) & DRM_MODE_TYPE_PREFERRED) {
4727 if (a->type & DRM_MODE_TYPE_PREFERRED)
4728 return a;
4729 else
4730 return b;
4731 }
4732
4733 return a;
4734}
4735
4736/* If the given mode info is not already in the list, add it.
4737 * If it is in the list, either keep the existing or replace it,
4738 * depending on which one is "better".
4739 */
4740static int
4741drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
4742{
4743 struct weston_mode *base;
4744 struct drm_mode *mode;
4745 struct drm_backend *backend;
4746 const drmModeModeInfo *chosen = NULL;
4747
4748 assert(info);
4749
4750 wl_list_for_each(base, &output->base.mode_list, link) {
4751 mode = to_drm_mode(base);
4752 chosen = drm_mode_pick_equivalent(&mode->mode_info, info);
4753 if (chosen)
4754 break;
4755 }
4756
4757 if (chosen == info) {
4758 backend = to_drm_backend(output->base.compositor);
4759 drm_output_destroy_mode(backend, mode);
4760 chosen = NULL;
4761 }
4762
4763 if (!chosen) {
4764 mode = drm_output_add_mode(output, info);
4765 if (!mode)
4766 return -1;
4767 }
4768 /* else { the equivalent mode is already in the list } */
4769
4770 return 0;
4771}
4772
Pekka Paalanen4be24852017-09-11 15:01:12 +03004773/** Rewrite the output's mode list
4774 *
4775 * @param output The output.
4776 * @return 0 on success, -1 on failure.
4777 *
4778 * Destroy all existing modes in the list, and reconstruct a new list from
4779 * scratch, based on the currently attached heads.
4780 *
4781 * On failure the output's mode list may contain some modes.
4782 */
4783static int
4784drm_output_update_modelist_from_heads(struct drm_output *output)
4785{
4786 struct drm_backend *backend = to_drm_backend(output->base.compositor);
4787 struct weston_head *head_base;
4788 struct drm_head *head;
Pekka Paalanen4be24852017-09-11 15:01:12 +03004789 int i;
Pekka Paalanenf005f252017-11-10 16:34:39 +02004790 int ret;
Pekka Paalanen4be24852017-09-11 15:01:12 +03004791
4792 assert(!output->base.enabled);
4793
4794 drm_mode_list_destroy(backend, &output->base.mode_list);
4795
Pekka Paalanenf005f252017-11-10 16:34:39 +02004796 wl_list_for_each(head_base, &output->base.head_list, output_link) {
4797 head = to_drm_head(head_base);
4798 for (i = 0; i < head->connector->count_modes; i++) {
4799 ret = drm_output_try_add_mode(output,
4800 &head->connector->modes[i]);
4801 if (ret < 0)
4802 return -1;
4803 }
Pekka Paalanen4be24852017-09-11 15:01:12 +03004804 }
4805
4806 return 0;
4807}
4808
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004809/**
4810 * Choose suitable mode for an output
4811 *
4812 * Find the most suitable mode to use for initial setup (or reconfiguration on
4813 * hotplug etc) for a DRM output.
4814 *
4815 * @param output DRM output to choose mode for
4816 * @param kind Strategy and preference to use when choosing mode
4817 * @param width Desired width for this output
4818 * @param height Desired height for this output
4819 * @param current_mode Mode currently being displayed on this output
4820 * @param modeline Manually-entered mode (may be NULL)
4821 * @returns A mode from the output's mode list, or NULL if none available
4822 */
4823static struct drm_mode *
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004824drm_output_choose_initial_mode(struct drm_backend *backend,
4825 struct drm_output *output,
4826 enum weston_drm_backend_output_mode mode,
Armin Krezović08368132016-09-30 14:11:05 +02004827 const char *modeline,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004828 const drmModeModeInfo *current_mode)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004829{
4830 struct drm_mode *preferred = NULL;
4831 struct drm_mode *current = NULL;
4832 struct drm_mode *configured = NULL;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304833 struct drm_mode *config_fall_back = NULL;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004834 struct drm_mode *best = NULL;
4835 struct drm_mode *drm_mode;
Armin Krezović08368132016-09-30 14:11:05 +02004836 drmModeModeInfo drm_modeline;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004837 int32_t width = 0;
4838 int32_t height = 0;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01004839 uint32_t refresh = 0;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304840 uint32_t aspect_width = 0;
4841 uint32_t aspect_height = 0;
4842 enum weston_mode_aspect_ratio aspect_ratio = WESTON_MODE_PIC_AR_NONE;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01004843 int n;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004844
Armin Krezović08368132016-09-30 14:11:05 +02004845 if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304846 n = sscanf(modeline, "%dx%d@%d %u:%u", &width, &height,
4847 &refresh, &aspect_width, &aspect_height);
4848 if (backend->aspect_ratio_supported && n == 5) {
4849 if (aspect_width == 4 && aspect_height == 3)
4850 aspect_ratio = WESTON_MODE_PIC_AR_4_3;
4851 else if (aspect_width == 16 && aspect_height == 9)
4852 aspect_ratio = WESTON_MODE_PIC_AR_16_9;
4853 else if (aspect_width == 64 && aspect_height == 27)
4854 aspect_ratio = WESTON_MODE_PIC_AR_64_27;
4855 else if (aspect_width == 256 && aspect_height == 135)
4856 aspect_ratio = WESTON_MODE_PIC_AR_256_135;
4857 else
4858 weston_log("Invalid modeline \"%s\" for output %s\n",
4859 modeline, output->base.name);
4860 }
4861 if (n != 2 && n != 3 && n != 5) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004862 width = -1;
4863
Armin Krezović08368132016-09-30 14:11:05 +02004864 if (parse_modeline(modeline, &drm_modeline) == 0) {
4865 configured = drm_output_add_mode(output, &drm_modeline);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004866 if (!configured)
4867 return NULL;
4868 } else {
4869 weston_log("Invalid modeline \"%s\" for output %s\n",
Armin Krezović08368132016-09-30 14:11:05 +02004870 modeline, output->base.name);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004871 }
4872 }
4873 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004874
4875 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004876 if (width == drm_mode->base.width &&
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01004877 height == drm_mode->base.height &&
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304878 (refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) {
4879 if (!backend->aspect_ratio_supported ||
4880 aspect_ratio == drm_mode->base.aspect_ratio)
4881 configured = drm_mode;
4882 else
4883 config_fall_back = drm_mode;
4884 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004885
comic fans7a5c5622016-03-17 14:29:27 +02004886 if (memcmp(current_mode, &drm_mode->mode_info,
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004887 sizeof *current_mode) == 0)
4888 current = drm_mode;
4889
4890 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
4891 preferred = drm_mode;
4892
4893 best = drm_mode;
4894 }
4895
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004896 if (current == NULL && current_mode->clock != 0) {
4897 current = drm_output_add_mode(output, current_mode);
4898 if (!current)
4899 return NULL;
4900 }
4901
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004902 if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004903 configured = current;
4904
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004905 if (configured)
4906 return configured;
4907
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304908 if (config_fall_back)
4909 return config_fall_back;
4910
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004911 if (preferred)
4912 return preferred;
4913
4914 if (current)
4915 return current;
4916
4917 if (best)
4918 return best;
4919
4920 weston_log("no available modes for %s\n", output->base.name);
4921 return NULL;
4922}
4923
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004924static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02004925drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004926{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02004927 int drm_fd = backend->drm.fd;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004928 drmModeEncoder *encoder;
4929 drmModeCrtc *crtc;
4930
4931 /* Get the current mode on the crtc that's currently driving
4932 * this connector. */
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02004933 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004934 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004935 head->inherited_crtc_id = encoder->crtc_id;
4936
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004937 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
4938 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004939
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004940 if (crtc == NULL)
4941 return -1;
4942 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02004943 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004944 drmModeFreeCrtc(crtc);
4945 }
4946
4947 return 0;
4948}
4949
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004950static int
Armin Krezović08368132016-09-30 14:11:05 +02004951drm_output_set_mode(struct weston_output *base,
4952 enum weston_drm_backend_output_mode mode,
4953 const char *modeline)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004954{
Armin Krezović08368132016-09-30 14:11:05 +02004955 struct drm_output *output = to_drm_output(base);
4956 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004957 struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004958
Armin Krezović445b41b2016-10-09 23:48:16 +02004959 struct drm_mode *current;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004960
Pekka Paalanen4be24852017-09-11 15:01:12 +03004961 if (drm_output_update_modelist_from_heads(output) < 0)
4962 return -1;
4963
Pekka Paalanen13d233e2017-09-11 14:06:11 +03004964 current = drm_output_choose_initial_mode(b, output, mode, modeline,
4965 &head->inherited_mode);
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004966 if (!current)
Armin Krezović445b41b2016-10-09 23:48:16 +02004967 return -1;
Armin Krezović08368132016-09-30 14:11:05 +02004968
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004969 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02004970 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04004971
Armin Krezović08368132016-09-30 14:11:05 +02004972 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
4973 output->base.native_mode = output->base.current_mode;
4974 output->base.native_scale = output->base.current_scale;
4975
Armin Krezović08368132016-09-30 14:11:05 +02004976 return 0;
Armin Krezović08368132016-09-30 14:11:05 +02004977}
4978
4979static void
4980drm_output_set_gbm_format(struct weston_output *base,
4981 const char *gbm_format)
4982{
4983 struct drm_output *output = to_drm_output(base);
4984 struct drm_backend *b = to_drm_backend(base->compositor);
4985
4986 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
4987 output->gbm_format = b->gbm_format;
Daniel Stonee2e80132018-01-16 15:37:33 +00004988
4989 /* Without universal planes, we can't discover which formats are
4990 * supported by the primary plane; we just hope that the GBM format
4991 * works. */
4992 if (!b->universal_planes)
4993 output->scanout_plane->formats[0] = output->gbm_format;
Armin Krezović08368132016-09-30 14:11:05 +02004994}
4995
4996static void
4997drm_output_set_seat(struct weston_output *base,
4998 const char *seat)
4999{
5000 struct drm_output *output = to_drm_output(base);
5001 struct drm_backend *b = to_drm_backend(base->compositor);
5002
5003 setup_output_seat_constraint(b, &output->base,
5004 seat ? seat : "");
5005}
5006
5007static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03005008drm_output_init_gamma_size(struct drm_output *output)
5009{
5010 struct drm_backend *backend = to_drm_backend(output->base.compositor);
5011 drmModeCrtc *crtc;
5012
5013 assert(output->base.compositor);
5014 assert(output->crtc_id != 0);
5015 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
5016 if (!crtc)
5017 return -1;
5018
5019 output->base.gamma_size = crtc->gamma_size;
5020
5021 drmModeFreeCrtc(crtc);
5022
5023 return 0;
5024}
5025
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005026static uint32_t
5027drm_head_get_possible_crtcs_mask(struct drm_head *head)
5028{
5029 uint32_t possible_crtcs = 0;
5030 drmModeEncoder *encoder;
5031 int i;
5032
5033 for (i = 0; i < head->connector->count_encoders; i++) {
5034 encoder = drmModeGetEncoder(head->backend->drm.fd,
5035 head->connector->encoders[i]);
5036 if (!encoder)
5037 continue;
5038
5039 possible_crtcs |= encoder->possible_crtcs;
5040 drmModeFreeEncoder(encoder);
5041 }
5042
5043 return possible_crtcs;
5044}
5045
5046static int
5047drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
5048{
5049 int i;
5050
5051 for (i = 0; i < resources->count_crtcs; i++) {
5052 if (resources->crtcs[i] == crtc_id)
5053 return i;
5054 }
5055
5056 assert(0 && "unknown crtc id");
5057 return -1;
5058}
5059
5060/** Pick a CRTC that might be able to drive all attached connectors
5061 *
5062 * @param output The output whose attached heads to include.
5063 * @param resources The DRM KMS resources.
5064 * @return CRTC index, or -1 on failure or not found.
5065 */
5066static int
5067drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
5068{
5069 struct drm_backend *backend;
5070 struct weston_head *base;
5071 struct drm_head *head;
5072 uint32_t possible_crtcs = 0xffffffff;
5073 int existing_crtc[32];
5074 unsigned j, n = 0;
5075 uint32_t crtc_id;
5076 int best_crtc_index = -1;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005077 int fallback_crtc_index = -1;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005078 int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005079 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005080
5081 backend = to_drm_backend(output->base.compositor);
5082
5083 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
5084 * because it is more often set wrong than not in the kernel. */
5085
5086 /* Accumulate a mask of possible crtcs and find existing routings. */
5087 wl_list_for_each(base, &output->base.head_list, output_link) {
5088 head = to_drm_head(base);
5089
5090 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
5091
5092 crtc_id = head->inherited_crtc_id;
5093 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
5094 existing_crtc[n++] = drm_crtc_get_index(resources,
5095 crtc_id);
5096 }
5097
5098 /* Find a crtc that could drive each connector individually at least,
5099 * and prefer existing routings. */
5100 for (i = 0; i < resources->count_crtcs; i++) {
5101 crtc_id = resources->crtcs[i];
5102
5103 /* Could the crtc not drive each connector? */
5104 if (!(possible_crtcs & (1 << i)))
5105 continue;
5106
5107 /* Is the crtc already in use? */
5108 if (drm_output_find_by_crtc(backend, crtc_id))
5109 continue;
5110
5111 /* Try to preserve the existing CRTC -> connector routing;
5112 * it makes initialisation faster, and also since we have a
5113 * very dumb picking algorithm, may preserve a better
5114 * choice. */
5115 for (j = 0; j < n; j++) {
5116 if (existing_crtc[j] == i)
5117 return i;
5118 }
5119
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005120 /* Check if any other head had existing routing to this CRTC.
5121 * If they did, this is not the best CRTC as it might be needed
5122 * for another output we haven't enabled yet. */
5123 match = false;
5124 wl_list_for_each(base, &backend->compositor->head_list,
5125 compositor_link) {
5126 head = to_drm_head(base);
5127
5128 if (head->base.output == &output->base)
5129 continue;
5130
5131 if (weston_head_is_enabled(&head->base))
5132 continue;
5133
5134 if (head->inherited_crtc_id == crtc_id) {
5135 match = true;
5136 break;
5137 }
5138 }
5139 if (!match)
5140 best_crtc_index = i;
5141
5142 fallback_crtc_index = i;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005143 }
5144
5145 if (best_crtc_index != -1)
5146 return best_crtc_index;
5147
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005148 if (fallback_crtc_index != -1)
5149 return fallback_crtc_index;
5150
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005151 /* Likely possible_crtcs was empty due to asking for clones,
5152 * but since the DRM documentation says the kernel lies, let's
5153 * pick one crtc anyway. Trial and error is the only way to
5154 * be sure if something doesn't work. */
5155
5156 /* First pick any existing assignment. */
5157 for (j = 0; j < n; j++) {
5158 crtc_id = resources->crtcs[existing_crtc[j]];
5159 if (!drm_output_find_by_crtc(backend, crtc_id))
5160 return existing_crtc[j];
5161 }
5162
5163 /* Otherwise pick any available crtc. */
5164 for (i = 0; i < resources->count_crtcs; i++) {
5165 crtc_id = resources->crtcs[i];
5166
5167 if (!drm_output_find_by_crtc(backend, crtc_id))
5168 return i;
5169 }
5170
5171 return -1;
5172}
5173
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005174/** Allocate a CRTC for the output
5175 *
5176 * @param output The output with no allocated CRTC.
5177 * @param resources DRM KMS resources.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005178 * @return 0 on success, -1 on failure.
5179 *
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005180 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005181 * for the output, and loads the CRTC properties.
5182 *
5183 * Populates the cursor and scanout planes.
5184 *
5185 * On failure, the output remains without a CRTC.
5186 */
5187static int
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005188drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005189{
5190 struct drm_backend *b = to_drm_backend(output->base.compositor);
5191 drmModeObjectPropertiesPtr props;
5192 int i;
5193
5194 assert(output->crtc_id == 0);
5195
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005196 i = drm_output_pick_crtc(output, resources);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005197 if (i < 0) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005198 weston_log("Output '%s': No available CRTCs.\n",
5199 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005200 return -1;
5201 }
5202
5203 output->crtc_id = resources->crtcs[i];
5204 output->pipe = i;
5205
5206 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
5207 DRM_MODE_OBJECT_CRTC);
5208 if (!props) {
5209 weston_log("failed to get CRTC properties\n");
5210 goto err_crtc;
5211 }
5212 drm_property_info_populate(b, crtc_props, output->props_crtc,
5213 WDRM_CRTC__COUNT, props);
5214 drmModeFreeObjectProperties(props);
5215
5216 output->scanout_plane =
5217 drm_output_find_special_plane(b, output,
5218 WDRM_PLANE_TYPE_PRIMARY);
5219 if (!output->scanout_plane) {
5220 weston_log("Failed to find primary plane for output %s\n",
5221 output->base.name);
5222 goto err_crtc;
5223 }
5224
5225 /* Failing to find a cursor plane is not fatal, as we'll fall back
5226 * to software cursor. */
5227 output->cursor_plane =
5228 drm_output_find_special_plane(b, output,
5229 WDRM_PLANE_TYPE_CURSOR);
5230
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005231 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
5232
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005233 return 0;
5234
5235err_crtc:
5236 output->crtc_id = 0;
5237 output->pipe = 0;
5238
5239 return -1;
5240}
5241
5242/** Free the CRTC from the output
5243 *
5244 * @param output The output whose CRTC to deallocate.
5245 *
5246 * The CRTC reserved for the given output becomes free to use again.
5247 */
5248static void
5249drm_output_fini_crtc(struct drm_output *output)
5250{
5251 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005252 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005253
5254 if (!b->universal_planes && !b->shutting_down) {
5255 /* With universal planes, the 'special' planes are allocated at
5256 * startup, freed at shutdown, and live on the plane list in
5257 * between. We want the planes to continue to exist and be freed
5258 * up for other outputs.
5259 *
5260 * Without universal planes, our special planes are
5261 * pseudo-planes allocated at output creation, freed at output
5262 * destruction, and not usable by other outputs.
5263 *
5264 * On the other hand, if the compositor is already shutting down,
5265 * the plane has already been destroyed.
5266 */
5267 if (output->cursor_plane)
5268 drm_plane_destroy(output->cursor_plane);
5269 if (output->scanout_plane)
5270 drm_plane_destroy(output->scanout_plane);
5271 }
5272
5273 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005274
5275 assert(output->crtc_id != 0);
5276
5277 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
5278 *unused = output->crtc_id;
5279
5280 /* Force resetting unused CRTCs */
5281 b->state_invalid = true;
5282
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005283 output->crtc_id = 0;
5284 output->cursor_plane = NULL;
5285 output->scanout_plane = NULL;
5286}
5287
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005288static void
5289drm_output_print_modes(struct drm_output *output)
5290{
5291 struct weston_mode *m;
5292 struct drm_mode *dm;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305293 const char *aspect_ratio;
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005294
5295 wl_list_for_each(m, &output->base.mode_list, link) {
5296 dm = to_drm_mode(m);
5297
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305298 aspect_ratio = aspect_ratio_to_string(m->aspect_ratio);
5299 weston_log_continue(STAMP_SPACE "%dx%d@%.1f%s%s%s, %.1f MHz\n",
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005300 m->width, m->height, m->refresh / 1000.0,
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305301 aspect_ratio,
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005302 m->flags & WL_OUTPUT_MODE_PREFERRED ?
5303 ", preferred" : "",
5304 m->flags & WL_OUTPUT_MODE_CURRENT ?
5305 ", current" : "",
5306 dm->mode_info.clock / 1000.0);
5307 }
5308}
5309
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03005310static int
Armin Krezović08368132016-09-30 14:11:05 +02005311drm_output_enable(struct weston_output *base)
5312{
5313 struct drm_output *output = to_drm_output(base);
5314 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005315 drmModeRes *resources;
5316 int ret;
5317
5318 resources = drmModeGetResources(b->drm.fd);
5319 if (!resources) {
5320 weston_log("drmModeGetResources failed\n");
5321 return -1;
5322 }
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005323 ret = drm_output_init_crtc(output, resources);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005324 drmModeFreeResources(resources);
5325 if (ret < 0)
5326 return -1;
5327
5328 if (drm_output_init_gamma_size(output) < 0)
5329 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02005330
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005331 if (b->pageflip_timeout)
5332 drm_output_pageflip_timer_create(output);
5333
Giulio Camuffo954f1832014-10-11 18:27:30 +03005334 if (b->use_pixman) {
5335 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005336 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005337 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005338 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03005339 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005340 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005341 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04005342 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04005343
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02005344 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005345
Jonas Ådahle5a12252013-04-05 23:07:11 +02005346 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05005347 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05005348 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005349 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08005350 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01005351 output->base.set_gamma = drm_output_set_gamma;
5352
Daniel Stone2ba17f42015-05-19 20:02:41 +01005353 if (output->cursor_plane)
5354 weston_compositor_stack_plane(b->compositor,
5355 &output->cursor_plane->base,
5356 NULL);
5357 else
5358 b->cursors_are_broken = 1;
5359
Daniel Stonee2e80132018-01-16 15:37:33 +00005360 weston_compositor_stack_plane(b->compositor,
5361 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03005362 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02005363
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005364 weston_log("Output %s (crtc %d) video modes:\n",
5365 output->base.name, output->crtc_id);
5366 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04005367
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005368 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01005369
Daniel Stone02cf4662017-03-03 16:19:39 +00005370err:
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005371 drm_output_fini_crtc(output);
5372
David Herrmann0f0d54e2011-12-08 17:05:45 +01005373 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005374}
5375
Jesse Barnes58ef3792012-02-23 09:45:49 -05005376static void
Armin Krezović08368132016-09-30 14:11:05 +02005377drm_output_deinit(struct weston_output *base)
5378{
5379 struct drm_output *output = to_drm_output(base);
5380 struct drm_backend *b = to_drm_backend(base->compositor);
5381
Daniel Stone3e661f72016-11-04 17:24:06 +00005382 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02005383 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00005384 else
5385 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02005386
Daniel Stone2ba17f42015-05-19 20:02:41 +01005387 /* Since our planes are no longer in use anywhere, remove their base
5388 * weston_plane's link from the plane stacking list, unless we're
5389 * shutting down, in which case the plane has already been
5390 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00005391 if (!b->shutting_down) {
5392 wl_list_remove(&output->scanout_plane->base.link);
5393 wl_list_init(&output->scanout_plane->base.link);
5394
5395 if (output->cursor_plane) {
5396 wl_list_remove(&output->cursor_plane->base.link);
5397 wl_list_init(&output->cursor_plane->base.link);
5398 /* Turn off hardware cursor */
5399 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
5400 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01005401 }
Daniel Stone087ddf02017-02-14 17:51:30 +00005402
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005403 drm_output_fini_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02005404}
5405
5406static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03005407drm_head_destroy(struct drm_head *head);
5408
5409static void
Armin Krezović08368132016-09-30 14:11:05 +02005410drm_output_destroy(struct weston_output *base)
5411{
5412 struct drm_output *output = to_drm_output(base);
5413 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02005414
Daniel Stone598ee9d2016-11-16 11:55:20 +00005415 if (output->page_flip_pending || output->vblank_pending ||
5416 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005417 output->destroy_pending = 1;
5418 weston_log("destroy output while page flip pending\n");
5419 return;
5420 }
5421
5422 if (output->base.enabled)
5423 drm_output_deinit(&output->base);
5424
Pekka Paalanen383b3af2017-09-11 14:40:48 +03005425 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02005426
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005427 if (output->pageflip_timer)
5428 wl_event_source_remove(output->pageflip_timer);
5429
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03005430 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02005431
Daniel Stone7b2ddac2016-11-11 19:11:49 +00005432 assert(!output->state_last);
5433 drm_output_state_free(output->state_cur);
5434
Armin Krezović08368132016-09-30 14:11:05 +02005435 free(output);
5436}
5437
5438static int
5439drm_output_disable(struct weston_output *base)
5440{
5441 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02005442
Daniel Stone598ee9d2016-11-16 11:55:20 +00005443 if (output->page_flip_pending || output->vblank_pending ||
5444 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005445 output->disable_pending = 1;
5446 return -1;
5447 }
5448
Daniel Stonea08512f2016-11-08 17:46:10 +00005449 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00005450
Armin Krezović08368132016-09-30 14:11:05 +02005451 if (output->base.enabled)
5452 drm_output_deinit(&output->base);
5453
5454 output->disable_pending = 0;
5455
Armin Krezović08368132016-09-30 14:11:05 +02005456 return 0;
5457}
5458
5459/**
Daniel Stone087ddf02017-02-14 17:51:30 +00005460 * Update the list of unused connectors and CRTCs
5461 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03005462 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00005463 *
5464 * @param b Weston backend structure
5465 * @param resources DRM resources for this device
5466 */
5467static void
5468drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
5469{
5470 int i;
5471
Daniel Stone087ddf02017-02-14 17:51:30 +00005472 wl_array_release(&b->unused_crtcs);
5473 wl_array_init(&b->unused_crtcs);
5474
5475 for (i = 0; i < resources->count_crtcs; i++) {
5476 struct drm_output *output;
5477 uint32_t *crtc_id;
5478
5479 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
5480 if (output && output->base.enabled)
5481 continue;
5482
5483 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
5484 *crtc_id = resources->crtcs[i];
5485 }
5486}
5487
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005488/** Replace connector data and monitor information
5489 *
5490 * @param head The head to update.
5491 * @param connector The connector data to be owned by the head, must match
5492 * the head's connector ID.
5493 * @return 0 on success, -1 on failure.
5494 *
5495 * Takes ownership of @c connector on success, not on failure.
5496 *
5497 * May schedule a heads changed call.
5498 */
5499static int
5500drm_head_assign_connector_info(struct drm_head *head,
5501 drmModeConnector *connector)
5502{
5503 drmModeObjectProperties *props;
5504 const char *make = "unknown";
5505 const char *model = "unknown";
5506 const char *serial_number = "unknown";
5507
5508 assert(connector);
5509 assert(head->connector_id == connector->connector_id);
5510
5511 props = drmModeObjectGetProperties(head->backend->drm.fd,
5512 head->connector_id,
5513 DRM_MODE_OBJECT_CONNECTOR);
5514 if (!props) {
5515 weston_log("Error: failed to get connector '%s' properties\n",
5516 head->base.name);
5517 return -1;
5518 }
5519
5520 if (head->connector)
5521 drmModeFreeConnector(head->connector);
5522 head->connector = connector;
5523
5524 drm_property_info_populate(head->backend, connector_props,
5525 head->props_conn,
5526 WDRM_CONNECTOR__COUNT, props);
5527 find_and_parse_output_edid(head, props, &make, &model, &serial_number);
5528 weston_head_set_monitor_strings(&head->base, make, model, serial_number);
5529 weston_head_set_subpixel(&head->base,
5530 drm_subpixel_to_wayland(head->connector->subpixel));
5531
5532 weston_head_set_physical_size(&head->base, head->connector->mmWidth,
5533 head->connector->mmHeight);
5534
5535 drmModeFreeObjectProperties(props);
5536
5537 /* Unknown connection status is assumed disconnected. */
5538 weston_head_set_connection_status(&head->base,
5539 head->connector->connection == DRM_MODE_CONNECTED);
5540
5541 return 0;
5542}
5543
Pekka Paalanen456dc732017-11-09 15:10:11 +02005544static void
5545drm_head_log_info(struct drm_head *head, const char *msg)
5546{
5547 if (head->base.connected) {
5548 weston_log("DRM: head '%s' %s, connector %d is connected, "
5549 "EDID make '%s', model '%s', serial '%s'\n",
5550 head->base.name, msg, head->connector_id,
5551 head->base.make, head->base.model,
5552 head->base.serial_number ?: "");
5553 } else {
5554 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
5555 head->base.name, msg, head->connector_id);
5556 }
5557}
5558
Pekka Paalanend2e62422017-09-08 15:48:07 +03005559/** Update connector and monitor information
5560 *
5561 * @param head The head to update.
5562 *
5563 * Re-reads the DRM property lists for the connector and updates monitor
5564 * information and connection status. This may schedule a heads changed call
5565 * to the user.
5566 */
5567static void
5568drm_head_update_info(struct drm_head *head)
5569{
5570 drmModeConnector *connector;
5571
5572 connector = drmModeGetConnector(head->backend->drm.fd,
5573 head->connector_id);
5574 if (!connector) {
5575 weston_log("DRM: getting connector info for '%s' failed.\n",
5576 head->base.name);
5577 return;
5578 }
5579
5580 if (drm_head_assign_connector_info(head, connector) < 0)
5581 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005582
5583 if (head->base.device_changed)
5584 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03005585}
5586
Daniel Stone087ddf02017-02-14 17:51:30 +00005587/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03005588 * Create a Weston head for a connector
5589 *
5590 * Given a DRM connector, create a matching drm_head structure and add it
5591 * to Weston's head list.
5592 *
5593 * @param b Weston backend structure
5594 * @param connector_id DRM connector ID for the head
5595 * @param drm_device udev device pointer
5596 * @returns The new head, or NULL on failure.
5597 */
5598static struct drm_head *
5599drm_head_create(struct drm_backend *backend, uint32_t connector_id,
5600 struct udev_device *drm_device)
5601{
5602 struct drm_head *head;
5603 drmModeConnector *connector;
5604 char *name;
5605
5606 head = zalloc(sizeof *head);
5607 if (!head)
5608 return NULL;
5609
5610 connector = drmModeGetConnector(backend->drm.fd, connector_id);
5611 if (!connector)
5612 goto err_alloc;
5613
5614 name = make_connector_name(connector);
5615 if (!name)
5616 goto err_alloc;
5617
5618 weston_head_init(&head->base, name);
5619 free(name);
5620
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005621 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03005622 head->backend = backend;
5623
Pekka Paalanence724242017-09-04 12:21:24 +03005624 head->backlight = backlight_init(drm_device, connector->connector_type);
5625
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005626 if (drm_head_assign_connector_info(head, connector) < 0)
5627 goto err_init;
5628
5629 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
5630 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
5631 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03005632
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005633 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005634 weston_log("Failed to retrieve current mode from connector %d.\n",
5635 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02005636 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005637 }
5638
Pekka Paalanenc112f002017-08-28 16:27:20 +03005639 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005640 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03005641
5642 return head;
5643
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005644err_init:
5645 weston_head_release(&head->base);
5646
Pekka Paalanenc112f002017-08-28 16:27:20 +03005647err_alloc:
5648 if (connector)
5649 drmModeFreeConnector(connector);
5650
5651 free(head);
5652
5653 return NULL;
5654}
5655
5656static void
5657drm_head_destroy(struct drm_head *head)
5658{
5659 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03005660
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005661 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
5662 drmModeFreeConnector(head->connector);
5663
Pekka Paalanence724242017-09-04 12:21:24 +03005664 if (head->backlight)
5665 backlight_destroy(head->backlight);
5666
Pekka Paalanenc112f002017-08-28 16:27:20 +03005667 free(head);
5668}
5669
5670/**
Armin Krezović08368132016-09-30 14:11:05 +02005671 * Create a Weston output structure
5672 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03005673 * Create an "empty" drm_output. This is the implementation of
5674 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02005675 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03005676 * Creating an output is usually followed by drm_output_attach_head()
5677 * and drm_output_enable() to make use of it.
5678 *
5679 * @param compositor The compositor instance.
5680 * @param name Name for the new output.
5681 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02005682 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03005683static struct weston_output *
5684drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02005685{
Pekka Paalanend2e62422017-09-08 15:48:07 +03005686 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02005687 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02005688
Armin Krezović08368132016-09-30 14:11:05 +02005689 output = zalloc(sizeof *output);
5690 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03005691 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02005692
Pekka Paalanend2e62422017-09-08 15:48:07 +03005693 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005694
Armin Krezović08368132016-09-30 14:11:05 +02005695 output->base.enable = drm_output_enable;
5696 output->base.destroy = drm_output_destroy;
5697 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03005698 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02005699 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02005700
5701 output->destroy_pending = 0;
5702 output->disable_pending = 0;
Armin Krezović08368132016-09-30 14:11:05 +02005703
Pekka Paalanen01f60212017-03-24 15:39:24 +02005704 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03005705
Armin Krezović08368132016-09-30 14:11:05 +02005706 weston_compositor_add_pending_output(&output->base, b->compositor);
5707
Pekka Paalanend2e62422017-09-08 15:48:07 +03005708 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02005709}
5710
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005711static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03005712drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005713{
Pekka Paalanend2e62422017-09-08 15:48:07 +03005714 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005715 drmModeRes *resources;
5716 int i;
5717
Giulio Camuffo954f1832014-10-11 18:27:30 +03005718 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005719 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02005720 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005721 return -1;
5722 }
5723
Giulio Camuffo954f1832014-10-11 18:27:30 +03005724 b->min_width = resources->min_width;
5725 b->max_width = resources->max_width;
5726 b->min_height = resources->min_height;
5727 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05005728
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005729 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005730 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00005731
Pekka Paalanend2e62422017-09-08 15:48:07 +03005732 head = drm_head_create(b, connector_id, drm_device);
5733 if (!head) {
5734 weston_log("DRM: failed to create head for connector %d.\n",
5735 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02005736 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005737 }
5738
Daniel Stone087ddf02017-02-14 17:51:30 +00005739 drm_backend_update_unused_outputs(b, resources);
5740
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005741 drmModeFreeResources(resources);
5742
5743 return 0;
5744}
5745
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005746static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03005747drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005748{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005749 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03005750 struct weston_head *base, *next;
5751 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005752 int i;
5753
Giulio Camuffo954f1832014-10-11 18:27:30 +03005754 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005755 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02005756 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005757 return;
5758 }
5759
Pekka Paalanend2e62422017-09-08 15:48:07 +03005760 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005761 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00005762 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02005763
Pekka Paalanend2e62422017-09-08 15:48:07 +03005764 head = drm_head_find_by_connector(b, connector_id);
5765 if (head) {
5766 drm_head_update_info(head);
5767 } else {
5768 head = drm_head_create(b, connector_id, drm_device);
5769 if (!head)
5770 weston_log("DRM: failed to create head for hot-added connector %d.\n",
5771 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01005772 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005773 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005774
Pekka Paalanend2e62422017-09-08 15:48:07 +03005775 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03005776 wl_list_for_each_safe(base, next,
5777 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005778 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005779
Pekka Paalanena0a37462017-08-31 15:41:57 +03005780 head = to_drm_head(base);
5781
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005782 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005783 if (resources->connectors[i] == head->connector_id) {
5784 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005785 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005786 }
5787 }
Armin Krezović08368132016-09-30 14:11:05 +02005788
Pekka Paalanend2e62422017-09-08 15:48:07 +03005789 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005790 continue;
5791
Pekka Paalanend2e62422017-09-08 15:48:07 +03005792 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
5793 head->base.name, head->connector_id);
5794 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005795 }
5796
Daniel Stone087ddf02017-02-14 17:51:30 +00005797 drm_backend_update_unused_outputs(b, resources);
5798
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005799 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005800}
5801
5802static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03005803udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005804{
David Herrmannd7488c22012-03-11 20:05:21 +01005805 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01005806 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01005807
5808 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005809 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01005810 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02005811
David Herrmann6ac52db2012-03-11 20:05:22 +01005812 val = udev_device_get_property_value(device, "HOTPLUG");
5813 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005814 return 0;
5815
David Herrmann6ac52db2012-03-11 20:05:22 +01005816 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005817}
5818
Kristian Høgsbergb1868472011-04-22 12:27:57 -04005819static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005820udev_drm_event(int fd, uint32_t mask, void *data)
5821{
Giulio Camuffo954f1832014-10-11 18:27:30 +03005822 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005823 struct udev_device *event;
5824
Giulio Camuffo954f1832014-10-11 18:27:30 +03005825 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02005826
Giulio Camuffo954f1832014-10-11 18:27:30 +03005827 if (udev_event_is_hotplug(b, event))
Pekka Paalanend2e62422017-09-08 15:48:07 +03005828 drm_backend_update_heads(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005829
5830 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04005831
5832 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005833}
5834
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005835static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005836drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005837{
Armin Krezović545dba62016-08-05 15:54:18 +02005838 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03005839 struct weston_head *base, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005840
Giulio Camuffo954f1832014-10-11 18:27:30 +03005841 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02005842
Giulio Camuffo954f1832014-10-11 18:27:30 +03005843 wl_event_source_remove(b->udev_drm_source);
5844 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02005845
Daniel Stoneb57c6a02017-10-05 16:27:21 +01005846 b->shutting_down = true;
5847
Giulio Camuffo954f1832014-10-11 18:27:30 +03005848 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04005849
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03005850 weston_compositor_shutdown(ec);
5851
Pekka Paalanenc112f002017-08-28 16:27:20 +03005852 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
5853 drm_head_destroy(to_drm_head(base));
5854
Giulio Camuffo954f1832014-10-11 18:27:30 +03005855 if (b->gbm)
5856 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005857
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02005858 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03005859 udev_unref(b->udev);
5860
Giulio Camuffo954f1832014-10-11 18:27:30 +03005861 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005862
Daniel Stone087ddf02017-02-14 17:51:30 +00005863 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00005864
Giulio Camuffo954f1832014-10-11 18:27:30 +03005865 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02005866 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005867 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005868}
5869
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005870static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005871session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005872{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005873 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02005874 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01005875 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04005876 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005877
Giulio Camuffo954f1832014-10-11 18:27:30 +03005878 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005879 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00005880 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005881 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00005882 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03005883 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005884 } else {
5885 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03005886 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04005887
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01005888 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04005889
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05005890 /* If we have a repaint scheduled (either from a
5891 * pending pageflip or the idle handler), make sure we
5892 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01005893 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05005894 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05005895 * back, we schedule a repaint, which will process
5896 * pending frame callbacks. */
5897
Giulio Camuffo954f1832014-10-11 18:27:30 +03005898 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00005899 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01005900 if (output->cursor_plane)
5901 drmModeSetCursor(b->drm.fd, output->crtc_id,
5902 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05005903 }
5904
Giulio Camuffo954f1832014-10-11 18:27:30 +03005905 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04005906 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05005907
Daniel Stone085d2b92015-05-21 00:00:57 +01005908 wl_list_for_each(plane, &b->plane_list, link) {
5909 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
5910 continue;
5911
Giulio Camuffo954f1832014-10-11 18:27:30 +03005912 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01005913 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04005914 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05005915 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01005916 }
5917 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005918}
5919
Daniel Stoneefa504f2016-12-19 16:48:20 +00005920/**
5921 * Determines whether or not a device is capable of modesetting. If successful,
5922 * sets b->drm.fd and b->drm.filename to the opened device.
5923 */
5924static bool
5925drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
5926{
5927 const char *filename = udev_device_get_devnode(device);
5928 const char *sysnum = udev_device_get_sysnum(device);
5929 drmModeRes *res;
5930 int id, fd;
5931
5932 if (!filename)
5933 return false;
5934
5935 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
5936 if (fd < 0)
5937 return false;
5938
5939 res = drmModeGetResources(fd);
5940 if (!res)
5941 goto out_fd;
5942
5943 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
5944 res->count_encoders <= 0)
5945 goto out_res;
5946
5947 if (sysnum)
5948 id = atoi(sysnum);
5949 if (!sysnum || id < 0) {
5950 weston_log("couldn't get sysnum for device %s\n", filename);
5951 goto out_res;
5952 }
5953
5954 /* We can be called successfully on multiple devices; if we have,
5955 * clean up old entries. */
5956 if (b->drm.fd >= 0)
5957 weston_launcher_close(b->compositor->launcher, b->drm.fd);
5958 free(b->drm.filename);
5959
5960 b->drm.fd = fd;
5961 b->drm.id = id;
5962 b->drm.filename = strdup(filename);
5963
Sergi Granellceb59812017-03-28 12:44:04 +02005964 drmModeFreeResources(res);
5965
Daniel Stoneefa504f2016-12-19 16:48:20 +00005966 return true;
5967
5968out_res:
5969 drmModeFreeResources(res);
5970out_fd:
5971 weston_launcher_close(b->compositor->launcher, fd);
5972 return false;
5973}
5974
David Herrmann0af066f2012-10-29 19:21:16 +01005975/*
5976 * Find primary GPU
5977 * Some systems may have multiple DRM devices attached to a single seat. This
5978 * function loops over all devices and tries to find a PCI device with the
5979 * boot_vga sysfs attribute set to 1.
5980 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00005981 * Devices are also vetted to make sure they are are capable of modesetting,
5982 * rather than pure render nodes (GPU with no display), or pure
5983 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01005984 */
5985static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03005986find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01005987{
5988 struct udev_enumerate *e;
5989 struct udev_list_entry *entry;
5990 const char *path, *device_seat, *id;
5991 struct udev_device *device, *drm_device, *pci;
5992
Giulio Camuffo954f1832014-10-11 18:27:30 +03005993 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01005994 udev_enumerate_add_match_subsystem(e, "drm");
5995 udev_enumerate_add_match_sysname(e, "card[0-9]*");
5996
5997 udev_enumerate_scan_devices(e);
5998 drm_device = NULL;
5999 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00006000 bool is_boot_vga = false;
6001
David Herrmann0af066f2012-10-29 19:21:16 +01006002 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006003 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01006004 if (!device)
6005 continue;
6006 device_seat = udev_device_get_property_value(device, "ID_SEAT");
6007 if (!device_seat)
6008 device_seat = default_seat;
6009 if (strcmp(device_seat, seat)) {
6010 udev_device_unref(device);
6011 continue;
6012 }
6013
6014 pci = udev_device_get_parent_with_subsystem_devtype(device,
6015 "pci", NULL);
6016 if (pci) {
6017 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00006018 if (id && !strcmp(id, "1"))
6019 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01006020 }
6021
Daniel Stoneefa504f2016-12-19 16:48:20 +00006022 /* If we already have a modesetting-capable device, and this
6023 * device isn't our boot-VGA device, we aren't going to use
6024 * it. */
6025 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01006026 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006027 continue;
6028 }
6029
6030 /* Make sure this device is actually capable of modesetting;
6031 * if this call succeeds, b->drm.{fd,filename} will be set,
6032 * and any old values freed. */
6033 if (!drm_device_is_kms(b, device)) {
6034 udev_device_unref(device);
6035 continue;
6036 }
6037
6038 /* There can only be one boot_vga device, and we try to use it
6039 * at all costs. */
6040 if (is_boot_vga) {
6041 if (drm_device)
6042 udev_device_unref(drm_device);
6043 drm_device = device;
6044 break;
6045 }
6046
6047 /* Per the (!is_boot_vga && drm_device) test above, we only
6048 * trump existing saved devices with boot-VGA devices, so if
6049 * we end up here, this must be the first device we've seen. */
6050 assert(!drm_device);
6051 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01006052 }
6053
Daniel Stoneefa504f2016-12-19 16:48:20 +00006054 /* If we're returning a device to use, we must have an open FD for
6055 * it. */
6056 assert(!!drm_device == (b->drm.fd >= 0));
6057
David Herrmann0af066f2012-10-29 19:21:16 +01006058 udev_enumerate_unref(e);
6059 return drm_device;
6060}
6061
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03006062static struct udev_device *
6063open_specific_drm_device(struct drm_backend *b, const char *name)
6064{
6065 struct udev_device *device;
6066
6067 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
6068 if (!device) {
6069 weston_log("ERROR: could not open DRM device '%s'\n", name);
6070 return NULL;
6071 }
6072
6073 if (!drm_device_is_kms(b, device)) {
6074 udev_device_unref(device);
6075 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
6076 return NULL;
6077 }
6078
6079 /* If we're returning a device to use, we must have an open FD for
6080 * it. */
6081 assert(b->drm.fd >= 0);
6082
6083 return device;
6084}
6085
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006086static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006087planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6088 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006089{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006090 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006091
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006092 switch (key) {
6093 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006094 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006095 break;
6096 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006097 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006098 break;
6099 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006100 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006101 break;
6102 default:
6103 break;
6104 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02006105}
6106
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07006107#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006108static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006109recorder_destroy(struct drm_output *output)
6110{
6111 vaapi_recorder_destroy(output->recorder);
6112 output->recorder = NULL;
6113
6114 output->base.disable_planes--;
6115
6116 wl_list_remove(&output->recorder_frame_listener.link);
6117 weston_log("[libva recorder] done\n");
6118}
6119
6120static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006121recorder_frame_notify(struct wl_listener *listener, void *data)
6122{
6123 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006124 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006125 int fd, ret;
6126
6127 output = container_of(listener, struct drm_output,
6128 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02006129 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006130
6131 if (!output->recorder)
6132 return;
6133
Daniel Stonee2e80132018-01-16 15:37:33 +00006134 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00006135 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006136 DRM_CLOEXEC, &fd);
6137 if (ret) {
6138 weston_log("[libva recorder] "
6139 "failed to create prime fd for front buffer\n");
6140 return;
6141 }
6142
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006143 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00006144 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006145 if (ret < 0) {
6146 weston_log("[libva recorder] aborted: %m\n");
6147 recorder_destroy(output);
6148 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006149}
6150
6151static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03006152create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006153 const char *filename)
6154{
6155 int fd;
6156 drm_magic_t magic;
6157
Giulio Camuffo954f1832014-10-11 18:27:30 +03006158 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006159 if (fd < 0)
6160 return NULL;
6161
6162 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006163 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006164
6165 return vaapi_recorder_create(fd, width, height, filename);
6166}
6167
6168static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006169recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6170 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006171{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006172 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006173 struct drm_output *output;
6174 int width, height;
6175
Giulio Camuffo954f1832014-10-11 18:27:30 +03006176 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006177 struct drm_output, base.link);
6178
6179 if (!output->recorder) {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01006180 if (output->gbm_format != GBM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03006181 weston_log("failed to start vaapi recorder: "
6182 "output format not supported\n");
6183 return;
6184 }
6185
Hardeningff39efa2013-09-18 23:56:35 +02006186 width = output->base.current_mode->width;
6187 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006188
6189 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03006190 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006191 if (!output->recorder) {
6192 weston_log("failed to create vaapi recorder\n");
6193 return;
6194 }
6195
6196 output->base.disable_planes++;
6197
6198 output->recorder_frame_listener.notify = recorder_frame_notify;
6199 wl_signal_add(&output->base.frame_signal,
6200 &output->recorder_frame_listener);
6201
6202 weston_output_schedule_repaint(&output->base);
6203
6204 weston_log("[libva recorder] initialized\n");
6205 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006206 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006207 }
6208}
6209#else
6210static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006211recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6212 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006213{
6214 weston_log("Compiled without libva support\n");
6215}
6216#endif
6217
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006218static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03006219switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006220{
6221 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006222 bool dmabuf_support_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006223
Giulio Camuffo954f1832014-10-11 18:27:30 +03006224 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006225 return;
6226
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006227 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
6228
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006229 weston_log("Switching to GL renderer\n");
6230
Giulio Camuffo954f1832014-10-11 18:27:30 +03006231 b->gbm = create_gbm_device(b->drm.fd);
6232 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006233 weston_log("Failed to create gbm device. "
6234 "Aborting renderer switch\n");
6235 return;
6236 }
6237
Giulio Camuffo954f1832014-10-11 18:27:30 +03006238 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006239 pixman_renderer_output_destroy(&output->base);
6240
Giulio Camuffo954f1832014-10-11 18:27:30 +03006241 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006242
Giulio Camuffo954f1832014-10-11 18:27:30 +03006243 if (drm_backend_create_gl_renderer(b) < 0) {
6244 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006245 weston_log("Failed to create GL renderer. Quitting.\n");
6246 /* FIXME: we need a function to shutdown cleanly */
6247 assert(0);
6248 }
6249
Giulio Camuffo954f1832014-10-11 18:27:30 +03006250 wl_list_for_each(output, &b->compositor->output_list, base.link)
6251 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006252
Giulio Camuffo954f1832014-10-11 18:27:30 +03006253 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006254
6255 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
6256 if (linux_dmabuf_setup(b->compositor) < 0)
6257 weston_log("Error: initializing dmabuf "
6258 "support failed.\n");
6259 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006260}
6261
6262static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006263renderer_switch_binding(struct weston_keyboard *keyboard,
6264 const struct timespec *time, uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006265{
Derek Foreman8ae2db52015-07-15 13:00:36 -05006266 struct drm_backend *b =
Armin Krezović545dba62016-08-05 15:54:18 +02006267 to_drm_backend(keyboard->seat->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006268
Giulio Camuffo954f1832014-10-11 18:27:30 +03006269 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006270}
6271
Armin Krezović08368132016-09-30 14:11:05 +02006272static const struct weston_drm_output_api api = {
6273 drm_output_set_mode,
6274 drm_output_set_gbm_format,
6275 drm_output_set_seat,
6276};
6277
Giulio Camuffo954f1832014-10-11 18:27:30 +03006278static struct drm_backend *
6279drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006280 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006281{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006282 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01006283 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006284 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006285 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04006286 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02006287 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006288
nerdopolisb16c4ac2018-06-29 08:17:46 -04006289 session_seat = getenv("XDG_SEAT");
6290 if (session_seat)
6291 seat_id = session_seat;
6292
6293 if (config->seat_id)
6294 seat_id = config->seat_id;
6295
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04006296 weston_log("initializing drm backend\n");
6297
Giulio Camuffo954f1832014-10-11 18:27:30 +03006298 b = zalloc(sizeof *b);
6299 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006300 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01006301
Daniel Stone6020f472018-02-05 15:46:20 +00006302 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00006303 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00006304 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006305
Pekka Paalanen68583832015-05-19 09:53:16 +03006306 /*
6307 * KMS support for hardware planes cannot properly synchronize
6308 * without nuclear page flip. Without nuclear/atomic, hw plane
6309 * and cursor plane updates would either tear or cause extra
6310 * waits for vblanks which means dropping the compositor framerate
Pekka Paalanen3f32a132015-09-07 15:38:43 +03006311 * to a fraction. For cursors, it's not so bad, so they are
6312 * enabled.
Pekka Paalanen68583832015-05-19 09:53:16 +03006313 *
6314 * These can be enabled again when nuclear/atomic support lands.
6315 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03006316 b->sprites_are_broken = 1;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006317 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006318 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00006319 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02006320 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006321
Pekka Paalanen7da9a382017-08-30 11:29:49 +03006322 compositor->backend = &b->base;
6323
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006324 if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
6325 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006326
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006327 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006328 compositor->launcher = weston_launcher_connect(compositor, config->tty,
6329 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006330 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02006331 weston_log("fatal: drm backend should be run using "
6332 "weston-launch binary, or your system should "
6333 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006334 goto err_compositor;
6335 }
6336
Giulio Camuffo954f1832014-10-11 18:27:30 +03006337 b->udev = udev_new();
6338 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006339 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006340 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006341 }
6342
Giulio Camuffo954f1832014-10-11 18:27:30 +03006343 b->session_listener.notify = session_notify;
6344 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05006345
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03006346 if (config->specific_device)
6347 drm_device = open_specific_drm_device(b, config->specific_device);
6348 else
6349 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04006350 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006351 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006352 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006353 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006354
Daniel Stoneefa504f2016-12-19 16:48:20 +00006355 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02006356 weston_log("failed to initialize kms\n");
6357 goto err_udev_dev;
6358 }
6359
Giulio Camuffo954f1832014-10-11 18:27:30 +03006360 if (b->use_pixman) {
6361 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006362 weston_log("failed to initialize pixman renderer\n");
6363 goto err_udev_dev;
6364 }
6365 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03006366 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006367 weston_log("failed to initialize egl\n");
6368 goto err_udev_dev;
6369 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006370 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05006371
Giulio Camuffo954f1832014-10-11 18:27:30 +03006372 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00006373 b->base.repaint_begin = drm_repaint_begin;
6374 b->base.repaint_flush = drm_repaint_flush;
6375 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03006376 b->base.create_output = drm_output_create;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02006377
Bob Ham91880f12016-01-12 10:21:47 +00006378 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04006379
Daniel Stone085d2b92015-05-21 00:00:57 +01006380 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006381 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05006382
Giulio Camuffo954f1832014-10-11 18:27:30 +03006383 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03006384 compositor, b->udev, seat_id,
6385 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006386 weston_log("failed to create input devices\n");
6387 goto err_sprite;
6388 }
6389
Pekka Paalanend2e62422017-09-08 15:48:07 +03006390 if (drm_backend_create_heads(b, drm_device) < 0) {
6391 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006392 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006393 }
6394
Jason Ekstrand9fc71512014-04-02 19:53:46 -05006395 /* A this point we have some idea of whether or not we have a working
6396 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03006397 if (!b->cursors_are_broken)
6398 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05006399
Giulio Camuffo954f1832014-10-11 18:27:30 +03006400 loop = wl_display_get_event_loop(compositor->wl_display);
6401 b->drm_source =
6402 wl_event_loop_add_fd(loop, b->drm.fd,
6403 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006404
Giulio Camuffo954f1832014-10-11 18:27:30 +03006405 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
6406 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05006407 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01006408 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006409 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03006410 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006411 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006412 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02006413 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03006414 udev_monitor_get_fd(b->udev_monitor),
6415 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006416
Giulio Camuffo954f1832014-10-11 18:27:30 +03006417 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02006418 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01006419 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006420 }
6421
Daniel Stonea96b93c2012-06-22 14:04:37 +01006422 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006423
Giulio Camuffo954f1832014-10-11 18:27:30 +03006424 weston_compositor_add_debug_binding(compositor, KEY_O,
6425 planes_binding, b);
6426 weston_compositor_add_debug_binding(compositor, KEY_C,
6427 planes_binding, b);
6428 weston_compositor_add_debug_binding(compositor, KEY_V,
6429 planes_binding, b);
6430 weston_compositor_add_debug_binding(compositor, KEY_Q,
6431 recorder_binding, b);
6432 weston_compositor_add_debug_binding(compositor, KEY_W,
6433 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006434
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006435 if (compositor->renderer->import_dmabuf) {
6436 if (linux_dmabuf_setup(compositor) < 0)
6437 weston_log("Error: initializing dmabuf "
6438 "support failed.\n");
6439 }
6440
Armin Krezović08368132016-09-30 14:11:05 +02006441 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
6442 &api, sizeof(api));
6443
6444 if (ret < 0) {
6445 weston_log("Failed to register output API.\n");
6446 goto err_udev_monitor;
6447 }
6448
Giulio Camuffo954f1832014-10-11 18:27:30 +03006449 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01006450
6451err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006452 wl_event_source_remove(b->udev_drm_source);
6453 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006454err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006455 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006456err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006457 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04006458err_sprite:
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01006459 if (b->gbm)
6460 gbm_device_destroy(b->gbm);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006461 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006462err_udev_dev:
6463 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006464err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006465 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006466err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006467 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006468err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006469 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006470 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006471 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006472}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006473
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006474static void
6475config_init_to_defaults(struct weston_drm_backend_config *config)
6476{
Pekka Paalanendee412d2018-04-23 11:44:58 +02006477 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006478}
6479
Giulio Camuffo954f1832014-10-11 18:27:30 +03006480WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01006481weston_backend_init(struct weston_compositor *compositor,
6482 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006483{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006484 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006485 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006486
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006487 if (config_base == NULL ||
6488 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
6489 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
6490 weston_log("drm backend config structure is invalid\n");
6491 return -1;
6492 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02006493
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006494 config_init_to_defaults(&config);
6495 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07006496
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006497 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006498 if (b == NULL)
6499 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006500
Giulio Camuffo954f1832014-10-11 18:27:30 +03006501 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006502}