blob: d045778aa22af6dcae61dd9ab077d5bc9751992a [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,
Sergi Granellf4456222017-01-12 17:17:32 +0000147 WDRM_PLANE_IN_FORMATS,
Daniel Stone598ee9d2016-11-16 11:55:20 +0000148 WDRM_PLANE__COUNT
149};
150
151/**
152 * Possible values for the WDRM_PLANE_TYPE property.
153 */
154enum wdrm_plane_type {
155 WDRM_PLANE_TYPE_PRIMARY = 0,
156 WDRM_PLANE_TYPE_CURSOR,
157 WDRM_PLANE_TYPE_OVERLAY,
158 WDRM_PLANE_TYPE__COUNT
159};
160
161static struct drm_property_enum_info plane_type_enums[] = {
162 [WDRM_PLANE_TYPE_PRIMARY] = {
163 .name = "Primary",
164 },
165 [WDRM_PLANE_TYPE_OVERLAY] = {
166 .name = "Overlay",
167 },
168 [WDRM_PLANE_TYPE_CURSOR] = {
169 .name = "Cursor",
170 },
171};
172
173static const struct drm_property_info plane_props[] = {
174 [WDRM_PLANE_TYPE] = {
175 .name = "type",
176 .enum_values = plane_type_enums,
177 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
178 },
179 [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
180 [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
181 [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
182 [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
183 [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
184 [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
185 [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
186 [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
187 [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
188 [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
Sergi Granellf4456222017-01-12 17:17:32 +0000189 [WDRM_PLANE_IN_FORMATS] = { .name = "IN_FORMATS" },
Daniel Stone598ee9d2016-11-16 11:55:20 +0000190};
191
192/**
193 * List of properties attached to a DRM connector
194 */
195enum wdrm_connector_property {
196 WDRM_CONNECTOR_EDID = 0,
197 WDRM_CONNECTOR_DPMS,
198 WDRM_CONNECTOR_CRTC_ID,
199 WDRM_CONNECTOR__COUNT
200};
201
Daniel Stone76255772018-07-06 11:36:49 +0100202enum wdrm_dpms_state {
203 WDRM_DPMS_STATE_OFF = 0,
204 WDRM_DPMS_STATE_ON,
205 WDRM_DPMS_STATE_STANDBY, /* unused */
206 WDRM_DPMS_STATE_SUSPEND, /* unused */
207 WDRM_DPMS_STATE__COUNT
208};
209
210static struct drm_property_enum_info dpms_state_enums[] = {
211 [WDRM_DPMS_STATE_OFF] = {
212 .name = "Off",
213 },
214 [WDRM_DPMS_STATE_ON] = {
215 .name = "On",
216 },
217 [WDRM_DPMS_STATE_STANDBY] = {
218 .name = "Standby",
219 },
220 [WDRM_DPMS_STATE_SUSPEND] = {
221 .name = "Suspend",
222 },
223};
224
Daniel Stone598ee9d2016-11-16 11:55:20 +0000225static const struct drm_property_info connector_props[] = {
226 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
Daniel Stone76255772018-07-06 11:36:49 +0100227 [WDRM_CONNECTOR_DPMS] = {
228 .name = "DPMS",
229 .enum_values = dpms_state_enums,
230 .num_enum_values = WDRM_DPMS_STATE__COUNT,
231 },
Daniel Stone598ee9d2016-11-16 11:55:20 +0000232 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
233};
234
235/**
Pekka Paalanencd011a62016-11-15 22:07:49 +0000236 * List of properties attached to DRM CRTCs
237 */
238enum wdrm_crtc_property {
239 WDRM_CRTC_MODE_ID = 0,
240 WDRM_CRTC_ACTIVE,
241 WDRM_CRTC__COUNT
242};
243
Daniel Stone598ee9d2016-11-16 11:55:20 +0000244static const struct drm_property_info crtc_props[] = {
245 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
246 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
247};
248
Pekka Paalanencd011a62016-11-15 22:07:49 +0000249/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000250 * Mode for drm_output_state_duplicate.
251 */
252enum drm_output_state_duplicate_mode {
253 DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
254 DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
255};
256
257/**
258 * Mode for drm_pending_state_apply and co.
259 */
260enum drm_state_apply_mode {
261 DRM_STATE_APPLY_SYNC, /**< state fully processed */
262 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
263};
264
Giulio Camuffo954f1832014-10-11 18:27:30 +0300265struct drm_backend {
266 struct weston_backend base;
267 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400268
269 struct udev *udev;
270 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400271
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100272 struct udev_monitor *udev_monitor;
273 struct wl_event_source *udev_drm_source;
274
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100275 struct {
David Herrmannd7488c22012-03-11 20:05:21 +0100276 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100277 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300278 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100279 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200280 struct gbm_device *gbm;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700281 struct wl_listener session_listener;
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +0100282 uint32_t gbm_format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200283
Rob Clark4339add2012-08-09 14:18:28 -0500284 /* we need these parameters in order to not fail drmModeAddFB2()
285 * due to out of bounds dimensions, and then mistakenly set
286 * sprites_are_broken:
287 */
Daniel Stonef214fdc2016-11-14 17:43:57 +0000288 int min_width, max_width;
289 int min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -0500290
Daniel Stone085d2b92015-05-21 00:00:57 +0100291 struct wl_list plane_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500292 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200293 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500294
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000295 void *repaint_data;
296
Daniel Stone6020f472018-02-05 15:46:20 +0000297 bool state_invalid;
298
Pekka Paalaneneacec812017-09-12 13:43:51 +0300299 /* CRTC IDs not used by any enabled output. */
Daniel Stone087ddf02017-02-14 17:51:30 +0000300 struct wl_array unused_crtcs;
301
Rob Clarkab5b1e32012-08-09 13:24:45 -0500302 int cursors_are_broken;
303
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100304 bool universal_planes;
Pekka Paalanencd011a62016-11-15 22:07:49 +0000305 bool atomic_modeset;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100306
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200307 int use_pixman;
Pekka Paalanendee412d2018-04-23 11:44:58 +0200308 bool use_pixman_shadow;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200309
Rob Bradfordd355b802013-05-31 18:09:55 +0100310 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300311
Daniel Stone70d337d2015-06-16 18:42:23 +0100312 int32_t cursor_width;
313 int32_t cursor_height;
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +0000314
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000315 uint32_t pageflip_timeout;
Daniel Stoneb57c6a02017-10-05 16:27:21 +0100316
317 bool shutting_down;
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530318
319 bool aspect_ratio_supported;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400320};
321
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400322struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500323 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400324 drmModeModeInfo mode_info;
Daniel Stoned5526cb2016-11-16 10:54:10 +0000325 uint32_t blob_id;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400326};
327
Daniel Stonefc175a72017-04-04 17:54:22 +0100328enum drm_fb_type {
329 BUFFER_INVALID = 0, /**< never used */
330 BUFFER_CLIENT, /**< directly sourced from client */
Daniel Stonef522e222016-11-18 12:31:26 +0000331 BUFFER_DMABUF, /**< imported from linux_dmabuf client */
Daniel Stonefc175a72017-04-04 17:54:22 +0100332 BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
333 BUFFER_GBM_SURFACE, /**< internal EGL rendering */
Daniel Stonee4256832017-04-04 17:54:27 +0100334 BUFFER_CURSOR, /**< internal cursor buffer */
Daniel Stonefc175a72017-04-04 17:54:22 +0100335};
336
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300337struct drm_fb {
Daniel Stonefc175a72017-04-04 17:54:22 +0100338 enum drm_fb_type type;
339
Daniel Stone6e7a9612017-04-04 17:54:26 +0100340 int refcnt;
341
Daniel Stone8eece0c2016-11-17 17:54:00 +0000342 uint32_t fb_id, size;
343 uint32_t handles[4];
344 uint32_t strides[4];
345 uint32_t offsets[4];
Daniel Stone0b70fa42017-04-04 17:54:23 +0100346 const struct pixel_format_info *format;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000347 uint64_t modifier;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000348 int width, height;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200349 int fd;
Pekka Paalanende685b82012-12-04 15:58:12 +0200350 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200351
352 /* Used by gbm fbs */
353 struct gbm_bo *bo;
Daniel Stone05a5ac22017-04-04 17:54:25 +0100354 struct gbm_surface *gbm_surface;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200355
356 /* Used by dumb fbs */
357 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300358};
359
Richard Hughes2b2092a2013-04-24 14:58:02 +0100360struct drm_edid {
361 char eisa_id[13];
362 char monitor_name[13];
363 char pnp_id[5];
364 char serial_number[13];
365};
366
Daniel Stone08d4edf2017-04-04 17:54:34 +0100367/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000368 * Pending state holds one or more drm_output_state structures, collected from
369 * performing repaint. This pending state is transient, and only lives between
370 * beginning a repaint group and flushing the results: after flush, each
371 * output state will complete and be retired separately.
372 */
373struct drm_pending_state {
374 struct drm_backend *backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000375 struct wl_list output_list;
376};
377
378/*
379 * Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
380 * plus >= 1 each of encoder/connector/plane. Since everything but the planes
381 * is currently statically assigned per-output, we mainly use this to track
382 * plane state.
383 *
384 * pending_state is set when the output state is owned by a pending_state,
385 * i.e. when it is being constructed and has not yet been applied. When the
386 * output state has been applied, the owning pending_state is freed.
387 */
388struct drm_output_state {
389 struct drm_pending_state *pending_state;
390 struct drm_output *output;
391 struct wl_list link;
Daniel Stonea08512f2016-11-08 17:46:10 +0000392 enum dpms_enum dpms;
Daniel Stonebc15f682016-11-14 16:57:01 +0000393 struct wl_list plane_list;
394};
395
396/**
397 * Plane state holds the dynamic state for a plane: where it is positioned,
398 * and which buffer it is currently displaying.
399 *
400 * The plane state is owned by an output state, except when setting an initial
401 * state. See drm_output_state for notes on state object lifetime.
402 */
403struct drm_plane_state {
404 struct drm_plane *plane;
405 struct drm_output *output;
406 struct drm_output_state *output_state;
407
408 struct drm_fb *fb;
409
Daniel Stoneee1aea72017-12-18 13:41:09 +0000410 struct weston_view *ev; /**< maintained for drm_assign_planes only */
411
Daniel Stonebc15f682016-11-14 16:57:01 +0000412 int32_t src_x, src_y;
413 uint32_t src_w, src_h;
414 int32_t dest_x, dest_y;
415 uint32_t dest_w, dest_h;
416
417 bool complete;
418
419 struct wl_list link; /* drm_output_state::plane_list */
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000420};
421
422/**
Daniel Stone08d4edf2017-04-04 17:54:34 +0100423 * A plane represents one buffer, positioned within a CRTC, and stacked
424 * relative to other planes on the same CRTC.
425 *
426 * Each CRTC has a 'primary plane', which use used to display the classic
427 * framebuffer contents, as accessed through the legacy drmModeSetCrtc
428 * call (which combines setting the CRTC's actual physical mode, and the
429 * properties of the primary plane).
430 *
431 * The cursor plane also has its own alternate legacy API.
432 *
433 * Other planes are used opportunistically to display content we do not
434 * wish to blit into the primary plane. These non-primary/cursor planes
435 * are referred to as 'sprites'.
436 */
437struct drm_plane {
Daniel Stone08d4edf2017-04-04 17:54:34 +0100438 struct weston_plane base;
439
Daniel Stone08d4edf2017-04-04 17:54:34 +0100440 struct drm_backend *backend;
441
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100442 enum wdrm_plane_type type;
443
Daniel Stone08d4edf2017-04-04 17:54:34 +0100444 uint32_t possible_crtcs;
445 uint32_t plane_id;
446 uint32_t count_formats;
447
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100448 struct drm_property_info props[WDRM_PLANE__COUNT];
449
Daniel Stonebc15f682016-11-14 16:57:01 +0000450 /* The last state submitted to the kernel for this plane. */
451 struct drm_plane_state *state_cur;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100452
Daniel Stonebc15f682016-11-14 16:57:01 +0000453 struct wl_list link;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100454
Sergi Granellf4456222017-01-12 17:17:32 +0000455 struct {
456 uint32_t format;
457 uint32_t count_modifiers;
458 uint64_t *modifiers;
459 } formats[];
Daniel Stone08d4edf2017-04-04 17:54:34 +0100460};
461
Pekka Paalanenc112f002017-08-28 16:27:20 +0300462struct drm_head {
463 struct weston_head base;
464 struct drm_backend *backend;
465
Armin Krezović08368132016-09-30 14:11:05 +0200466 drmModeConnector *connector;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400467 uint32_t connector_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100468 struct drm_edid edid;
Daniel Stone02cf4662017-03-03 16:19:39 +0000469
470 /* Holds the properties for the connector */
471 struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300472
473 struct backlight *backlight;
Pekka Paalanen13d233e2017-09-11 14:06:11 +0300474
475 drmModeModeInfo inherited_mode; /**< Original mode on the connector */
Pekka Paalanen27cc4812017-11-20 13:31:06 +0200476 uint32_t inherited_crtc_id; /**< Original CRTC assignment */
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300477};
478
479struct drm_output {
480 struct weston_output base;
481
482 uint32_t crtc_id; /* object ID to pass to DRM functions */
483 int pipe; /* index of CRTC in resource array / bitmasks */
484
Pekka Paalanencd011a62016-11-15 22:07:49 +0000485 /* Holds the properties for the CRTC */
486 struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200487
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300488 int vblank_pending;
489 int page_flip_pending;
Daniel Stone598ee9d2016-11-16 11:55:20 +0000490 int atomic_complete_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800491 int destroy_pending;
Armin Krezović08368132016-09-30 14:11:05 +0200492 int disable_pending;
Daniel Stonea08512f2016-11-08 17:46:10 +0000493 int dpms_off_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300494
Daniel Stonee4256832017-04-04 17:54:27 +0100495 struct drm_fb *gbm_cursor_fb[2];
Daniel Stone2ba17f42015-05-19 20:02:41 +0100496 struct drm_plane *cursor_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500497 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400498 int current_cursor;
Daniel Stone5bb8f582017-04-04 17:54:28 +0100499
500 struct gbm_surface *gbm_surface;
501 uint32_t gbm_format;
502
Daniel Stonee2e80132018-01-16 15:37:33 +0000503 /* Plane being displayed directly on the CRTC */
504 struct drm_plane *scanout_plane;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200505
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000506 /* The last state submitted to the kernel for this CRTC. */
507 struct drm_output_state *state_cur;
508 /* The previously-submitted state, where the hardware has not
509 * yet acknowledged completion of state_cur. */
510 struct drm_output_state *state_last;
511
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200512 struct drm_fb *dumb[2];
513 pixman_image_t *image[2];
514 int current_image;
515 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300516
517 struct vaapi_recorder *recorder;
518 struct wl_listener recorder_frame_listener;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000519
520 struct wl_event_source *pageflip_timer;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400521};
522
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530523static const char *const aspect_ratio_as_string[] = {
524 [WESTON_MODE_PIC_AR_NONE] = "",
525 [WESTON_MODE_PIC_AR_4_3] = " 4:3",
526 [WESTON_MODE_PIC_AR_16_9] = " 16:9",
527 [WESTON_MODE_PIC_AR_64_27] = " 64:27",
528 [WESTON_MODE_PIC_AR_256_135] = " 256:135",
529};
530
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300531static struct gl_renderer_interface *gl_renderer;
532
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500533static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400534
Daniel Stone087ddf02017-02-14 17:51:30 +0000535static void
536wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
537{
538 uint32_t *pos, *end;
539
540 end = (uint32_t *) ((char *) array->data + array->size);
541
542 wl_array_for_each(pos, array) {
543 if (*pos != elm)
544 continue;
545
546 array->size -= sizeof(*pos);
547 if (pos + 1 == end)
548 break;
549
550 memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
551 break;
552 }
553}
554
Pekka Paalanenc112f002017-08-28 16:27:20 +0300555static inline struct drm_head *
556to_drm_head(struct weston_head *base)
557{
558 return container_of(base, struct drm_head, base);
559}
560
Armin Krezović545dba62016-08-05 15:54:18 +0200561static inline struct drm_output *
562to_drm_output(struct weston_output *base)
563{
564 return container_of(base, struct drm_output, base);
565}
566
567static inline struct drm_backend *
568to_drm_backend(struct weston_compositor *base)
569{
570 return container_of(base->backend, struct drm_backend, base);
571}
572
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000573static int
574pageflip_timeout(void *data) {
575 /*
576 * Our timer just went off, that means we're not receiving drm
577 * page flip events anymore for that output. Let's gracefully exit
578 * weston with a return value so devs can debug what's going on.
579 */
580 struct drm_output *output = data;
581 struct weston_compositor *compositor = output->base.compositor;
582
583 weston_log("Pageflip timeout reached on output %s, your "
584 "driver is probably buggy! Exiting.\n",
585 output->base.name);
586 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
587
588 return 0;
589}
590
591/* Creates the pageflip timer. Note that it isn't armed by default */
592static int
593drm_output_pageflip_timer_create(struct drm_output *output)
594{
595 struct wl_event_loop *loop = NULL;
596 struct weston_compositor *ec = output->base.compositor;
597
598 loop = wl_display_get_event_loop(ec->wl_display);
599 assert(loop);
600 output->pageflip_timer = wl_event_loop_add_timer(loop,
601 pageflip_timeout,
602 output);
603
604 if (output->pageflip_timer == NULL) {
605 weston_log("creating drm pageflip timer failed: %m\n");
606 return -1;
607 }
608
609 return 0;
610}
611
Daniel Stonecb04cc42016-11-16 11:51:27 +0000612static inline struct drm_mode *
613to_drm_mode(struct weston_mode *base)
614{
615 return container_of(base, struct drm_mode, base);
616}
617
Daniel Stone02cf4662017-03-03 16:19:39 +0000618/**
619 * Get the current value of a KMS property
620 *
621 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
622 * for the target property, return the current value of that property,
623 * with an optional default. If the property is a KMS enum type, the return
624 * value will be translated into the appropriate internal enum.
625 *
626 * If the property is not present, the default value will be returned.
627 *
628 * @param info Internal structure for property to look up
629 * @param props Raw KMS properties for the target object
630 * @param def Value to return if property is not found
631 */
632static uint64_t
633drm_property_get_value(struct drm_property_info *info,
Daniel Stone85eebdf2018-07-05 17:55:43 +0100634 const drmModeObjectProperties *props,
Daniel Stone02cf4662017-03-03 16:19:39 +0000635 uint64_t def)
636{
637 unsigned int i;
638
639 if (info->prop_id == 0)
640 return def;
641
642 for (i = 0; i < props->count_props; i++) {
643 unsigned int j;
644
645 if (props->props[i] != info->prop_id)
646 continue;
647
648 /* Simple (non-enum) types can return the value directly */
649 if (info->num_enum_values == 0)
650 return props->prop_values[i];
651
652 /* Map from raw value to enum value */
653 for (j = 0; j < info->num_enum_values; j++) {
654 if (!info->enum_values[j].valid)
655 continue;
656 if (info->enum_values[j].value != props->prop_values[i])
657 continue;
658
659 return j;
660 }
661
662 /* We don't have a mapping for this enum; return default. */
663 break;
664 }
665
666 return def;
667}
668
669/**
670 * Cache DRM property values
671 *
672 * Update a per-object array of drm_property_info structures, given the
673 * DRM properties of the object.
674 *
675 * Call this every time an object newly appears (note that only connectors
676 * can be hotplugged), the first time it is seen, or when its status changes
677 * in a way which invalidates the potential property values (currently, the
678 * only case for this is connector hotplug).
679 *
680 * This updates the property IDs and enum values within the drm_property_info
681 * array.
682 *
683 * DRM property enum values are dynamic at runtime; the user must query the
684 * property to find out the desired runtime value for a requested string
685 * name. Using the 'type' field on planes as an example, there is no single
686 * hardcoded constant for primary plane types; instead, the property must be
687 * queried at runtime to find the value associated with the string "Primary".
688 *
689 * This helper queries and caches the enum values, to allow us to use a set
690 * of compile-time-constant enums portably across various implementations.
691 * The values given in enum_names are searched for, and stored in the
692 * same-indexed field of the map array.
693 *
694 * @param b DRM backend object
695 * @param src DRM property info array to source from
696 * @param info DRM property info array to copy into
697 * @param num_infos Number of entries in the source array
698 * @param props DRM object properties for the object
699 */
700static void
701drm_property_info_populate(struct drm_backend *b,
702 const struct drm_property_info *src,
703 struct drm_property_info *info,
704 unsigned int num_infos,
705 drmModeObjectProperties *props)
706{
707 drmModePropertyRes *prop;
708 unsigned i, j;
709
710 for (i = 0; i < num_infos; i++) {
711 unsigned int j;
712
713 info[i].name = src[i].name;
714 info[i].prop_id = 0;
715 info[i].num_enum_values = src[i].num_enum_values;
716
717 if (src[i].num_enum_values == 0)
718 continue;
719
720 info[i].enum_values =
721 malloc(src[i].num_enum_values *
722 sizeof(*info[i].enum_values));
723 assert(info[i].enum_values);
724 for (j = 0; j < info[i].num_enum_values; j++) {
725 info[i].enum_values[j].name = src[i].enum_values[j].name;
726 info[i].enum_values[j].valid = false;
727 }
728 }
729
730 for (i = 0; i < props->count_props; i++) {
731 unsigned int k;
732
733 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
734 if (!prop)
735 continue;
736
737 for (j = 0; j < num_infos; j++) {
738 if (!strcmp(prop->name, info[j].name))
739 break;
740 }
741
742 /* We don't know/care about this property. */
743 if (j == num_infos) {
744#ifdef DEBUG
745 weston_log("DRM debug: unrecognized property %u '%s'\n",
746 prop->prop_id, prop->name);
747#endif
748 drmModeFreeProperty(prop);
749 continue;
750 }
751
752 if (info[j].num_enum_values == 0 &&
753 (prop->flags & DRM_MODE_PROP_ENUM)) {
754 weston_log("DRM: expected property %s to not be an"
755 " enum, but it is; ignoring\n", prop->name);
756 drmModeFreeProperty(prop);
757 continue;
758 }
759
760 info[j].prop_id = props->props[i];
761
762 if (info[j].num_enum_values == 0) {
763 drmModeFreeProperty(prop);
764 continue;
765 }
766
767 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
768 weston_log("DRM: expected property %s to be an enum,"
769 " but it is not; ignoring\n", prop->name);
770 drmModeFreeProperty(prop);
771 info[j].prop_id = 0;
772 continue;
773 }
774
775 for (k = 0; k < info[j].num_enum_values; k++) {
776 int l;
777
778 for (l = 0; l < prop->count_enums; l++) {
779 if (!strcmp(prop->enums[l].name,
780 info[j].enum_values[k].name))
781 break;
782 }
783
784 if (l == prop->count_enums)
785 continue;
786
787 info[j].enum_values[k].valid = true;
788 info[j].enum_values[k].value = prop->enums[l].value;
789 }
790
791 drmModeFreeProperty(prop);
792 }
793
794#ifdef DEBUG
795 for (i = 0; i < num_infos; i++) {
796 if (info[i].prop_id == 0)
797 weston_log("DRM warning: property '%s' missing\n",
798 info[i].name);
799 }
800#endif
801}
802
803/**
804 * Free DRM property information
805 *
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300806 * Frees all memory associated with a DRM property info array and zeroes
807 * it out, leaving it usable for a further drm_property_info_update() or
808 * drm_property_info_free().
Daniel Stone02cf4662017-03-03 16:19:39 +0000809 *
810 * @param info DRM property info array
811 * @param num_props Number of entries in array to free
812 */
813static void
814drm_property_info_free(struct drm_property_info *info, int num_props)
815{
816 int i;
817
818 for (i = 0; i < num_props; i++)
819 free(info[i].enum_values);
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300820
821 memset(info, 0, sizeof(*info) * num_props);
Daniel Stone02cf4662017-03-03 16:19:39 +0000822}
823
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400824static void
Daniel Stone2ba17f42015-05-19 20:02:41 +0100825drm_output_set_cursor(struct drm_output_state *output_state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400826
Mario Kleinerf507ec32015-06-21 21:25:14 +0200827static void
828drm_output_update_msc(struct drm_output *output, unsigned int seq);
829
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000830static void
831drm_output_destroy(struct weston_output *output_base);
832
Daniel Stone5ff289a2017-10-07 12:59:02 +0100833/**
834 * Returns true if the plane can be used on the given output for its current
835 * repaint cycle.
836 */
837static bool
838drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100840 assert(plane->state_cur);
841
842 /* The plane still has a request not yet completed by the kernel. */
843 if (!plane->state_cur->complete)
844 return false;
845
846 /* The plane is still active on another output. */
847 if (plane->state_cur->output && plane->state_cur->output != output)
848 return false;
849
850 /* Check whether the plane can be used with this CRTC; possible_crtcs
851 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Daniel Stone08d4edf2017-04-04 17:54:34 +0100852 return !!(plane->possible_crtcs & (1 << output->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500853}
854
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000855static struct drm_output *
856drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
857{
858 struct drm_output *output;
859
860 wl_list_for_each(output, &b->compositor->output_list, base.link) {
861 if (output->crtc_id == crtc_id)
862 return output;
863 }
864
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000865 return NULL;
866}
867
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300868static struct drm_head *
869drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
870{
871 struct weston_head *base;
872 struct drm_head *head;
873
874 wl_list_for_each(base,
875 &backend->compositor->head_list, compositor_link) {
876 head = to_drm_head(base);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300877 if (head->connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300878 return head;
879 }
880
881 return NULL;
882}
883
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300884static void
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100885drm_fb_destroy(struct drm_fb *fb)
886{
887 if (fb->fb_id != 0)
888 drmModeRmFB(fb->fd, fb->fb_id);
889 weston_buffer_reference(&fb->buffer_ref, NULL);
890 free(fb);
891}
892
893static void
894drm_fb_destroy_dumb(struct drm_fb *fb)
895{
896 struct drm_mode_destroy_dumb destroy_arg;
897
898 assert(fb->type == BUFFER_PIXMAN_DUMB);
899
900 if (fb->map && fb->size > 0)
901 munmap(fb->map, fb->size);
902
903 memset(&destroy_arg, 0, sizeof(destroy_arg));
Daniel Stone8eece0c2016-11-17 17:54:00 +0000904 destroy_arg.handle = fb->handles[0];
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100905 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
906
907 drm_fb_destroy(fb);
908}
909
910static void
911drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300912{
913 struct drm_fb *fb = data;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300914
Daniel Stonee4256832017-04-04 17:54:27 +0100915 assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
916 fb->type == BUFFER_CURSOR);
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100917 drm_fb_destroy(fb);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300918}
919
Daniel Stone8eece0c2016-11-17 17:54:00 +0000920static int
921drm_fb_addfb(struct drm_fb *fb)
922{
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000923 int ret = -EINVAL;
924#ifdef HAVE_DRM_ADDFB2_MODIFIERS
925 uint64_t mods[4] = { };
Daniel Stonedc082cb2018-07-09 13:49:04 +0100926 size_t i;
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000927#endif
928
929 /* If we have a modifier set, we must only use the WithModifiers
930 * entrypoint; we cannot import it through legacy ioctls. */
931 if (fb->modifier != DRM_FORMAT_MOD_INVALID) {
932 /* KMS demands that if a modifier is set, it must be the same
933 * for all planes. */
934#ifdef HAVE_DRM_ADDFB2_MODIFIERS
Daniel Stonedc082cb2018-07-09 13:49:04 +0100935 for (i = 0; i < ARRAY_LENGTH(mods) && fb->handles[i]; i++)
Daniel Stone65a4dbc2016-12-08 16:36:18 +0000936 mods[i] = fb->modifier;
937 ret = drmModeAddFB2WithModifiers(fb->fd, fb->width, fb->height,
938 fb->format->format,
939 fb->handles, fb->strides,
940 fb->offsets, mods, &fb->fb_id,
941 DRM_MODE_FB_MODIFIERS);
942#endif
943 return ret;
944 }
Daniel Stone8eece0c2016-11-17 17:54:00 +0000945
946 ret = drmModeAddFB2(fb->fd, fb->width, fb->height, fb->format->format,
947 fb->handles, fb->strides, fb->offsets, &fb->fb_id,
948 0);
949 if (ret == 0)
950 return 0;
951
952 /* Legacy AddFB can't always infer the format from depth/bpp alone, so
953 * check if our format is one of the lucky ones. */
954 if (!fb->format->depth || !fb->format->bpp)
955 return ret;
956
957 /* Cannot fall back to AddFB for multi-planar formats either. */
958 if (fb->handles[1] || fb->handles[2] || fb->handles[3])
959 return ret;
960
961 ret = drmModeAddFB(fb->fd, fb->width, fb->height,
962 fb->format->depth, fb->format->bpp,
963 fb->strides[0], fb->handles[0], &fb->fb_id);
964 return ret;
965}
966
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300967static struct drm_fb *
Daniel Stonef214fdc2016-11-14 17:43:57 +0000968drm_fb_create_dumb(struct drm_backend *b, int width, int height,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300969 uint32_t format)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200970{
971 struct drm_fb *fb;
972 int ret;
973
974 struct drm_mode_create_dumb create_arg;
975 struct drm_mode_destroy_dumb destroy_arg;
976 struct drm_mode_map_dumb map_arg;
977
Peter Huttererf3d62272013-08-08 11:57:05 +1000978 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200979 if (!fb)
980 return NULL;
Daniel Stone6e7a9612017-04-04 17:54:26 +0100981 fb->refcnt = 1;
982
Daniel Stone0b70fa42017-04-04 17:54:23 +0100983 fb->format = pixel_format_get_info(format);
984 if (!fb->format) {
985 weston_log("failed to look up format 0x%lx\n",
986 (unsigned long) format);
987 goto err_fb;
988 }
989
990 if (!fb->format->depth || !fb->format->bpp) {
991 weston_log("format 0x%lx is not compatible with dumb buffers\n",
992 (unsigned long) format);
993 goto err_fb;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300994 }
995
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700996 memset(&create_arg, 0, sizeof create_arg);
Daniel Stone0b70fa42017-04-04 17:54:23 +0100997 create_arg.bpp = fb->format->bpp;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200998 create_arg.width = width;
999 create_arg.height = height;
1000
Giulio Camuffo954f1832014-10-11 18:27:30 +03001001 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001002 if (ret)
1003 goto err_fb;
1004
Daniel Stonefc175a72017-04-04 17:54:22 +01001005 fb->type = BUFFER_PIXMAN_DUMB;
Daniel Stone65a4dbc2016-12-08 16:36:18 +00001006 fb->modifier = DRM_FORMAT_MOD_INVALID;
Daniel Stone8eece0c2016-11-17 17:54:00 +00001007 fb->handles[0] = create_arg.handle;
1008 fb->strides[0] = create_arg.pitch;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001009 fb->size = create_arg.size;
Daniel Stonec8c917c2016-11-14 17:45:58 +00001010 fb->width = width;
1011 fb->height = height;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001012 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001013
Daniel Stone8eece0c2016-11-17 17:54:00 +00001014 if (drm_fb_addfb(fb) != 0) {
1015 weston_log("failed to create kms fb: %m\n");
1016 goto err_bo;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001017 }
1018
Kristian Høgsbergac6104e2013-08-21 22:14:14 -07001019 memset(&map_arg, 0, sizeof map_arg);
Daniel Stone8eece0c2016-11-17 17:54:00 +00001020 map_arg.handle = fb->handles[0];
Chris Michaeleb2074a2013-05-01 21:26:02 -04001021 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001022 if (ret)
1023 goto err_add_fb;
1024
Chris Michael4a7ce1f2015-11-10 10:40:37 -05001025 fb->map = mmap(NULL, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001026 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001027 if (fb->map == MAP_FAILED)
1028 goto err_add_fb;
1029
1030 return fb;
1031
1032err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +03001033 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001034err_bo:
1035 memset(&destroy_arg, 0, sizeof(destroy_arg));
1036 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001037 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001038err_fb:
1039 free(fb);
1040 return NULL;
1041}
1042
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001043static struct drm_fb *
Daniel Stone6e7a9612017-04-04 17:54:26 +01001044drm_fb_ref(struct drm_fb *fb)
1045{
1046 fb->refcnt++;
1047 return fb;
1048}
1049
Daniel Stonef522e222016-11-18 12:31:26 +00001050static void
1051drm_fb_destroy_dmabuf(struct drm_fb *fb)
1052{
1053 /* We deliberately do not close the GEM handles here; GBM manages
1054 * their lifetime through the BO. */
1055 if (fb->bo)
1056 gbm_bo_destroy(fb->bo);
1057 drm_fb_destroy(fb);
1058}
1059
1060static struct drm_fb *
1061drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
1062 struct drm_backend *backend, bool is_opaque)
1063{
1064#ifdef HAVE_GBM_FD_IMPORT
1065 struct drm_fb *fb;
1066 struct gbm_import_fd_data import_legacy = {
1067 .width = dmabuf->attributes.width,
1068 .height = dmabuf->attributes.height,
1069 .format = dmabuf->attributes.format,
1070 .stride = dmabuf->attributes.stride[0],
1071 .fd = dmabuf->attributes.fd[0],
1072 };
1073 struct gbm_import_fd_modifier_data import_mod = {
1074 .width = dmabuf->attributes.width,
1075 .height = dmabuf->attributes.height,
1076 .format = dmabuf->attributes.format,
1077 .num_fds = dmabuf->attributes.n_planes,
1078 .modifier = dmabuf->attributes.modifier[0],
1079 };
1080 int i;
1081
1082 /* XXX: TODO:
1083 *
1084 * Currently the buffer is rejected if any dmabuf attribute
1085 * flag is set. This keeps us from passing an inverted /
1086 * interlaced / bottom-first buffer (or any other type that may
1087 * be added in the future) through to an overlay. Ultimately,
1088 * these types of buffers should be handled through buffer
1089 * transforms and not as spot-checks requiring specific
1090 * knowledge. */
1091 if (dmabuf->attributes.flags)
1092 return NULL;
1093
1094 fb = zalloc(sizeof *fb);
1095 if (fb == NULL)
1096 return NULL;
1097
1098 fb->refcnt = 1;
1099 fb->type = BUFFER_DMABUF;
1100
1101 static_assert(ARRAY_LENGTH(import_mod.fds) ==
1102 ARRAY_LENGTH(dmabuf->attributes.fd),
1103 "GBM and linux_dmabuf FD size must match");
1104 static_assert(sizeof(import_mod.fds) == sizeof(dmabuf->attributes.fd),
1105 "GBM and linux_dmabuf FD size must match");
1106 memcpy(import_mod.fds, dmabuf->attributes.fd, sizeof(import_mod.fds));
1107
1108 static_assert(ARRAY_LENGTH(import_mod.strides) ==
1109 ARRAY_LENGTH(dmabuf->attributes.stride),
1110 "GBM and linux_dmabuf stride size must match");
1111 static_assert(sizeof(import_mod.strides) ==
1112 sizeof(dmabuf->attributes.stride),
1113 "GBM and linux_dmabuf stride size must match");
1114 memcpy(import_mod.strides, dmabuf->attributes.stride,
1115 sizeof(import_mod.strides));
1116
1117 static_assert(ARRAY_LENGTH(import_mod.offsets) ==
1118 ARRAY_LENGTH(dmabuf->attributes.offset),
1119 "GBM and linux_dmabuf offset size must match");
1120 static_assert(sizeof(import_mod.offsets) ==
1121 sizeof(dmabuf->attributes.offset),
1122 "GBM and linux_dmabuf offset size must match");
1123 memcpy(import_mod.offsets, dmabuf->attributes.offset,
1124 sizeof(import_mod.offsets));
1125
1126 /* The legacy FD-import path does not allow us to supply modifiers,
1127 * multiple planes, or buffer offsets. */
1128 if (dmabuf->attributes.modifier[0] != DRM_FORMAT_MOD_INVALID ||
1129 import_mod.num_fds > 1 ||
1130 import_mod.offsets[0] > 0) {
1131 fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
1132 &import_mod,
1133 GBM_BO_USE_SCANOUT);
1134 } else {
1135 fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD,
1136 &import_legacy,
1137 GBM_BO_USE_SCANOUT);
1138 }
1139
1140 if (!fb->bo)
1141 goto err_free;
1142
1143 fb->width = dmabuf->attributes.width;
1144 fb->height = dmabuf->attributes.height;
1145 fb->modifier = dmabuf->attributes.modifier[0];
1146 fb->size = 0;
1147 fb->fd = backend->drm.fd;
1148
1149 static_assert(ARRAY_LENGTH(fb->strides) ==
1150 ARRAY_LENGTH(dmabuf->attributes.stride),
1151 "drm_fb and dmabuf stride size must match");
1152 static_assert(sizeof(fb->strides) == sizeof(dmabuf->attributes.stride),
1153 "drm_fb and dmabuf stride size must match");
1154 memcpy(fb->strides, dmabuf->attributes.stride, sizeof(fb->strides));
1155 static_assert(ARRAY_LENGTH(fb->offsets) ==
1156 ARRAY_LENGTH(dmabuf->attributes.offset),
1157 "drm_fb and dmabuf offset size must match");
1158 static_assert(sizeof(fb->offsets) == sizeof(dmabuf->attributes.offset),
1159 "drm_fb and dmabuf offset size must match");
1160 memcpy(fb->offsets, dmabuf->attributes.offset, sizeof(fb->offsets));
1161
1162 fb->format = pixel_format_get_info(dmabuf->attributes.format);
1163 if (!fb->format) {
1164 weston_log("couldn't look up format info for 0x%lx\n",
1165 (unsigned long) dmabuf->attributes.format);
1166 goto err_free;
1167 }
1168
1169 if (is_opaque)
1170 fb->format = pixel_format_get_opaque_substitute(fb->format);
1171
1172 if (backend->min_width > fb->width ||
1173 fb->width > backend->max_width ||
1174 backend->min_height > fb->height ||
1175 fb->height > backend->max_height) {
1176 weston_log("bo geometry out of bounds\n");
1177 goto err_free;
1178 }
1179
1180 for (i = 0; i < dmabuf->attributes.n_planes; i++) {
1181 fb->handles[i] = gbm_bo_get_handle_for_plane(fb->bo, i).u32;
1182 if (!fb->handles[i])
1183 goto err_free;
1184 }
1185
1186 if (drm_fb_addfb(fb) != 0) {
1187 weston_log("failed to create kms fb: %m\n");
1188 goto err_free;
1189 }
1190
1191 return fb;
1192
1193err_free:
1194 drm_fb_destroy_dmabuf(fb);
1195#endif
1196 return NULL;
1197}
1198
Daniel Stone6e7a9612017-04-04 17:54:26 +01001199static struct drm_fb *
Daniel Stonefc175a72017-04-04 17:54:22 +01001200drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
Daniel Stonedb10df12016-12-08 13:15:58 +00001201 bool is_opaque, enum drm_fb_type type)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001202{
1203 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Daniel Stone244244d2016-11-18 18:02:08 +00001204#ifdef HAVE_GBM_MODIFIERS
1205 int i;
1206#endif
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001207
Daniel Stonefc175a72017-04-04 17:54:22 +01001208 if (fb) {
1209 assert(fb->type == type);
Daniel Stone6e7a9612017-04-04 17:54:26 +01001210 return drm_fb_ref(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +01001211 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001212
Bryce Harringtonde16d892014-11-20 22:21:57 -08001213 fb = zalloc(sizeof *fb);
1214 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001215 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001216
Daniel Stonefc175a72017-04-04 17:54:22 +01001217 fb->type = type;
Daniel Stone6e7a9612017-04-04 17:54:26 +01001218 fb->refcnt = 1;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001219 fb->bo = bo;
Daniel Stone244244d2016-11-18 18:02:08 +00001220 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001221
Daniel Stonec8c917c2016-11-14 17:45:58 +00001222 fb->width = gbm_bo_get_width(bo);
1223 fb->height = gbm_bo_get_height(bo);
Daniel Stone244244d2016-11-18 18:02:08 +00001224 fb->format = pixel_format_get_info(gbm_bo_get_format(bo));
1225 fb->size = 0;
1226
1227#ifdef HAVE_GBM_MODIFIERS
1228 fb->modifier = gbm_bo_get_modifier(bo);
1229 for (i = 0; i < gbm_bo_get_plane_count(bo); i++) {
1230 fb->strides[i] = gbm_bo_get_stride_for_plane(bo, i);
1231 fb->handles[i] = gbm_bo_get_handle_for_plane(bo, i).u32;
1232 fb->offsets[i] = gbm_bo_get_offset(bo, i);
1233 }
1234#else
Daniel Stone8eece0c2016-11-17 17:54:00 +00001235 fb->strides[0] = gbm_bo_get_stride(bo);
1236 fb->handles[0] = gbm_bo_get_handle(bo).u32;
Daniel Stone65a4dbc2016-12-08 16:36:18 +00001237 fb->modifier = DRM_FORMAT_MOD_INVALID;
Daniel Stone244244d2016-11-18 18:02:08 +00001238#endif
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001239
Daniel Stone0b70fa42017-04-04 17:54:23 +01001240 if (!fb->format) {
1241 weston_log("couldn't look up format 0x%lx\n",
Daniel Stonedb10df12016-12-08 13:15:58 +00001242 (unsigned long) gbm_bo_get_format(bo));
Daniel Stone0b70fa42017-04-04 17:54:23 +01001243 goto err_free;
1244 }
1245
Daniel Stonedb10df12016-12-08 13:15:58 +00001246 /* We can scanout an ARGB buffer if the surface's opaque region covers
1247 * the whole output, but we have to use XRGB as the KMS format code. */
1248 if (is_opaque)
1249 fb->format = pixel_format_get_opaque_substitute(fb->format);
1250
Daniel Stonec8c917c2016-11-14 17:45:58 +00001251 if (backend->min_width > fb->width ||
1252 fb->width > backend->max_width ||
1253 backend->min_height > fb->height ||
1254 fb->height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001255 weston_log("bo geometry out of bounds\n");
1256 goto err_free;
1257 }
1258
Daniel Stone8eece0c2016-11-17 17:54:00 +00001259 if (drm_fb_addfb(fb) != 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001260 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001261 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001262 }
1263
Tomohito Esaki576f42e2017-04-04 17:54:24 +01001264 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001265
1266 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001267
1268err_free:
1269 free(fb);
1270 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001271}
1272
1273static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001274drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001275{
Pekka Paalanende685b82012-12-04 15:58:12 +02001276 assert(fb->buffer_ref.buffer == NULL);
Daniel Stonef522e222016-11-18 12:31:26 +00001277 assert(fb->type == BUFFER_CLIENT || fb->type == BUFFER_DMABUF);
Pekka Paalanende685b82012-12-04 15:58:12 +02001278 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001279}
1280
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001281static void
Daniel Stone05a5ac22017-04-04 17:54:25 +01001282drm_fb_unref(struct drm_fb *fb)
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001283{
1284 if (!fb)
1285 return;
1286
Daniel Stone6e7a9612017-04-04 17:54:26 +01001287 assert(fb->refcnt > 0);
1288 if (--fb->refcnt > 0)
1289 return;
1290
Daniel Stonefc175a72017-04-04 17:54:22 +01001291 switch (fb->type) {
1292 case BUFFER_PIXMAN_DUMB:
Daniel Stone6e7a9612017-04-04 17:54:26 +01001293 drm_fb_destroy_dumb(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +01001294 break;
Daniel Stonee4256832017-04-04 17:54:27 +01001295 case BUFFER_CURSOR:
Daniel Stonefc175a72017-04-04 17:54:22 +01001296 case BUFFER_CLIENT:
1297 gbm_bo_destroy(fb->bo);
1298 break;
1299 case BUFFER_GBM_SURFACE:
Daniel Stone05a5ac22017-04-04 17:54:25 +01001300 gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
Daniel Stonefc175a72017-04-04 17:54:22 +01001301 break;
Daniel Stonef522e222016-11-18 12:31:26 +00001302 case BUFFER_DMABUF:
1303 drm_fb_destroy_dmabuf(fb);
1304 break;
Daniel Stonefc175a72017-04-04 17:54:22 +01001305 default:
1306 assert(NULL);
1307 break;
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001308 }
1309}
1310
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001311/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001312 * Allocate a new, empty, plane state.
1313 */
1314static struct drm_plane_state *
1315drm_plane_state_alloc(struct drm_output_state *state_output,
1316 struct drm_plane *plane)
1317{
1318 struct drm_plane_state *state = zalloc(sizeof(*state));
1319
1320 assert(state);
1321 state->output_state = state_output;
1322 state->plane = plane;
1323
1324 /* Here we only add the plane state to the desired link, and not
1325 * set the member. Having an output pointer set means that the
1326 * plane will be displayed on the output; this won't be the case
1327 * when we go to disable a plane. In this case, it must be part of
1328 * the commit (and thus the output state), but the member must be
1329 * NULL, as it will not be on any output when the state takes
1330 * effect.
1331 */
1332 if (state_output)
1333 wl_list_insert(&state_output->plane_list, &state->link);
1334 else
1335 wl_list_init(&state->link);
1336
1337 return state;
1338}
1339
1340/**
1341 * Free an existing plane state. As a special case, the state will not
1342 * normally be freed if it is the current state; see drm_plane_set_state.
1343 */
1344static void
1345drm_plane_state_free(struct drm_plane_state *state, bool force)
1346{
1347 if (!state)
1348 return;
1349
1350 wl_list_remove(&state->link);
1351 wl_list_init(&state->link);
1352 state->output_state = NULL;
1353
1354 if (force || state != state->plane->state_cur) {
1355 drm_fb_unref(state->fb);
1356 free(state);
1357 }
1358}
1359
1360/**
1361 * Duplicate an existing plane state into a new plane state, storing it within
1362 * the given output state. If the output state already contains a plane state
1363 * for the drm_plane referenced by 'src', that plane state is freed first.
1364 */
1365static struct drm_plane_state *
1366drm_plane_state_duplicate(struct drm_output_state *state_output,
1367 struct drm_plane_state *src)
1368{
1369 struct drm_plane_state *dst = malloc(sizeof(*dst));
1370 struct drm_plane_state *old, *tmp;
1371
1372 assert(src);
1373 assert(dst);
1374 *dst = *src;
1375 wl_list_init(&dst->link);
1376
1377 wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
1378 /* Duplicating a plane state into the same output state, so
1379 * it can replace itself with an identical copy of itself,
1380 * makes no sense. */
1381 assert(old != src);
1382 if (old->plane == dst->plane)
1383 drm_plane_state_free(old, false);
1384 }
1385
1386 wl_list_insert(&state_output->plane_list, &dst->link);
1387 if (src->fb)
1388 dst->fb = drm_fb_ref(src->fb);
1389 dst->output_state = state_output;
1390 dst->complete = false;
1391
1392 return dst;
1393}
1394
1395/**
1396 * Remove a plane state from an output state; if the plane was previously
1397 * enabled, then replace it with a disabling state. This ensures that the
1398 * output state was untouched from it was before the plane state was
1399 * modified by the caller of this function.
1400 *
1401 * This is required as drm_output_state_get_plane may either allocate a
1402 * new plane state, in which case this function will just perform a matching
1403 * drm_plane_state_free, or it may instead repurpose an existing disabling
1404 * state (if the plane was previously active), in which case this function
1405 * will reset it.
1406 */
1407static void
1408drm_plane_state_put_back(struct drm_plane_state *state)
1409{
1410 struct drm_output_state *state_output;
1411 struct drm_plane *plane;
1412
1413 if (!state)
1414 return;
1415
1416 state_output = state->output_state;
1417 plane = state->plane;
1418 drm_plane_state_free(state, false);
1419
1420 /* Plane was previously disabled; no need to keep this temporary
1421 * state around. */
1422 if (!plane->state_cur->fb)
1423 return;
1424
1425 (void) drm_plane_state_alloc(state_output, plane);
1426}
1427
Daniel Stonece137472016-11-16 19:35:03 +00001428static bool
1429drm_view_transform_supported(struct weston_view *ev, struct weston_output *output)
1430{
1431 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
1432
1433 /* This will incorrectly disallow cases where the combination of
1434 * buffer and view transformations match the output transform.
1435 * Fixing this requires a full analysis of the transformation
1436 * chain. */
1437 if (ev->transform.enabled &&
1438 ev->transform.matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE)
1439 return false;
1440
1441 if (viewport->buffer.transform != output->transform)
1442 return false;
1443
1444 return true;
1445}
1446
Daniel Stonebc15f682016-11-14 16:57:01 +00001447/**
Daniel Stoned6e2a762016-11-16 19:33:20 +00001448 * Given a weston_view, fill the drm_plane_state's co-ordinates to display on
1449 * a given plane.
1450 */
Daniel Stonece137472016-11-16 19:35:03 +00001451static bool
Daniel Stoned6e2a762016-11-16 19:33:20 +00001452drm_plane_state_coords_for_view(struct drm_plane_state *state,
1453 struct weston_view *ev)
1454{
1455 struct drm_output *output = state->output;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001456 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001457 pixman_region32_t dest_rect, src_rect;
1458 pixman_box32_t *box, tbox;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001459 float sxf1, syf1, sxf2, syf2;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001460
Daniel Stonece137472016-11-16 19:35:03 +00001461 if (!drm_view_transform_supported(ev, &output->base))
1462 return false;
1463
Daniel Stoned6e2a762016-11-16 19:33:20 +00001464 /* Update the base weston_plane co-ordinates. */
1465 box = pixman_region32_extents(&ev->transform.boundingbox);
1466 state->plane->base.x = box->x1;
1467 state->plane->base.y = box->y1;
1468
1469 /* First calculate the destination co-ordinates by taking the
1470 * area of the view which is visible on this output, performing any
1471 * transforms to account for output rotation and scale as necessary. */
1472 pixman_region32_init(&dest_rect);
1473 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
1474 &output->base.region);
1475 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
1476 box = pixman_region32_extents(&dest_rect);
1477 tbox = weston_transformed_rect(output->base.width,
1478 output->base.height,
1479 output->base.transform,
1480 output->base.current_scale,
1481 *box);
1482 state->dest_x = tbox.x1;
1483 state->dest_y = tbox.y1;
1484 state->dest_w = tbox.x2 - tbox.x1;
1485 state->dest_h = tbox.y2 - tbox.y1;
1486 pixman_region32_fini(&dest_rect);
1487
1488 /* Now calculate the source rectangle, by finding the extents of the
1489 * view, and working backwards to source co-ordinates. */
1490 pixman_region32_init(&src_rect);
1491 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
1492 &output->base.region);
1493 box = pixman_region32_extents(&src_rect);
Daniel Stonedf2726a2017-02-07 18:48:19 +00001494 weston_view_from_global_float(ev, box->x1, box->y1, &sxf1, &syf1);
1495 weston_surface_to_buffer_float(ev->surface, sxf1, syf1, &sxf1, &syf1);
1496 weston_view_from_global_float(ev, box->x2, box->y2, &sxf2, &syf2);
1497 weston_surface_to_buffer_float(ev->surface, sxf2, syf2, &sxf2, &syf2);
1498 pixman_region32_fini(&src_rect);
Daniel Stoned6e2a762016-11-16 19:33:20 +00001499
Daniel Stonedf2726a2017-02-07 18:48:19 +00001500 /* Buffer transforms may mean that x2 is to the left of x1, and/or that
1501 * y2 is above y1. */
1502 if (sxf2 < sxf1) {
1503 double tmp = sxf1;
1504 sxf1 = sxf2;
1505 sxf2 = tmp;
1506 }
1507 if (syf2 < syf1) {
1508 double tmp = syf1;
1509 syf1 = syf2;
1510 syf2 = tmp;
1511 }
1512
1513 /* Shift from S23.8 wl_fixed to U16.16 KMS fixed-point encoding. */
1514 state->src_x = wl_fixed_from_double(sxf1) << 8;
1515 state->src_y = wl_fixed_from_double(syf1) << 8;
1516 state->src_w = wl_fixed_from_double(sxf2 - sxf1) << 8;
1517 state->src_h = wl_fixed_from_double(syf2 - syf1) << 8;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001518
1519 /* Clamp our source co-ordinates to surface bounds; it's possible
1520 * for intermediate translations to give us slightly incorrect
1521 * co-ordinates if we have, for example, multiple zooming
1522 * transformations. View bounding boxes are also explicitly rounded
1523 * greedily. */
Daniel Stonedf2726a2017-02-07 18:48:19 +00001524 if (state->src_x < 0)
1525 state->src_x = 0;
1526 if (state->src_y < 0)
1527 state->src_y = 0;
1528 if (state->src_w > (uint32_t) ((buffer->width << 16) - state->src_x))
1529 state->src_w = (buffer->width << 16) - state->src_x;
1530 if (state->src_h > (uint32_t) ((buffer->height << 16) - state->src_y))
1531 state->src_h = (buffer->height << 16) - state->src_y;
Daniel Stonece137472016-11-16 19:35:03 +00001532
1533 return true;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001534}
1535
Daniel Stonef11ec022016-11-17 17:32:42 +00001536static bool
1537drm_view_is_opaque(struct weston_view *ev)
1538{
1539 pixman_region32_t r;
1540 bool ret = false;
1541
1542 pixman_region32_init_rect(&r, 0, 0,
1543 ev->surface->width,
1544 ev->surface->height);
1545 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
1546
1547 if (!pixman_region32_not_empty(&r))
1548 ret = true;
1549
1550 pixman_region32_fini(&r);
1551
1552 return ret;
1553}
1554
1555static struct drm_fb *
1556drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
1557{
1558 struct drm_output *output = state->output;
1559 struct drm_backend *b = to_drm_backend(output->base.compositor);
1560 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Daniel Stonef522e222016-11-18 12:31:26 +00001561 bool is_opaque = drm_view_is_opaque(ev);
Daniel Stonef11ec022016-11-17 17:32:42 +00001562 struct linux_dmabuf_buffer *dmabuf;
1563 struct drm_fb *fb;
Daniel Stonef11ec022016-11-17 17:32:42 +00001564
Daniel Stonef11ec022016-11-17 17:32:42 +00001565 if (ev->alpha != 1.0f)
1566 return NULL;
1567
1568 if (!drm_view_transform_supported(ev, &output->base))
1569 return NULL;
1570
1571 if (!buffer)
1572 return NULL;
1573
1574 if (wl_shm_buffer_get(buffer->resource))
1575 return NULL;
1576
Daniel Stonef522e222016-11-18 12:31:26 +00001577 /* GBM is used for dmabuf import as well as from client wl_buffer. */
Daniel Stonef11ec022016-11-17 17:32:42 +00001578 if (!b->gbm)
1579 return NULL;
1580
1581 dmabuf = linux_dmabuf_buffer_get(buffer->resource);
1582 if (dmabuf) {
Daniel Stonef522e222016-11-18 12:31:26 +00001583 fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque);
1584 if (!fb)
Daniel Stonef11ec022016-11-17 17:32:42 +00001585 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00001586 } else {
Daniel Stonef522e222016-11-18 12:31:26 +00001587 struct gbm_bo *bo;
1588
Daniel Stonef11ec022016-11-17 17:32:42 +00001589 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
1590 buffer->resource, GBM_BO_USE_SCANOUT);
Daniel Stonef522e222016-11-18 12:31:26 +00001591 if (!bo)
1592 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00001593
Daniel Stonef522e222016-11-18 12:31:26 +00001594 fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT);
1595 if (!fb) {
1596 gbm_bo_destroy(bo);
1597 return NULL;
1598 }
Daniel Stonef11ec022016-11-17 17:32:42 +00001599 }
1600
1601 drm_fb_set_buffer(fb, buffer);
1602 return fb;
1603}
1604
Daniel Stoned6e2a762016-11-16 19:33:20 +00001605/**
Daniel Stone2ba17f42015-05-19 20:02:41 +01001606 * Return a plane state from a drm_output_state.
1607 */
1608static struct drm_plane_state *
1609drm_output_state_get_existing_plane(struct drm_output_state *state_output,
1610 struct drm_plane *plane)
1611{
1612 struct drm_plane_state *ps;
1613
1614 wl_list_for_each(ps, &state_output->plane_list, link) {
1615 if (ps->plane == plane)
1616 return ps;
1617 }
1618
1619 return NULL;
1620}
1621
1622/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001623 * Return a plane state from a drm_output_state, either existing or
1624 * freshly allocated.
1625 */
1626static struct drm_plane_state *
1627drm_output_state_get_plane(struct drm_output_state *state_output,
1628 struct drm_plane *plane)
1629{
1630 struct drm_plane_state *ps;
1631
Daniel Stone2ba17f42015-05-19 20:02:41 +01001632 ps = drm_output_state_get_existing_plane(state_output, plane);
1633 if (ps)
1634 return ps;
Daniel Stonebc15f682016-11-14 16:57:01 +00001635
1636 return drm_plane_state_alloc(state_output, plane);
1637}
1638
1639/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001640 * Allocate a new, empty drm_output_state. This should not generally be used
1641 * in the repaint cycle; see drm_output_state_duplicate.
1642 */
1643static struct drm_output_state *
1644drm_output_state_alloc(struct drm_output *output,
1645 struct drm_pending_state *pending_state)
Daniel Stone90648872016-10-21 18:08:37 +01001646{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001647 struct drm_output_state *state = zalloc(sizeof(*state));
1648
1649 assert(state);
1650 state->output = output;
Daniel Stonea08512f2016-11-08 17:46:10 +00001651 state->dpms = WESTON_DPMS_OFF;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001652 state->pending_state = pending_state;
1653 if (pending_state)
1654 wl_list_insert(&pending_state->output_list, &state->link);
1655 else
1656 wl_list_init(&state->link);
1657
Daniel Stonebc15f682016-11-14 16:57:01 +00001658 wl_list_init(&state->plane_list);
1659
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001660 return state;
1661}
1662
1663/**
1664 * Duplicate an existing drm_output_state into a new one. This is generally
1665 * used during the repaint cycle, to capture the existing state of an output
1666 * and modify it to create a new state to be used.
1667 *
1668 * The mode determines whether the output will be reset to an a blank state,
1669 * or an exact mirror of the current state.
1670 */
1671static struct drm_output_state *
1672drm_output_state_duplicate(struct drm_output_state *src,
1673 struct drm_pending_state *pending_state,
1674 enum drm_output_state_duplicate_mode plane_mode)
1675{
1676 struct drm_output_state *dst = malloc(sizeof(*dst));
Daniel Stonebc15f682016-11-14 16:57:01 +00001677 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001678
1679 assert(dst);
1680
1681 /* Copy the whole structure, then individually modify the
1682 * pending_state, as well as the list link into our pending
1683 * state. */
1684 *dst = *src;
1685
1686 dst->pending_state = pending_state;
1687 if (pending_state)
1688 wl_list_insert(&pending_state->output_list, &dst->link);
1689 else
1690 wl_list_init(&dst->link);
1691
Daniel Stonebc15f682016-11-14 16:57:01 +00001692 wl_list_init(&dst->plane_list);
1693
1694 wl_list_for_each(ps, &src->plane_list, link) {
1695 /* Don't carry planes which are now disabled; these should be
1696 * free for other outputs to reuse. */
1697 if (!ps->output)
1698 continue;
1699
1700 if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
1701 (void) drm_plane_state_alloc(dst, ps->plane);
1702 else
1703 (void) drm_plane_state_duplicate(dst, ps);
1704 }
1705
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001706 return dst;
1707}
1708
1709/**
1710 * Free an unused drm_output_state.
1711 */
1712static void
1713drm_output_state_free(struct drm_output_state *state)
1714{
Daniel Stonebc15f682016-11-14 16:57:01 +00001715 struct drm_plane_state *ps, *next;
1716
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001717 if (!state)
1718 return;
1719
Daniel Stonebc15f682016-11-14 16:57:01 +00001720 wl_list_for_each_safe(ps, next, &state->plane_list, link)
1721 drm_plane_state_free(ps, false);
1722
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001723 wl_list_remove(&state->link);
Daniel Stonebc15f682016-11-14 16:57:01 +00001724
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001725 free(state);
Daniel Stone90648872016-10-21 18:08:37 +01001726}
1727
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001728/**
Daniel Stonea08512f2016-11-08 17:46:10 +00001729 * Get output state to disable output
1730 *
1731 * Returns a pointer to an output_state object which can be used to disable
1732 * an output (e.g. DPMS off).
1733 *
1734 * @param pending_state The pending state object owning this update
1735 * @param output The output to disable
1736 * @returns A drm_output_state to disable the output
1737 */
1738static struct drm_output_state *
1739drm_output_get_disable_state(struct drm_pending_state *pending_state,
1740 struct drm_output *output)
1741{
1742 struct drm_output_state *output_state;
1743
1744 output_state = drm_output_state_duplicate(output->state_cur,
1745 pending_state,
1746 DRM_OUTPUT_STATE_CLEAR_PLANES);
1747 output_state->dpms = WESTON_DPMS_OFF;
1748
1749 return output_state;
1750}
1751
1752/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001753 * Allocate a new drm_pending_state
1754 *
1755 * Allocate a new, empty, 'pending state' structure to be used across a
1756 * repaint cycle or similar.
1757 *
1758 * @param backend DRM backend
1759 * @returns Newly-allocated pending state structure
1760 */
1761static struct drm_pending_state *
1762drm_pending_state_alloc(struct drm_backend *backend)
1763{
1764 struct drm_pending_state *ret;
1765
1766 ret = calloc(1, sizeof(*ret));
1767 if (!ret)
1768 return NULL;
1769
1770 ret->backend = backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001771 wl_list_init(&ret->output_list);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001772
1773 return ret;
1774}
1775
1776/**
1777 * Free a drm_pending_state structure
1778 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001779 * Frees a pending_state structure, as well as any output_states connected
1780 * to this pending state.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001781 *
1782 * @param pending_state Pending state structure to free
1783 */
1784static void
1785drm_pending_state_free(struct drm_pending_state *pending_state)
1786{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001787 struct drm_output_state *output_state, *tmp;
1788
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001789 if (!pending_state)
1790 return;
1791
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001792 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1793 link) {
1794 drm_output_state_free(output_state);
1795 }
1796
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001797 free(pending_state);
1798}
1799
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001800/**
1801 * Find an output state in a pending state
1802 *
1803 * Given a pending_state structure, find the output_state for a particular
1804 * output.
1805 *
1806 * @param pending_state Pending state structure to search
1807 * @param output Output to find state for
1808 * @returns Output state if present, or NULL if not
1809 */
1810static struct drm_output_state *
1811drm_pending_state_get_output(struct drm_pending_state *pending_state,
1812 struct drm_output *output)
1813{
1814 struct drm_output_state *output_state;
1815
1816 wl_list_for_each(output_state, &pending_state->output_list, link) {
1817 if (output_state->output == output)
1818 return output_state;
1819 }
1820
1821 return NULL;
1822}
1823
Daniel Stonea08512f2016-11-08 17:46:10 +00001824static int drm_pending_state_apply_sync(struct drm_pending_state *state);
1825
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001826/**
1827 * Mark a drm_output_state (the output's last state) as complete. This handles
1828 * any post-completion actions such as updating the repaint timer, disabling the
1829 * output, and finally freeing the state.
1830 */
1831static void
1832drm_output_update_complete(struct drm_output *output, uint32_t flags,
1833 unsigned int sec, unsigned int usec)
1834{
Daniel Stonea08512f2016-11-08 17:46:10 +00001835 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001836 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001837 struct timespec ts;
1838
1839 /* Stop the pageflip timer instead of rearming it here */
1840 if (output->pageflip_timer)
1841 wl_event_source_timer_update(output->pageflip_timer, 0);
1842
Daniel Stonebc15f682016-11-14 16:57:01 +00001843 wl_list_for_each(ps, &output->state_cur->plane_list, link)
1844 ps->complete = true;
1845
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001846 drm_output_state_free(output->state_last);
1847 output->state_last = NULL;
1848
1849 if (output->destroy_pending) {
Daniel Stonea08512f2016-11-08 17:46:10 +00001850 output->destroy_pending = 0;
1851 output->disable_pending = 0;
1852 output->dpms_off_pending = 0;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001853 drm_output_destroy(&output->base);
1854 return;
1855 } else if (output->disable_pending) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001856 output->disable_pending = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00001857 output->dpms_off_pending = 0;
1858 weston_output_disable(&output->base);
1859 return;
1860 } else if (output->dpms_off_pending) {
1861 struct drm_pending_state *pending = drm_pending_state_alloc(b);
1862 output->dpms_off_pending = 0;
1863 drm_output_get_disable_state(pending, output);
1864 drm_pending_state_apply_sync(pending);
1865 return;
1866 } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
1867 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
1868 /* DPMS can happen to us either in the middle of a repaint
1869 * cycle (when we have painted fresh content, only to throw it
1870 * away for DPMS off), or at any other random point. If the
1871 * latter is true, then we cannot go through finish_frame,
1872 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001873 return;
1874 }
1875
1876 ts.tv_sec = sec;
1877 ts.tv_nsec = usec * 1000;
1878 weston_output_finish_frame(&output->base, &ts, flags);
1879
1880 /* We can't call this from frame_notify, because the output's
1881 * repaint needed flag is cleared just after that */
1882 if (output->recorder)
1883 weston_output_schedule_repaint(&output->base);
1884}
1885
1886/**
1887 * Mark an output state as current on the output, i.e. it has been
1888 * submitted to the kernel. The mode argument determines whether this
1889 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
1890 * or asynchronously (in which case we wait for events to complete).
1891 */
1892static void
1893drm_output_assign_state(struct drm_output_state *state,
1894 enum drm_state_apply_mode mode)
1895{
1896 struct drm_output *output = state->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00001897 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001898 struct drm_plane_state *plane_state;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001899
1900 assert(!output->state_last);
1901
1902 if (mode == DRM_STATE_APPLY_ASYNC)
1903 output->state_last = output->state_cur;
1904 else
1905 drm_output_state_free(output->state_cur);
1906
1907 wl_list_remove(&state->link);
1908 wl_list_init(&state->link);
1909 state->pending_state = NULL;
1910
1911 output->state_cur = state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001912
Daniel Stone598ee9d2016-11-16 11:55:20 +00001913 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC)
1914 output->atomic_complete_pending = 1;
1915
Daniel Stonebc15f682016-11-14 16:57:01 +00001916 /* Replace state_cur on each affected plane with the new state, being
1917 * careful to dispose of orphaned (but only orphaned) previous state.
1918 * If the previous state is not orphaned (still has an output_state
1919 * attached), it will be disposed of by freeing the output_state. */
1920 wl_list_for_each(plane_state, &state->plane_list, link) {
1921 struct drm_plane *plane = plane_state->plane;
1922
1923 if (plane->state_cur && !plane->state_cur->output_state)
1924 drm_plane_state_free(plane->state_cur, true);
1925 plane->state_cur = plane_state;
1926
1927 if (mode != DRM_STATE_APPLY_ASYNC) {
1928 plane_state->complete = true;
1929 continue;
1930 }
1931
Daniel Stone598ee9d2016-11-16 11:55:20 +00001932 if (b->atomic_modeset)
1933 continue;
1934
Daniel Stonebc15f682016-11-14 16:57:01 +00001935 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
1936 output->vblank_pending++;
Daniel Stonee2e80132018-01-16 15:37:33 +00001937 else if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
1938 output->page_flip_pending = 1;
Daniel Stonebc15f682016-11-14 16:57:01 +00001939 }
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001940}
1941
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001942static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001943drm_output_prepare_scanout_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001944 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001945{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001946 struct drm_output *output = output_state->output;
Daniel Stone44abfaa2018-07-10 14:31:06 +01001947 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00001948 struct drm_plane *scanout_plane = output->scanout_plane;
1949 struct drm_plane_state *state;
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001950 struct drm_fb *fb;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001951 pixman_box32_t *extents;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001952
Daniel Stone44abfaa2018-07-10 14:31:06 +01001953 assert(!b->sprites_are_broken);
1954
Daniel Stone7cdf2312016-11-16 19:40:29 +00001955 /* Check the view spans exactly the output size, calculated in the
1956 * logical co-ordinate space. */
1957 extents = pixman_region32_extents(&ev->transform.boundingbox);
1958 if (extents->x1 != output->base.x ||
1959 extents->y1 != output->base.y ||
1960 extents->x2 != output->base.x + output->base.width ||
1961 extents->y2 != output->base.y + output->base.height)
Daniel Stone90648872016-10-21 18:08:37 +01001962 return NULL;
1963
1964 if (ev->alpha != 1.0f)
1965 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001966
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001967 fb = drm_fb_get_from_view(output_state, ev);
1968 if (!fb)
1969 return NULL;
1970
1971 /* Can't change formats with just a pageflip */
1972 if (fb->format->format != output->gbm_format) {
1973 drm_fb_unref(fb);
1974 return NULL;
1975 }
1976
Daniel Stonee2e80132018-01-16 15:37:33 +00001977 state = drm_output_state_get_plane(output_state, scanout_plane);
1978 if (state->fb) {
1979 /* If there is already a framebuffer on the scanout plane,
1980 * a client view has already been placed on the scanout
1981 * view. In that case, do not free or put back the state,
1982 * but just leave it in place and quietly exit. */
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001983 drm_fb_unref(fb);
Daniel Stonee2e80132018-01-16 15:37:33 +00001984 return NULL;
1985 }
1986
Daniel Stonebdf3e7e2016-11-17 17:33:08 +00001987 state->fb = fb;
Daniel Stoneee1aea72017-12-18 13:41:09 +00001988 state->ev = ev;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001989 state->output = output;
1990 if (!drm_plane_state_coords_for_view(state, ev))
1991 goto err;
1992
1993 /* The legacy API does not let us perform cropping or scaling. */
1994 if (state->src_x != 0 || state->src_y != 0 ||
1995 state->src_w != state->dest_w << 16 ||
1996 state->src_h != state->dest_h << 16 ||
1997 state->dest_x != 0 || state->dest_y != 0 ||
1998 state->dest_w != (unsigned) output->base.current_mode->width ||
1999 state->dest_h != (unsigned) output->base.current_mode->height)
2000 goto err;
2001
Daniel Stonee2e80132018-01-16 15:37:33 +00002002 return &scanout_plane->base;
Daniel Stone7cdf2312016-11-16 19:40:29 +00002003
2004err:
2005 drm_plane_state_put_back(state);
2006 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05002007}
2008
Daniel Stone95d48a22017-04-04 17:54:30 +01002009static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002010drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002011{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002012 struct drm_output *output = state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02002013 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002014 struct gbm_bo *bo;
Daniel Stone95d48a22017-04-04 17:54:30 +01002015 struct drm_fb *ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002016
Giulio Camuffo954f1832014-10-11 18:27:30 +03002017 output->base.compositor->renderer->repaint_output(&output->base,
2018 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002019
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01002020 bo = gbm_surface_lock_front_buffer(output->gbm_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002021 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +02002022 weston_log("failed to lock front buffer: %m\n");
Daniel Stone95d48a22017-04-04 17:54:30 +01002023 return NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002024 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002025
Daniel Stonedb10df12016-12-08 13:15:58 +00002026 /* The renderer always produces an opaque image. */
2027 ret = drm_fb_get_from_bo(bo, b, true, BUFFER_GBM_SURFACE);
Daniel Stone95d48a22017-04-04 17:54:30 +01002028 if (!ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002029 weston_log("failed to get drm_fb for bo\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01002030 gbm_surface_release_buffer(output->gbm_surface, bo);
Daniel Stone95d48a22017-04-04 17:54:30 +01002031 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002032 }
Daniel Stone95d48a22017-04-04 17:54:30 +01002033 ret->gbm_surface = output->gbm_surface;
2034
2035 return ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002036}
2037
Daniel Stone95d48a22017-04-04 17:54:30 +01002038static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002039drm_output_render_pixman(struct drm_output_state *state,
2040 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002041{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002042 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002043 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002044
2045 output->current_image ^= 1;
2046
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002047 pixman_renderer_output_set_buffer(&output->base,
2048 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +02002049 pixman_renderer_output_set_hw_extra_damage(&output->base,
2050 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002051
Pekka Paalanenacf50c32018-04-23 11:44:56 +02002052 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002053
Pekka Paalanenacf50c32018-04-23 11:44:56 +02002054 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +01002055
2056 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002057}
2058
2059static void
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002060drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002061{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002062 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002063 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +00002064 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +00002065 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02002066 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +01002067 struct drm_fb *fb;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002068
Daniel Stone4e84f7d2017-04-04 17:54:29 +01002069 /* If we already have a client buffer promoted to scanout, then we don't
2070 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +00002071 scanout_state = drm_output_state_get_plane(state,
2072 output->scanout_plane);
2073 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +01002074 return;
2075
Daniel Stonee95169b2016-11-14 17:46:59 +00002076 if (!pixman_region32_not_empty(damage) &&
2077 scanout_plane->state_cur->fb &&
2078 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
2079 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
2080 scanout_plane->state_cur->fb->width ==
2081 output->base.current_mode->width &&
2082 scanout_plane->state_cur->fb->height ==
2083 output->base.current_mode->height) {
2084 fb = drm_fb_ref(scanout_plane->state_cur->fb);
2085 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002086 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00002087 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002088 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00002089 }
Daniel Stone95d48a22017-04-04 17:54:30 +01002090
Daniel Stonee2e80132018-01-16 15:37:33 +00002091 if (!fb) {
2092 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +01002093 return;
Daniel Stonee2e80132018-01-16 15:37:33 +00002094 }
2095
2096 scanout_state->fb = fb;
2097 scanout_state->output = output;
2098
2099 scanout_state->src_x = 0;
2100 scanout_state->src_y = 0;
2101 scanout_state->src_w = output->base.current_mode->width << 16;
2102 scanout_state->src_h = output->base.current_mode->height << 16;
2103
2104 scanout_state->dest_x = 0;
2105 scanout_state->dest_y = 0;
2106 scanout_state->dest_w = scanout_state->src_w >> 16;
2107 scanout_state->dest_h = scanout_state->src_h >> 16;
2108
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002109
Giulio Camuffo954f1832014-10-11 18:27:30 +03002110 pixman_region32_subtract(&c->primary_plane.damage,
2111 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002112}
2113
2114static void
Richard Hughese7299962013-05-01 21:52:12 +01002115drm_output_set_gamma(struct weston_output *output_base,
2116 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
2117{
2118 int rc;
Armin Krezović545dba62016-08-05 15:54:18 +02002119 struct drm_output *output = to_drm_output(output_base);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002120 struct drm_backend *backend =
Armin Krezović545dba62016-08-05 15:54:18 +02002121 to_drm_backend(output->base.compositor);
Richard Hughese7299962013-05-01 21:52:12 +01002122
2123 /* check */
2124 if (output_base->gamma_size != size)
2125 return;
Richard Hughese7299962013-05-01 21:52:12 +01002126
Giulio Camuffo954f1832014-10-11 18:27:30 +03002127 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +01002128 output->crtc_id,
2129 size, r, g, b);
2130 if (rc)
2131 weston_log("set gamma failed: %m\n");
2132}
2133
Bryce Harringtonada4f072015-06-30 13:25:46 -07002134/* Determine the type of vblank synchronization to use for the output.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002135 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07002136 * The pipe parameter indicates which CRTC is in use. Knowing this, we
2137 * can determine which vblank sequence type to use for it. Traditional
2138 * cards had only two CRTCs, with CRTC 0 using no special flags, and
2139 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
2140 * parameter indicates this.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002141 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07002142 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
2143 * 0-31. If this is non-zero it indicates we're dealing with a
2144 * multi-gpu situation and we need to calculate the vblank sync
2145 * using DRM_BLANK_HIGH_CRTC_MASK.
2146 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +03002147static unsigned int
2148drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02002149{
2150 if (output->pipe > 1)
2151 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
2152 DRM_VBLANK_HIGH_CRTC_MASK;
2153 else if (output->pipe > 0)
2154 return DRM_VBLANK_SECONDARY;
2155 else
2156 return 0;
2157}
2158
David Herrmann1edf44c2013-10-22 17:11:26 +02002159static int
Daniel Stone598ee9d2016-11-16 11:55:20 +00002160drm_output_apply_state_legacy(struct drm_output_state *state)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002161{
Daniel Stonea08512f2016-11-08 17:46:10 +00002162 struct drm_output *output = state->output;
2163 struct drm_backend *backend = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00002164 struct drm_plane *scanout_plane = output->scanout_plane;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002165 struct drm_property_info *dpms_prop;
Daniel Stonee2e80132018-01-16 15:37:33 +00002166 struct drm_plane_state *scanout_state;
Daniel Stonebc15f682016-11-14 16:57:01 +00002167 struct drm_plane_state *ps;
Daniel Stone085d2b92015-05-21 00:00:57 +01002168 struct drm_plane *p;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002169 struct drm_mode *mode;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002170 struct drm_head *head;
2171 uint32_t connectors[MAX_CLONED_CONNECTORS];
2172 int n_conn = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00002173 struct timespec now;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002174 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002175
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002176 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2177 assert(n_conn < MAX_CLONED_CONNECTORS);
2178 connectors[n_conn++] = head->connector_id;
2179 }
2180
Derek Foreman2cd87fe2017-04-13 13:48:48 -05002181 /* If disable_planes is set then assign_planes() wasn't
2182 * called for this render, so we could still have a stale
2183 * cursor plane set up.
2184 */
2185 if (output->base.disable_planes) {
2186 output->cursor_view = NULL;
Greg V1f781762018-02-19 17:59:42 +03002187 if (output->cursor_plane) {
2188 output->cursor_plane->base.x = INT32_MIN;
2189 output->cursor_plane->base.y = INT32_MIN;
2190 }
Derek Foreman2cd87fe2017-04-13 13:48:48 -05002191 }
2192
Daniel Stonea08512f2016-11-08 17:46:10 +00002193 if (state->dpms != WESTON_DPMS_ON) {
2194 wl_list_for_each(ps, &state->plane_list, link) {
2195 p = ps->plane;
2196 assert(ps->fb == NULL);
2197 assert(ps->output == NULL);
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002198
Daniel Stonea08512f2016-11-08 17:46:10 +00002199 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2200 continue;
2201
2202 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
2203 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2204 if (ret)
2205 weston_log("drmModeSetPlane failed disable: %m\n");
2206 }
2207
2208 if (output->cursor_plane) {
2209 ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
2210 0, 0, 0);
2211 if (ret)
2212 weston_log("drmModeSetCursor failed disable: %m\n");
2213 }
2214
2215 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002216 NULL, 0, NULL);
Daniel Stonea08512f2016-11-08 17:46:10 +00002217 if (ret)
2218 weston_log("drmModeSetCrtc failed disabling: %m\n");
2219
2220 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
2221 weston_compositor_read_presentation_clock(output->base.compositor, &now);
2222 drm_output_update_complete(output,
2223 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
2224 now.tv_sec, now.tv_nsec / 1000);
2225
2226 return 0;
2227 }
2228
2229 scanout_state =
2230 drm_output_state_get_existing_plane(state, scanout_plane);
Daniel Stone087ddf02017-02-14 17:51:30 +00002231
Daniel Stonee2e80132018-01-16 15:37:33 +00002232 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
2233 * legacy PageFlip API doesn't allow us to do clipping either. */
2234 assert(scanout_state->src_x == 0);
2235 assert(scanout_state->src_y == 0);
2236 assert(scanout_state->src_w ==
2237 (unsigned) (output->base.current_mode->width << 16));
2238 assert(scanout_state->src_h ==
2239 (unsigned) (output->base.current_mode->height << 16));
2240 assert(scanout_state->dest_x == 0);
2241 assert(scanout_state->dest_y == 0);
2242 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
2243 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
2244
Daniel Stonecb04cc42016-11-16 11:51:27 +00002245 mode = to_drm_mode(output->base.current_mode);
Daniel Stone8eece0c2016-11-17 17:54:00 +00002246 if (backend->state_invalid ||
2247 !scanout_plane->state_cur->fb ||
2248 scanout_plane->state_cur->fb->strides[0] !=
2249 scanout_state->fb->strides[0]) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002250 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00002251 scanout_state->fb->fb_id,
2252 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002253 connectors, n_conn,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002254 &mode->mode_info);
2255 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002256 weston_log("set mode failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002257 goto err;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002258 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02002259 }
2260
Giulio Camuffo954f1832014-10-11 18:27:30 +03002261 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00002262 scanout_state->fb->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05002263 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002264 weston_log("queueing pageflip failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002265 goto err;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05002266 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002267
Daniel Stone205c0a02017-04-04 17:54:33 +01002268 assert(!output->page_flip_pending);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002269
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002270 if (output->pageflip_timer)
2271 wl_event_source_timer_update(output->pageflip_timer,
2272 backend->pageflip_timeout);
2273
Daniel Stone2ba17f42015-05-19 20:02:41 +01002274 drm_output_set_cursor(state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04002275
Jesse Barnes58ef3792012-02-23 09:45:49 -05002276 /*
2277 * Now, update all the sprite surfaces
2278 */
Daniel Stonebc15f682016-11-14 16:57:01 +00002279 wl_list_for_each(ps, &state->plane_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002280 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002281 drmVBlank vbl = {
2282 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
2283 .request.sequence = 1,
2284 };
2285
Daniel Stonebc15f682016-11-14 16:57:01 +00002286 p = ps->plane;
Daniel Stone085d2b92015-05-21 00:00:57 +01002287 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002288 continue;
2289
Daniel Stonebc15f682016-11-14 16:57:01 +00002290 assert(p->state_cur->complete);
2291 assert(!!p->state_cur->output == !!p->state_cur->fb);
2292 assert(!p->state_cur->output || p->state_cur->output == output);
2293 assert(!ps->complete);
2294 assert(!ps->output || ps->output == output);
2295 assert(!!ps->output == !!ps->fb);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002296
Daniel Stonebc15f682016-11-14 16:57:01 +00002297 if (ps->fb && !backend->sprites_hidden)
2298 fb_id = ps->fb->fb_id;
Daniel Stone085d2b92015-05-21 00:00:57 +01002299
2300 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002301 output->crtc_id, fb_id, flags,
Daniel Stonebc15f682016-11-14 16:57:01 +00002302 ps->dest_x, ps->dest_y,
2303 ps->dest_w, ps->dest_h,
2304 ps->src_x, ps->src_y,
2305 ps->src_w, ps->src_h);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002306 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +02002307 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002308 ret, strerror(errno));
2309
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02002310 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -05002311
Jesse Barnes58ef3792012-02-23 09:45:49 -05002312 /*
2313 * Queue a vblank signal so we know when the surface
2314 * becomes active on the display or has been replaced.
2315 */
Daniel Stonebc15f682016-11-14 16:57:01 +00002316 vbl.request.signal = (unsigned long) ps;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002317 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002318 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002319 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002320 ret, strerror(errno));
2321 }
2322 }
2323
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002324 if (state->dpms != output->state_cur->dpms) {
2325 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2326 dpms_prop = &head->props_conn[WDRM_CONNECTOR_DPMS];
2327 if (dpms_prop->prop_id == 0)
2328 continue;
2329
2330 ret = drmModeConnectorSetProperty(backend->drm.fd,
2331 head->connector_id,
2332 dpms_prop->prop_id,
2333 state->dpms);
2334 if (ret) {
2335 weston_log("DRM: DPMS: failed property set for %s\n",
2336 head->base.name);
2337 }
Daniel Stonea08512f2016-11-08 17:46:10 +00002338 }
2339 }
2340
2341 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
2342
David Herrmann1edf44c2013-10-22 17:11:26 +02002343 return 0;
2344
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002345err:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -08002346 output->cursor_view = NULL;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002347 drm_output_state_free(state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002348 return -1;
2349}
David Herrmann1edf44c2013-10-22 17:11:26 +02002350
Daniel Stone598ee9d2016-11-16 11:55:20 +00002351#ifdef HAVE_DRM_ATOMIC
2352static int
2353crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
2354 enum wdrm_crtc_property prop, uint64_t val)
2355{
2356 struct drm_property_info *info = &output->props_crtc[prop];
2357 int ret;
2358
2359 if (info->prop_id == 0)
2360 return -1;
2361
2362 ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
2363 val);
2364 return (ret <= 0) ? -1 : 0;
2365}
2366
2367static int
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002368connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002369 enum wdrm_connector_property prop, uint64_t val)
2370{
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002371 struct drm_property_info *info = &head->props_conn[prop];
Daniel Stone598ee9d2016-11-16 11:55:20 +00002372 int ret;
2373
2374 if (info->prop_id == 0)
2375 return -1;
2376
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002377 ret = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002378 info->prop_id, val);
2379 return (ret <= 0) ? -1 : 0;
2380}
2381
2382static int
2383plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
2384 enum wdrm_plane_property prop, uint64_t val)
2385{
2386 struct drm_property_info *info = &plane->props[prop];
2387 int ret;
2388
2389 if (info->prop_id == 0)
2390 return -1;
2391
2392 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
2393 val);
2394 return (ret <= 0) ? -1 : 0;
2395}
2396
2397static int
2398drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
2399{
2400 int ret;
2401
2402 if (mode->blob_id)
2403 return 0;
2404
2405 ret = drmModeCreatePropertyBlob(backend->drm.fd,
2406 &mode->mode_info,
2407 sizeof(mode->mode_info),
2408 &mode->blob_id);
2409 if (ret != 0)
2410 weston_log("failed to create mode property blob: %m\n");
2411
2412 return ret;
2413}
2414
2415static int
2416drm_output_apply_state_atomic(struct drm_output_state *state,
2417 drmModeAtomicReq *req,
2418 uint32_t *flags)
2419{
2420 struct drm_output *output = state->output;
2421 struct drm_backend *backend = to_drm_backend(output->base.compositor);
2422 struct drm_plane_state *plane_state;
2423 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002424 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002425 int ret = 0;
2426
2427 if (state->dpms != output->state_cur->dpms)
2428 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2429
2430 if (state->dpms == WESTON_DPMS_ON) {
2431 ret = drm_mode_ensure_blob(backend, current_mode);
2432 if (ret != 0)
2433 return ret;
2434
2435 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
2436 current_mode->blob_id);
2437 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002438
Daniel Stone76255772018-07-06 11:36:49 +01002439 /* No need for the DPMS property, since it is implicit in
2440 * routing and CRTC activity. */
Pekka Paalanen2f661302017-09-12 16:07:32 +03002441 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2442 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
2443 output->crtc_id);
2444 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00002445 } else {
2446 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
2447 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002448
Daniel Stone76255772018-07-06 11:36:49 +01002449 /* No need for the DPMS property, since it is implicit in
2450 * routing and CRTC activity. */
Pekka Paalanen2f661302017-09-12 16:07:32 +03002451 wl_list_for_each(head, &output->base.head_list, base.output_link)
2452 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002453 }
2454
2455 if (ret != 0) {
2456 weston_log("couldn't set atomic CRTC/connector state\n");
2457 return ret;
2458 }
2459
2460 wl_list_for_each(plane_state, &state->plane_list, link) {
2461 struct drm_plane *plane = plane_state->plane;
2462
2463 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
2464 plane_state->fb ? plane_state->fb->fb_id : 0);
2465 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
2466 plane_state->fb ? output->crtc_id : 0);
2467 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
2468 plane_state->src_x);
2469 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
2470 plane_state->src_y);
2471 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
2472 plane_state->src_w);
2473 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
2474 plane_state->src_h);
2475 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
2476 plane_state->dest_x);
2477 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
2478 plane_state->dest_y);
2479 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
2480 plane_state->dest_w);
2481 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
2482 plane_state->dest_h);
2483
2484 if (ret != 0) {
2485 weston_log("couldn't set plane state\n");
2486 return ret;
2487 }
2488 }
2489
2490 return 0;
2491}
2492
2493/**
2494 * Helper function used only by drm_pending_state_apply, with the same
2495 * guarantees and constraints as that function.
2496 */
2497static int
2498drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
2499 enum drm_state_apply_mode mode)
2500{
2501 struct drm_backend *b = pending_state->backend;
2502 struct drm_output_state *output_state, *tmp;
2503 struct drm_plane *plane;
2504 drmModeAtomicReq *req = drmModeAtomicAlloc();
2505 uint32_t flags = 0;
2506 int ret = 0;
2507
2508 if (!req)
2509 return -1;
2510
2511 if (b->state_invalid) {
Pekka Paalaneneacec812017-09-12 13:43:51 +03002512 struct weston_head *head_base;
2513 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002514 uint32_t *unused;
2515 int err;
2516
2517 /* If we need to reset all our state (e.g. because we've
2518 * just started, or just been VT-switched in), explicitly
2519 * disable all the CRTCs and connectors we aren't using. */
Pekka Paalaneneacec812017-09-12 13:43:51 +03002520 wl_list_for_each(head_base,
2521 &b->compositor->head_list, compositor_link) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00002522 struct drm_property_info *info;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002523
Pekka Paalaneneacec812017-09-12 13:43:51 +03002524 if (weston_head_is_enabled(head_base))
Daniel Stone598ee9d2016-11-16 11:55:20 +00002525 continue;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002526
Pekka Paalaneneacec812017-09-12 13:43:51 +03002527 head = to_drm_head(head_base);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002528
Pekka Paalaneneacec812017-09-12 13:43:51 +03002529 info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
2530 err = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002531 info->prop_id, 0);
2532 if (err <= 0)
2533 ret = -1;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002534 }
2535
2536 wl_array_for_each(unused, &b->unused_crtcs) {
2537 struct drm_property_info infos[WDRM_CRTC__COUNT];
2538 struct drm_property_info *info;
2539 drmModeObjectProperties *props;
2540 uint64_t active;
2541
2542 memset(infos, 0, sizeof(infos));
2543
2544 /* We can't emit a disable on a CRTC that's already
2545 * off, as the kernel will refuse to generate an event
2546 * for an off->off state and fail the commit.
2547 */
2548 props = drmModeObjectGetProperties(b->drm.fd,
2549 *unused,
2550 DRM_MODE_OBJECT_CRTC);
2551 if (!props) {
2552 ret = -1;
2553 continue;
2554 }
2555
2556 drm_property_info_populate(b, crtc_props, infos,
2557 WDRM_CRTC__COUNT,
2558 props);
2559
2560 info = &infos[WDRM_CRTC_ACTIVE];
2561 active = drm_property_get_value(info, props, 0);
2562 drmModeFreeObjectProperties(props);
2563 if (active == 0) {
2564 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2565 continue;
2566 }
2567
2568 err = drmModeAtomicAddProperty(req, *unused,
2569 info->prop_id, 0);
2570 if (err <= 0)
2571 ret = -1;
2572
2573 info = &infos[WDRM_CRTC_MODE_ID];
2574 err = drmModeAtomicAddProperty(req, *unused,
2575 info->prop_id, 0);
2576 if (err <= 0)
2577 ret = -1;
2578
2579 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2580 }
2581
2582 /* Disable all the planes; planes which are being used will
2583 * override this state in the output-state application. */
2584 wl_list_for_each(plane, &b->plane_list, link) {
2585 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
2586 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
2587 }
2588
2589 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2590 }
2591
2592 wl_list_for_each(output_state, &pending_state->output_list, link) {
2593 if (mode == DRM_STATE_APPLY_SYNC)
2594 assert(output_state->dpms == WESTON_DPMS_OFF);
2595 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
2596 }
2597
2598 if (ret != 0) {
2599 weston_log("atomic: couldn't compile atomic state\n");
2600 goto out;
2601 }
2602
2603 switch (mode) {
2604 case DRM_STATE_APPLY_SYNC:
2605 break;
2606 case DRM_STATE_APPLY_ASYNC:
2607 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
2608 break;
2609 }
2610
2611 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
2612 if (ret != 0) {
2613 weston_log("atomic: couldn't commit new state: %m\n");
2614 goto out;
2615 }
2616
2617 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2618 link)
2619 drm_output_assign_state(output_state, mode);
2620
2621 b->state_invalid = false;
2622
2623 assert(wl_list_empty(&pending_state->output_list));
2624
2625out:
2626 drmModeAtomicFree(req);
2627 drm_pending_state_free(pending_state);
2628 return ret;
2629}
2630#endif
2631
Daniel Stonea08512f2016-11-08 17:46:10 +00002632/**
2633 * Applies all of a pending_state asynchronously: the primary entry point for
2634 * applying KMS state to a device. Updates the state for all outputs in the
2635 * pending_state, as well as disabling any unclaimed outputs.
2636 *
2637 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2638 */
2639static int
2640drm_pending_state_apply(struct drm_pending_state *pending_state)
2641{
2642 struct drm_backend *b = pending_state->backend;
2643 struct drm_output_state *output_state, *tmp;
2644 uint32_t *unused;
2645
Daniel Stone598ee9d2016-11-16 11:55:20 +00002646#ifdef HAVE_DRM_ATOMIC
2647 if (b->atomic_modeset)
2648 return drm_pending_state_apply_atomic(pending_state,
2649 DRM_STATE_APPLY_ASYNC);
2650#endif
2651
Daniel Stonea08512f2016-11-08 17:46:10 +00002652 if (b->state_invalid) {
2653 /* If we need to reset all our state (e.g. because we've
2654 * just started, or just been VT-switched in), explicitly
2655 * disable all the CRTCs we aren't using. This also disables
2656 * all connectors on these CRTCs, so we don't need to do that
2657 * separately with the pre-atomic API. */
2658 wl_array_for_each(unused, &b->unused_crtcs)
2659 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2660 NULL);
2661 }
2662
2663 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2664 link) {
2665 struct drm_output *output = output_state->output;
2666 int ret;
2667
Daniel Stone598ee9d2016-11-16 11:55:20 +00002668 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002669 if (ret != 0) {
2670 weston_log("Couldn't apply state for output %s\n",
2671 output->base.name);
2672 }
2673 }
2674
2675 b->state_invalid = false;
2676
2677 assert(wl_list_empty(&pending_state->output_list));
2678
2679 drm_pending_state_free(pending_state);
2680
2681 return 0;
2682}
2683
2684/**
2685 * The synchronous version of drm_pending_state_apply. May only be used to
2686 * disable outputs. Does so synchronously: the request is guaranteed to have
2687 * completed on return, and the output will not be touched afterwards.
2688 *
2689 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2690 */
2691static int
2692drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
2693{
2694 struct drm_backend *b = pending_state->backend;
2695 struct drm_output_state *output_state, *tmp;
2696 uint32_t *unused;
2697
Daniel Stone598ee9d2016-11-16 11:55:20 +00002698#ifdef HAVE_DRM_ATOMIC
2699 if (b->atomic_modeset)
2700 return drm_pending_state_apply_atomic(pending_state,
2701 DRM_STATE_APPLY_SYNC);
2702#endif
2703
Daniel Stonea08512f2016-11-08 17:46:10 +00002704 if (b->state_invalid) {
2705 /* If we need to reset all our state (e.g. because we've
2706 * just started, or just been VT-switched in), explicitly
2707 * disable all the CRTCs we aren't using. This also disables
2708 * all connectors on these CRTCs, so we don't need to do that
2709 * separately with the pre-atomic API. */
2710 wl_array_for_each(unused, &b->unused_crtcs)
2711 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2712 NULL);
2713 }
2714
2715 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2716 link) {
2717 int ret;
2718
2719 assert(output_state->dpms == WESTON_DPMS_OFF);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002720 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002721 if (ret != 0) {
2722 weston_log("Couldn't apply state for output %s\n",
2723 output_state->output->base.name);
2724 }
2725 }
2726
2727 b->state_invalid = false;
2728
2729 assert(wl_list_empty(&pending_state->output_list));
2730
2731 drm_pending_state_free(pending_state);
2732
2733 return 0;
2734}
2735
2736static int
2737drm_output_repaint(struct weston_output *output_base,
2738 pixman_region32_t *damage,
2739 void *repaint_data)
2740{
2741 struct drm_pending_state *pending_state = repaint_data;
2742 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00002743 struct drm_output_state *state = NULL;
2744 struct drm_plane_state *scanout_state;
2745
2746 if (output->disable_pending || output->destroy_pending)
2747 goto err;
2748
2749 assert(!output->state_last);
2750
2751 /* If planes have been disabled in the core, we might not have
2752 * hit assign_planes at all, so might not have valid output state
2753 * here. */
2754 state = drm_pending_state_get_output(pending_state, output);
2755 if (!state)
2756 state = drm_output_state_duplicate(output->state_cur,
2757 pending_state,
2758 DRM_OUTPUT_STATE_CLEAR_PLANES);
2759 state->dpms = WESTON_DPMS_ON;
2760
2761 drm_output_render(state, damage);
2762 scanout_state = drm_output_state_get_plane(state,
2763 output->scanout_plane);
2764 if (!scanout_state || !scanout_state->fb)
2765 goto err;
2766
Daniel Stonea08512f2016-11-08 17:46:10 +00002767 return 0;
2768
2769err:
2770 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +02002771 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002772}
2773
2774static void
Jonas Ådahle5a12252013-04-05 23:07:11 +02002775drm_output_start_repaint_loop(struct weston_output *output_base)
2776{
Armin Krezović545dba62016-08-05 15:54:18 +02002777 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +00002778 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +00002779 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02002780 struct drm_backend *backend =
2781 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002782 struct timespec ts, tnow;
2783 struct timespec vbl2now;
2784 int64_t refresh_nsec;
2785 int ret;
2786 drmVBlank vbl = {
2787 .request.type = DRM_VBLANK_RELATIVE,
2788 .request.sequence = 0,
2789 .request.signal = 0,
2790 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002791
Armin Krezović08368132016-09-30 14:11:05 +02002792 if (output->disable_pending || output->destroy_pending)
Xiong Zhangabd5d472013-10-11 14:43:07 +08002793 return;
2794
Daniel Stonee2e80132018-01-16 15:37:33 +00002795 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002796 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +02002797 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002798 }
2799
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002800 /* Need to smash all state in from scratch; current timings might not
2801 * be what we want, page flip might not work, etc.
2802 */
Daniel Stone6020f472018-02-05 15:46:20 +00002803 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002804 goto finish_frame;
2805
Daniel Stonee2e80132018-01-16 15:37:33 +00002806 assert(scanout_plane->state_cur->output == output);
2807
Mario Kleinerf507ec32015-06-21 21:25:14 +02002808 /* Try to get current msc and timestamp via instant query */
2809 vbl.request.type |= drm_waitvblank_pipe(output);
2810 ret = drmWaitVBlank(backend->drm.fd, &vbl);
2811
2812 /* Error ret or zero timestamp means failure to get valid timestamp */
2813 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
2814 ts.tv_sec = vbl.reply.tval_sec;
2815 ts.tv_nsec = vbl.reply.tval_usec * 1000;
2816
2817 /* Valid timestamp for most recent vblank - not stale?
2818 * Stale ts could happen on Linux 3.17+, so make sure it
2819 * is not older than 1 refresh duration since now.
2820 */
2821 weston_compositor_read_presentation_clock(backend->compositor,
2822 &tnow);
2823 timespec_sub(&vbl2now, &tnow, &ts);
2824 refresh_nsec =
2825 millihz_to_nsec(output->base.current_mode->refresh);
2826 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
2827 drm_output_update_msc(output, vbl.reply.sequence);
2828 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002829 WP_PRESENTATION_FEEDBACK_INVALID);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002830 return;
2831 }
2832 }
2833
2834 /* Immediate query didn't provide valid timestamp.
2835 * Use pageflip fallback.
2836 */
Jonas Ådahle5a12252013-04-05 23:07:11 +02002837
Daniel Stone205c0a02017-04-04 17:54:33 +01002838 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002839 assert(!output->state_last);
2840
2841 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +00002842 drm_output_state_duplicate(output->state_cur, pending_state,
2843 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +01002844
Daniel Stone8747f952016-11-29 20:17:32 +00002845 ret = drm_pending_state_apply(pending_state);
2846 if (ret != 0) {
2847 weston_log("applying repaint-start state failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +02002848 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +02002849 }
David Herrmann3c688c52013-10-22 17:11:25 +02002850
2851 return;
2852
2853finish_frame:
2854 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +00002855 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002856 WP_PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002857}
2858
2859static void
Pekka Paalanen641307c2014-09-23 22:08:47 -04002860drm_output_update_msc(struct drm_output *output, unsigned int seq)
2861{
2862 uint64_t msc_hi = output->base.msc >> 32;
2863
2864 if (seq < (output->base.msc & 0xffffffff))
2865 msc_hi++;
2866
2867 output->base.msc = (msc_hi << 32) + seq;
2868}
2869
2870static void
Jesse Barnes58ef3792012-02-23 09:45:49 -05002871vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
2872 void *data)
2873{
Daniel Stonebc15f682016-11-14 16:57:01 +00002874 struct drm_plane_state *ps = (struct drm_plane_state *) data;
2875 struct drm_output_state *os = ps->output_state;
2876 struct drm_output *output = os->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002877 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002878 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2879 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002880
Daniel Stone598ee9d2016-11-16 11:55:20 +00002881 assert(!b->atomic_modeset);
2882
Pekka Paalanen641307c2014-09-23 22:08:47 -04002883 drm_output_update_msc(output, frame);
Daniel Stone65d87d02017-04-04 17:54:32 +01002884 output->vblank_pending--;
2885 assert(output->vblank_pending >= 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002886
Daniel Stonebc15f682016-11-14 16:57:01 +00002887 assert(ps->fb);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002888
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002889 if (output->page_flip_pending || output->vblank_pending)
2890 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002891
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002892 drm_output_update_complete(output, flags, sec, usec);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002893}
2894
2895static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002896page_flip_handler(int fd, unsigned int frame,
2897 unsigned int sec, unsigned int usec, void *data)
2898{
Armin Krezović545dba62016-08-05 15:54:18 +02002899 struct drm_output *output = data;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002900 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002901 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2902 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2903 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002904
Pekka Paalanen641307c2014-09-23 22:08:47 -04002905 drm_output_update_msc(output, frame);
2906
Daniel Stone598ee9d2016-11-16 11:55:20 +00002907 assert(!b->atomic_modeset);
Daniel Stone205c0a02017-04-04 17:54:33 +01002908 assert(output->page_flip_pending);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002909 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002910
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002911 if (output->vblank_pending)
2912 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002913
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002914 drm_output_update_complete(output, flags, sec, usec);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02002915}
2916
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002917/**
2918 * Begin a new repaint cycle
2919 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002920 * Called by the core compositor at the beginning of a repaint cycle. Creates
2921 * a new pending_state structure to own any output state created by individual
2922 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002923 */
2924static void *
2925drm_repaint_begin(struct weston_compositor *compositor)
2926{
2927 struct drm_backend *b = to_drm_backend(compositor);
2928 struct drm_pending_state *ret;
2929
2930 ret = drm_pending_state_alloc(b);
2931 b->repaint_data = ret;
2932
2933 return ret;
2934}
2935
2936/**
2937 * Flush a repaint set
2938 *
2939 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002940 * and should be flushed. Frees the pending state, transitioning ownership
2941 * of the output state from the pending state, to the update itself. When
2942 * the update completes (see drm_output_update_complete), the output
2943 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002944 */
2945static void
2946drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
2947{
2948 struct drm_backend *b = to_drm_backend(compositor);
2949 struct drm_pending_state *pending_state = repaint_data;
Daniel Stone6020f472018-02-05 15:46:20 +00002950
Daniel Stonea08512f2016-11-08 17:46:10 +00002951 drm_pending_state_apply(pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002952 b->repaint_data = NULL;
2953}
2954
2955/**
2956 * Cancel a repaint set
2957 *
2958 * Called by the core compositor when a repaint has finished, so the data
2959 * held across the repaint cycle should be discarded.
2960 */
2961static void
2962drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
2963{
2964 struct drm_backend *b = to_drm_backend(compositor);
2965 struct drm_pending_state *pending_state = repaint_data;
2966
2967 drm_pending_state_free(pending_state);
2968 b->repaint_data = NULL;
2969}
2970
Daniel Stone598ee9d2016-11-16 11:55:20 +00002971#ifdef HAVE_DRM_ATOMIC
2972static void
2973atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
2974 unsigned int usec, unsigned int crtc_id, void *data)
2975{
2976 struct drm_backend *b = data;
2977 struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
2978 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2979 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2980 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
2981
2982 /* During the initial modeset, we can disable CRTCs which we don't
2983 * actually handle during normal operation; this will give us events
2984 * for unknown outputs. Ignore them. */
2985 if (!output || !output->base.enabled)
2986 return;
2987
2988 drm_output_update_msc(output, frame);
2989
2990 assert(b->atomic_modeset);
2991 assert(output->atomic_complete_pending);
2992 output->atomic_complete_pending = 0;
2993
2994 drm_output_update_complete(output, flags, sec, usec);
2995}
2996#endif
2997
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002998static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002999drm_output_prepare_overlay_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05003000 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -05003001{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003002 struct drm_output *output = output_state->output;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02003003 struct weston_compositor *ec = output->base.compositor;
Daniel Stoned6e2a762016-11-16 19:33:20 +00003004 struct drm_backend *b = to_drm_backend(ec);
Daniel Stone08d4edf2017-04-04 17:54:34 +01003005 struct drm_plane *p;
Daniel Stonebc15f682016-11-14 16:57:01 +00003006 struct drm_plane_state *state = NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00003007 struct drm_fb *fb;
Daniel Stonedb10df12016-12-08 13:15:58 +00003008 unsigned int i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003009
Daniel Stone44abfaa2018-07-10 14:31:06 +01003010 assert(!b->sprites_are_broken);
Kristian Høgsberg65bec242012-03-05 19:57:35 -05003011
Daniel Stonef11ec022016-11-17 17:32:42 +00003012 fb = drm_fb_get_from_view(output_state, ev);
3013 if (!fb)
Daniel Stone296d7a92016-10-21 18:05:37 +01003014 return NULL;
3015
Daniel Stone085d2b92015-05-21 00:00:57 +01003016 wl_list_for_each(p, &b->plane_list, link) {
3017 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
3018 continue;
3019
Daniel Stone5ff289a2017-10-07 12:59:02 +01003020 if (!drm_plane_is_available(p, output))
Daniel Stonebc15f682016-11-14 16:57:01 +00003021 continue;
3022
Daniel Stonef11ec022016-11-17 17:32:42 +00003023 /* Check whether the format is supported */
3024 for (i = 0; i < p->count_formats; i++) {
Sergi Granellf4456222017-01-12 17:17:32 +00003025 unsigned int j;
3026
3027 if (p->formats[i].format != fb->format->format)
3028 continue;
3029
3030 if (fb->modifier == DRM_FORMAT_MOD_INVALID)
3031 break;
3032
3033 for (j = 0; j < p->formats[i].count_modifiers; j++) {
3034 if (p->formats[i].modifiers[j] == fb->modifier)
3035 break;
3036 }
3037 if (j != p->formats[i].count_modifiers)
Daniel Stonef11ec022016-11-17 17:32:42 +00003038 break;
3039 }
3040 if (i == p->count_formats)
3041 continue;
3042
Daniel Stonebc15f682016-11-14 16:57:01 +00003043 state = drm_output_state_get_plane(output_state, p);
3044 if (state->fb) {
3045 state = NULL;
3046 continue;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003047 }
Daniel Stonebc15f682016-11-14 16:57:01 +00003048
3049 break;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003050 }
3051
3052 /* No sprites available */
Daniel Stonef11ec022016-11-17 17:32:42 +00003053 if (!state) {
3054 drm_fb_unref(fb);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003055 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00003056 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05003057
Daniel Stonef11ec022016-11-17 17:32:42 +00003058 state->fb = fb;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003059 state->ev = ev;
Daniel Stonece137472016-11-16 19:35:03 +00003060 state->output = output;
Daniel Stonef11ec022016-11-17 17:32:42 +00003061
Daniel Stonece137472016-11-16 19:35:03 +00003062 if (!drm_plane_state_coords_for_view(state, ev))
3063 goto err;
3064
3065 if (state->src_w != state->dest_w << 16 ||
3066 state->src_h != state->dest_h << 16)
3067 goto err;
3068
Daniel Stone08d4edf2017-04-04 17:54:34 +01003069 return &p->base;
Daniel Stonebc15f682016-11-14 16:57:01 +00003070
3071err:
Daniel Stonedb10df12016-12-08 13:15:58 +00003072 drm_plane_state_put_back(state);
Daniel Stonebc15f682016-11-14 16:57:01 +00003073 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003074}
3075
Pekka Paalanend0ead482014-06-16 12:05:40 +03003076/**
3077 * Update the image for the current cursor surface
3078 *
Daniel Stone9b560382016-11-16 19:46:35 +00003079 * @param plane_state DRM cursor plane state
3080 * @param ev Source view for cursor
Pekka Paalanend0ead482014-06-16 12:05:40 +03003081 */
3082static void
Daniel Stone9b560382016-11-16 19:46:35 +00003083cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
Pekka Paalanend0ead482014-06-16 12:05:40 +03003084{
Daniel Stone9b560382016-11-16 19:46:35 +00003085 struct drm_backend *b = plane_state->plane->backend;
3086 struct gbm_bo *bo = plane_state->fb->bo;
Pekka Paalanend0ead482014-06-16 12:05:40 +03003087 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
3088 uint32_t buf[b->cursor_width * b->cursor_height];
3089 int32_t stride;
3090 uint8_t *s;
3091 int i;
3092
3093 assert(buffer && buffer->shm_buffer);
3094 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
Daniel Stone9b560382016-11-16 19:46:35 +00003095 assert(buffer->width <= b->cursor_width);
3096 assert(buffer->height <= b->cursor_height);
Pekka Paalanend0ead482014-06-16 12:05:40 +03003097
3098 memset(buf, 0, sizeof buf);
3099 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
3100 s = wl_shm_buffer_get_data(buffer->shm_buffer);
3101
3102 wl_shm_buffer_begin_access(buffer->shm_buffer);
Daniel Stone9b560382016-11-16 19:46:35 +00003103 for (i = 0; i < buffer->height; i++)
Pekka Paalanend0ead482014-06-16 12:05:40 +03003104 memcpy(buf + i * b->cursor_width,
3105 s + i * stride,
Daniel Stone9b560382016-11-16 19:46:35 +00003106 buffer->width * 4);
Pekka Paalanend0ead482014-06-16 12:05:40 +03003107 wl_shm_buffer_end_access(buffer->shm_buffer);
3108
3109 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
3110 weston_log("failed update cursor: %m\n");
3111}
3112
Daniel Stone2ba17f42015-05-19 20:02:41 +01003113static struct weston_plane *
3114drm_output_prepare_cursor_view(struct drm_output_state *output_state,
3115 struct weston_view *ev)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04003116{
Daniel Stone2ba17f42015-05-19 20:02:41 +01003117 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02003118 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stone2ba17f42015-05-19 20:02:41 +01003119 struct drm_plane *plane = output->cursor_plane;
3120 struct drm_plane_state *plane_state;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003121 struct wl_shm_buffer *shmbuf;
3122 bool needs_update = false;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003123
Daniel Stone2ba17f42015-05-19 20:02:41 +01003124 if (!plane)
3125 return NULL;
3126
3127 if (b->cursors_are_broken)
3128 return NULL;
3129
3130 if (!plane->state_cur->complete)
3131 return NULL;
3132
3133 if (plane->state_cur->output && plane->state_cur->output != output)
3134 return NULL;
3135
Daniel Stone2ba17f42015-05-19 20:02:41 +01003136 /* We use GBM to import SHM buffers. */
3137 if (b->gbm == NULL)
3138 return NULL;
3139
3140 if (ev->surface->buffer_ref.buffer == NULL)
3141 return NULL;
3142 shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
3143 if (!shmbuf)
3144 return NULL;
3145 if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)
3146 return NULL;
3147
Daniel Stone2ba17f42015-05-19 20:02:41 +01003148 plane_state =
3149 drm_output_state_get_plane(output_state, output->cursor_plane);
3150
3151 if (plane_state && plane_state->fb)
3152 return NULL;
3153
Daniel Stone9b560382016-11-16 19:46:35 +00003154 /* We can't scale with the legacy API, and we don't try to account for
3155 * simple cropping/translation in cursor_bo_update. */
3156 plane_state->output = output;
3157 if (!drm_plane_state_coords_for_view(plane_state, ev))
3158 goto err;
3159
3160 if (plane_state->src_x != 0 || plane_state->src_y != 0 ||
3161 plane_state->src_w > (unsigned) b->cursor_width << 16 ||
3162 plane_state->src_h > (unsigned) b->cursor_height << 16 ||
3163 plane_state->src_w != plane_state->dest_w << 16 ||
3164 plane_state->src_h != plane_state->dest_h << 16)
3165 goto err;
3166
Daniel Stone2ba17f42015-05-19 20:02:41 +01003167 /* Since we're setting plane state up front, we need to work out
3168 * whether or not we need to upload a new cursor. We can't use the
3169 * plane damage, since the planes haven't actually been calculated
3170 * yet: instead try to figure it out directly. KMS cursor planes are
3171 * pretty unique here, in that they lie partway between a Weston plane
3172 * (direct scanout) and a renderer. */
3173 if (ev != output->cursor_view ||
3174 pixman_region32_not_empty(&ev->surface->damage)) {
3175 output->current_cursor++;
3176 output->current_cursor =
3177 output->current_cursor %
3178 ARRAY_LENGTH(output->gbm_cursor_fb);
3179 needs_update = true;
3180 }
3181
3182 output->cursor_view = ev;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003183 plane_state->ev = ev;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003184
3185 plane_state->fb =
3186 drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
Daniel Stone9b560382016-11-16 19:46:35 +00003187
3188 if (needs_update)
3189 cursor_bo_update(plane_state, ev);
3190
3191 /* The cursor API is somewhat special: in cursor_bo_update(), we upload
3192 * a buffer which is always cursor_width x cursor_height, even if the
3193 * surface we want to promote is actually smaller than this. Manually
3194 * mangle the plane state to deal with this. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01003195 plane_state->src_w = b->cursor_width << 16;
3196 plane_state->src_h = b->cursor_height << 16;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003197 plane_state->dest_w = b->cursor_width;
3198 plane_state->dest_h = b->cursor_height;
3199
Daniel Stone2ba17f42015-05-19 20:02:41 +01003200 return &plane->base;
Daniel Stone9b560382016-11-16 19:46:35 +00003201
3202err:
3203 drm_plane_state_put_back(plane_state);
3204 return NULL;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003205}
3206
3207static void
3208drm_output_set_cursor(struct drm_output_state *output_state)
3209{
3210 struct drm_output *output = output_state->output;
3211 struct drm_backend *b = to_drm_backend(output->base.compositor);
3212 struct drm_plane *plane = output->cursor_plane;
3213 struct drm_plane_state *state;
3214 EGLint handle;
3215 struct gbm_bo *bo;
3216
3217 if (!plane)
3218 return;
3219
3220 state = drm_output_state_get_existing_plane(output_state, plane);
3221 if (!state)
3222 return;
3223
3224 if (!state->fb) {
3225 pixman_region32_fini(&plane->base.damage);
3226 pixman_region32_init(&plane->base.damage);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003227 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04003228 return;
3229 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003230
Daniel Stone2ba17f42015-05-19 20:02:41 +01003231 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
3232 assert(!plane->state_cur->output || plane->state_cur->output == output);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003233
Daniel Stone2ba17f42015-05-19 20:02:41 +01003234 if (plane->state_cur->fb != state->fb) {
3235 bo = state->fb->bo;
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04003236 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03003237 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
Daniel Stone2ba17f42015-05-19 20:02:41 +01003238 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03003239 weston_log("failed to set cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01003240 goto err;
Rob Clarkab5b1e32012-08-09 13:24:45 -05003241 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003242 }
3243
Daniel Stone2ba17f42015-05-19 20:02:41 +01003244 pixman_region32_fini(&plane->base.damage);
3245 pixman_region32_init(&plane->base.damage);
Pekka Paalanen7eaed402015-11-27 14:20:58 +02003246
Daniel Stone2ba17f42015-05-19 20:02:41 +01003247 if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
3248 state->dest_x, state->dest_y)) {
Daniel Stonea7cba1d2017-04-04 17:54:21 +01003249 weston_log("failed to move cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01003250 goto err;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003251 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003252
3253 return;
3254
3255err:
3256 b->cursors_are_broken = 1;
3257 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003258}
3259
Daniel Stoneee1aea72017-12-18 13:41:09 +00003260static struct drm_output_state *
3261drm_output_propose_state(struct weston_output *output_base,
3262 struct drm_pending_state *pending_state)
3263{
3264 struct drm_output *output = to_drm_output(output_base);
Daniel Stone44abfaa2018-07-10 14:31:06 +01003265 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003266 struct drm_output_state *state;
3267 struct weston_view *ev;
Daniel Stone81082392016-12-09 18:03:31 +00003268 pixman_region32_t surface_overlap, renderer_region, occluded_region;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003269 struct weston_plane *primary = &output_base->compositor->primary_plane;
3270
3271 assert(!output->state_last);
3272 state = drm_output_state_duplicate(output->state_cur,
3273 pending_state,
3274 DRM_OUTPUT_STATE_CLEAR_PLANES);
3275
3276 /*
3277 * Find a surface for each sprite in the output using some heuristics:
3278 * 1) size
3279 * 2) frequency of update
3280 * 3) opacity (though some hw might support alpha blending)
3281 * 4) clipping (this can be fixed with color keys)
3282 *
3283 * The idea is to save on blitting since this should save power.
3284 * If we can get a large video surface on the sprite for example,
3285 * the main display surface may not need to update at all, and
3286 * the client buffer can be used directly for the sprite surface
3287 * as we do for flipping full screen surfaces.
3288 */
3289 pixman_region32_init(&renderer_region);
Daniel Stone81082392016-12-09 18:03:31 +00003290 pixman_region32_init(&occluded_region);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003291
3292 wl_list_for_each(ev, &output_base->compositor->view_list, link) {
3293 struct weston_plane *next_plane = NULL;
Daniel Stone81082392016-12-09 18:03:31 +00003294 pixman_region32_t clipped_view;
3295 bool occluded = false;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003296
Daniel Stone231ae2f2016-11-29 21:03:44 +00003297 /* If this view doesn't touch our output at all, there's no
3298 * reason to do anything with it. */
3299 if (!(ev->output_mask & (1u << output->base.id)))
3300 continue;
3301
3302 /* We only assign planes to views which are exclusively present
3303 * on our output. */
3304 if (ev->output_mask != (1u << output->base.id))
3305 next_plane = primary;
3306
Daniel Stone81082392016-12-09 18:03:31 +00003307 /* Ignore views we know to be totally occluded. */
3308 pixman_region32_init(&clipped_view);
3309 pixman_region32_intersect(&clipped_view,
3310 &ev->transform.boundingbox,
3311 &output->base.region);
3312
3313 pixman_region32_init(&surface_overlap);
3314 pixman_region32_subtract(&surface_overlap, &clipped_view,
3315 &occluded_region);
3316 occluded = !pixman_region32_not_empty(&surface_overlap);
3317 if (occluded) {
3318 pixman_region32_fini(&surface_overlap);
3319 pixman_region32_fini(&clipped_view);
3320 continue;
3321 }
3322
Daniel Stoneee1aea72017-12-18 13:41:09 +00003323 /* Since we process views from top to bottom, we know that if
3324 * the view intersects the calculated renderer region, it must
3325 * be part of, or occluded by, it, and cannot go on a plane. */
Daniel Stoneee1aea72017-12-18 13:41:09 +00003326 pixman_region32_intersect(&surface_overlap, &renderer_region,
Daniel Stone81082392016-12-09 18:03:31 +00003327 &clipped_view);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003328 if (pixman_region32_not_empty(&surface_overlap))
3329 next_plane = primary;
Daniel Stonea0f82762018-07-10 11:44:25 +01003330
3331 /* We do not control the stacking order of overlay planes;
3332 * the scanout plane is strictly stacked bottom and the cursor
3333 * plane top, but the ordering of overlay planes with respect
3334 * to each other is undefined. Make sure we do not have two
3335 * planes overlapping each other. */
3336 pixman_region32_intersect(&surface_overlap, &occluded_region,
3337 &clipped_view);
3338 if (pixman_region32_not_empty(&surface_overlap))
3339 next_plane = primary;
Daniel Stoneee1aea72017-12-18 13:41:09 +00003340 pixman_region32_fini(&surface_overlap);
3341
3342 if (next_plane == NULL)
3343 next_plane = drm_output_prepare_cursor_view(state, ev);
3344
Daniel Stone81082392016-12-09 18:03:31 +00003345 if (next_plane == NULL && !drm_view_is_opaque(ev))
3346 next_plane = primary;
3347
Daniel Stone44abfaa2018-07-10 14:31:06 +01003348 if (next_plane == NULL && b->sprites_are_broken)
3349 next_plane = primary;
3350
Daniel Stoneee1aea72017-12-18 13:41:09 +00003351 if (next_plane == NULL)
3352 next_plane = drm_output_prepare_scanout_view(state, ev);
3353
3354 if (next_plane == NULL)
3355 next_plane = drm_output_prepare_overlay_view(state, ev);
3356
3357 if (next_plane == NULL)
3358 next_plane = primary;
3359
Daniel Stone81082392016-12-09 18:03:31 +00003360 /* If we've been assigned to the 'primary' (renderer) plane,
3361 * add this to our renderer region. If we have been assigned
3362 * to the cursor plane, do nothing, as the cursor plane is
3363 * blended with content underneath it. If neither, we have
3364 * been assigned to an overlay plane, so add this view's
3365 * area to the occluded region. */
Daniel Stoneee1aea72017-12-18 13:41:09 +00003366 if (next_plane == primary)
3367 pixman_region32_union(&renderer_region,
3368 &renderer_region,
Daniel Stone81082392016-12-09 18:03:31 +00003369 &clipped_view);
3370 else if (!output->cursor_plane ||
3371 next_plane != &output->cursor_plane->base)
3372 pixman_region32_union(&occluded_region,
3373 &occluded_region,
3374 &clipped_view);
3375 pixman_region32_fini(&clipped_view);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003376 }
3377 pixman_region32_fini(&renderer_region);
Daniel Stone81082392016-12-09 18:03:31 +00003378 pixman_region32_fini(&occluded_region);
Daniel Stoneee1aea72017-12-18 13:41:09 +00003379
3380 return state;
3381}
3382
3383static void
3384drm_assign_planes(struct weston_output *output_base, void *repaint_data)
3385{
3386 struct drm_backend *b = to_drm_backend(output_base->compositor);
3387 struct drm_pending_state *pending_state = repaint_data;
3388 struct drm_output *output = to_drm_output(output_base);
3389 struct drm_output_state *state;
3390 struct drm_plane_state *plane_state;
3391 struct weston_view *ev;
3392 struct weston_plane *primary = &output_base->compositor->primary_plane;
3393
3394 state = drm_output_propose_state(output_base, pending_state);
3395
3396 wl_list_for_each(ev, &output_base->compositor->view_list, link) {
3397 struct drm_plane *target_plane = NULL;
3398
Daniel Stone231ae2f2016-11-29 21:03:44 +00003399 /* If this view doesn't touch our output at all, there's no
3400 * reason to do anything with it. */
3401 if (!(ev->output_mask & (1u << output->base.id)))
3402 continue;
3403
Daniel Stoneee1aea72017-12-18 13:41:09 +00003404 /* Test whether this buffer can ever go into a plane:
3405 * non-shm, or small enough to be a cursor.
3406 *
3407 * Also, keep a reference when using the pixman renderer.
3408 * That makes it possible to do a seamless switch to the GL
3409 * renderer and since the pixman renderer keeps a reference
3410 * to the buffer anyway, there is no side effects.
3411 */
3412 if (b->use_pixman ||
3413 (ev->surface->buffer_ref.buffer &&
3414 (!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
3415 (ev->surface->width <= b->cursor_width &&
3416 ev->surface->height <= b->cursor_height))))
3417 ev->surface->keep_buffer = true;
3418 else
3419 ev->surface->keep_buffer = false;
3420
3421 /* This is a bit unpleasant, but lacking a temporary place to
3422 * hang a plane off the view, we have to do a nested walk.
3423 * Our first-order iteration has to be planes rather than
3424 * views, because otherwise we won't reset views which were
3425 * previously on planes to being on the primary plane. */
3426 wl_list_for_each(plane_state, &state->plane_list, link) {
3427 if (plane_state->ev == ev) {
3428 plane_state->ev = NULL;
3429 target_plane = plane_state->plane;
3430 break;
3431 }
3432 }
3433
3434 if (target_plane)
3435 weston_view_move_to_plane(ev, &target_plane->base);
3436 else
3437 weston_view_move_to_plane(ev, primary);
3438
3439 if (!target_plane ||
3440 target_plane->type == WDRM_PLANE_TYPE_CURSOR) {
3441 /* cursor plane & renderer involve a copy */
3442 ev->psf_flags = 0;
3443 } else {
3444 /* All other planes are a direct scanout of a
3445 * single client buffer.
3446 */
3447 ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
3448 }
3449 }
3450
3451 /* We rely on output->cursor_view being both an accurate reflection of
3452 * the cursor plane's state, but also being maintained across repaints
3453 * to avoid unnecessary damage uploads, per the comment in
3454 * drm_output_prepare_cursor_view. In the event that we go from having
3455 * a cursor view to not having a cursor view, we need to clear it. */
3456 if (output->cursor_view) {
3457 plane_state =
3458 drm_output_state_get_existing_plane(state,
3459 output->cursor_plane);
3460 if (!plane_state || !plane_state->fb)
3461 output->cursor_view = NULL;
3462 }
3463}
3464
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303465/*
3466 * Get the aspect-ratio from drmModeModeInfo mode flags.
3467 *
3468 * @param drm_mode_flags- flags from drmModeModeInfo structure.
3469 * @returns aspect-ratio as encoded in enum 'weston_mode_aspect_ratio'.
3470 */
3471static enum weston_mode_aspect_ratio
3472drm_to_weston_mode_aspect_ratio(uint32_t drm_mode_flags)
3473{
3474 return (drm_mode_flags & DRM_MODE_FLAG_PIC_AR_MASK) >>
3475 DRM_MODE_FLAG_PIC_AR_BITS_POS;
3476}
3477
3478static const char *
3479aspect_ratio_to_string(enum weston_mode_aspect_ratio ratio)
3480{
3481 if (ratio < 0 || ratio >= ARRAY_LENGTH(aspect_ratio_as_string) ||
3482 !aspect_ratio_as_string[ratio])
3483 return " (unknown aspect ratio)";
3484
3485 return aspect_ratio_as_string[ratio];
3486}
3487
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003488/**
3489 * Find the closest-matching mode for a given target
3490 *
3491 * Given a target mode, find the most suitable mode amongst the output's
3492 * current mode list to use, preferring the current mode if possible, to
3493 * avoid an expensive mode switch.
3494 *
3495 * @param output DRM output
3496 * @param target_mode Mode to attempt to match
3497 * @returns Pointer to a mode from the output's mode list
3498 */
Alex Wub7b8bda2012-04-17 17:20:48 +08003499static struct drm_mode *
3500choose_mode (struct drm_output *output, struct weston_mode *target_mode)
3501{
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303502 struct drm_mode *tmp_mode = NULL, *mode_fall_back = NULL, *mode;
3503 enum weston_mode_aspect_ratio src_aspect = WESTON_MODE_PIC_AR_NONE;
3504 enum weston_mode_aspect_ratio target_aspect = WESTON_MODE_PIC_AR_NONE;
3505 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08003506
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303507 b = to_drm_backend(output->base.compositor);
3508 target_aspect = target_mode->aspect_ratio;
3509 src_aspect = output->base.current_mode->aspect_ratio;
Hardeningff39efa2013-09-18 23:56:35 +02003510 if (output->base.current_mode->width == target_mode->width &&
3511 output->base.current_mode->height == target_mode->height &&
3512 (output->base.current_mode->refresh == target_mode->refresh ||
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303513 target_mode->refresh == 0)) {
3514 if (!b->aspect_ratio_supported || src_aspect == target_aspect)
3515 return to_drm_mode(output->base.current_mode);
3516 }
Alex Wub7b8bda2012-04-17 17:20:48 +08003517
3518 wl_list_for_each(mode, &output->base.mode_list, base.link) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303519
3520 src_aspect = mode->base.aspect_ratio;
Alex Wub7b8bda2012-04-17 17:20:48 +08003521 if (mode->mode_info.hdisplay == target_mode->width &&
3522 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02003523 if (mode->base.refresh == target_mode->refresh ||
3524 target_mode->refresh == 0) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303525 if (!b->aspect_ratio_supported ||
3526 src_aspect == target_aspect)
3527 return mode;
3528 else if (!mode_fall_back)
3529 mode_fall_back = mode;
3530 } else if (!tmp_mode) {
Alex Wub7b8bda2012-04-17 17:20:48 +08003531 tmp_mode = mode;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303532 }
Alex Wub7b8bda2012-04-17 17:20:48 +08003533 }
3534 }
3535
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303536 if (mode_fall_back)
3537 return mode_fall_back;
3538
Alex Wub7b8bda2012-04-17 17:20:48 +08003539 return tmp_mode;
3540}
3541
3542static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003543drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003544static void
3545drm_output_fini_egl(struct drm_output *output);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003546static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003547drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003548static void
3549drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003550
3551static int
Alex Wub7b8bda2012-04-17 17:20:48 +08003552drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
3553{
Daniel Stone02d487a2017-10-07 14:01:45 +01003554 struct drm_output *output = to_drm_output(output_base);
3555 struct drm_backend *b = to_drm_backend(output_base->compositor);
3556 struct drm_mode *drm_mode = choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +08003557
3558 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +01003559 weston_log("%s: invalid resolution %dx%d\n",
3560 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08003561 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003562 }
3563
Hardeningff39efa2013-09-18 23:56:35 +02003564 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08003565 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003566
Hardeningff39efa2013-09-18 23:56:35 +02003567 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003568
Hardeningff39efa2013-09-18 23:56:35 +02003569 output->base.current_mode = &drm_mode->base;
3570 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08003571 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
3572
Daniel Stonef30a18c2017-04-04 17:54:31 +01003573 /* XXX: This drops our current buffer too early, before we've started
3574 * displaying it. Ideally this should be much more atomic and
3575 * integrated with a full repaint cycle, rather than doing a
3576 * sledgehammer modeswitch first, and only later showing new
3577 * content.
3578 */
Daniel Stone6020f472018-02-05 15:46:20 +00003579 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +08003580
Giulio Camuffo954f1832014-10-11 18:27:30 +03003581 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003582 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003583 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003584 weston_log("failed to init output pixman state with "
3585 "new mode\n");
3586 return -1;
3587 }
3588 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +00003589 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003590 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003591 weston_log("failed to init output egl state with "
3592 "new mode");
3593 return -1;
3594 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003595 }
3596
Alex Wub7b8bda2012-04-17 17:20:48 +08003597 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003598}
3599
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003600static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003601on_drm_input(int fd, uint32_t mask, void *data)
3602{
Daniel Stone598ee9d2016-11-16 11:55:20 +00003603#ifdef HAVE_DRM_ATOMIC
3604 struct drm_backend *b = data;
3605#endif
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003606 drmEventContext evctx;
3607
3608 memset(&evctx, 0, sizeof evctx);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003609#ifndef HAVE_DRM_ATOMIC
Emil Velikov863e66b2017-04-04 18:07:34 +01003610 evctx.version = 2;
Daniel Stone598ee9d2016-11-16 11:55:20 +00003611#else
3612 evctx.version = 3;
3613 if (b->atomic_modeset)
3614 evctx.page_flip_handler2 = atomic_flip_handler;
3615 else
3616#endif
3617 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003618 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003619 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003620
3621 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003622}
3623
3624static int
Daniel Stoneefa504f2016-12-19 16:48:20 +00003625init_kms_caps(struct drm_backend *b)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003626{
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003627 uint64_t cap;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003628 int ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003629 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003630
Daniel Stoneefa504f2016-12-19 16:48:20 +00003631 weston_log("using %s\n", b->drm.filename);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003632
Daniel Stoneefa504f2016-12-19 16:48:20 +00003633 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003634 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003635 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003636 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003637 clk_id = CLOCK_REALTIME;
3638
Giulio Camuffo954f1832014-10-11 18:27:30 +03003639 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003640 weston_log("Error: failed to set presentation clock %d.\n",
3641 clk_id);
3642 return -1;
3643 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02003644
Daniel Stoneefa504f2016-12-19 16:48:20 +00003645 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003646 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003647 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003648 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003649 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003650
Daniel Stoneefa504f2016-12-19 16:48:20 +00003651 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003652 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003653 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003654 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003655 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003656
Daniel Stonebe1090b2017-09-06 17:29:57 +01003657 if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
3658 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
3659 b->universal_planes = (ret == 0);
3660 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003661 weston_log("DRM: %s universal planes\n",
3662 b->universal_planes ? "supports" : "does not support");
3663
Pekka Paalanencd011a62016-11-15 22:07:49 +00003664#ifdef HAVE_DRM_ATOMIC
3665 if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00003666 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
3667 if (ret != 0)
3668 cap = 0;
Pekka Paalanencd011a62016-11-15 22:07:49 +00003669 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003670 b->atomic_modeset = ((ret == 0) && (cap == 1));
Pekka Paalanencd011a62016-11-15 22:07:49 +00003671 }
3672#endif
3673 weston_log("DRM: %s atomic modesetting\n",
3674 b->atomic_modeset ? "supports" : "does not support");
3675
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303676 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
3677 b->aspect_ratio_supported = (ret == 0);
3678 weston_log("DRM: %s picture aspect ratio\n",
3679 b->aspect_ratio_supported ? "supports" : "does not support");
3680
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003681 return 0;
3682}
3683
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003684static struct gbm_device *
3685create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003686{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003687 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01003688
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003689 gl_renderer = weston_load_module("gl-renderer.so",
3690 "gl_renderer_interface");
3691 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003692 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003693
3694 /* GBM will load a dri driver, but even though they need symbols from
3695 * libglapi, in some version of Mesa they are not linked to it. Since
3696 * only the gl-renderer module links to it, the call above won't make
3697 * these symbols globally available, and loading the DRI driver fails.
3698 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
3699 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
3700
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003701 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003702
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003703 return gbm;
3704}
3705
Bryce Harringtonc056a982015-05-19 15:25:18 -07003706/* When initializing EGL, if the preferred buffer format isn't available
Bryce Harringtonb9939982016-04-15 20:28:26 -07003707 * we may be able to substitute an ARGB format for an XRGB one.
Derek Foremanc4cfe852015-05-15 12:12:40 -05003708 *
3709 * This returns 0 if substitution isn't possible, but 0 might be a
3710 * legitimate format for other EGL platforms, so the caller is
3711 * responsible for checking for 0 before calling gl_renderer->create().
3712 *
3713 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
3714 * but it's entirely possible we'll see this again on other implementations.
3715 */
3716static int
3717fallback_format_for(uint32_t format)
3718{
3719 switch (format) {
3720 case GBM_FORMAT_XRGB8888:
3721 return GBM_FORMAT_ARGB8888;
3722 case GBM_FORMAT_XRGB2101010:
3723 return GBM_FORMAT_ARGB2101010;
3724 default:
3725 return 0;
3726 }
3727}
3728
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003729static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003730drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003731{
Derek Foreman6d556372015-11-04 14:47:33 -06003732 EGLint format[3] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01003733 b->gbm_format,
3734 fallback_format_for(b->gbm_format),
Derek Foreman6d556372015-11-04 14:47:33 -06003735 0,
Derek Foremanc4cfe852015-05-15 12:12:40 -05003736 };
Derek Foreman6d556372015-11-04 14:47:33 -06003737 int n_formats = 2;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01003738
Derek Foremanc4cfe852015-05-15 12:12:40 -05003739 if (format[1])
Derek Foreman6d556372015-11-04 14:47:33 -06003740 n_formats = 3;
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003741 if (gl_renderer->display_create(b->compositor,
3742 EGL_PLATFORM_GBM_KHR,
3743 (void *)b->gbm,
Miguel A. Vico41700e32016-05-18 17:47:59 +02003744 NULL,
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003745 gl_renderer->opaque_attribs,
3746 format,
3747 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003748 return -1;
3749 }
3750
3751 return 0;
3752}
3753
3754static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003755init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003756{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003757 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003758
Giulio Camuffo954f1832014-10-11 18:27:30 +03003759 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003760 return -1;
3761
Giulio Camuffo954f1832014-10-11 18:27:30 +03003762 if (drm_backend_create_gl_renderer(b) < 0) {
3763 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003764 return -1;
3765 }
3766
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003767 return 0;
3768}
3769
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003770static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003771init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003772{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003773 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003774}
3775
Sergi Granellf4456222017-01-12 17:17:32 +00003776#ifdef HAVE_DRM_FORMATS_BLOB
3777static inline uint32_t *
3778formats_ptr(struct drm_format_modifier_blob *blob)
3779{
3780 return (uint32_t *)(((char *)blob) + blob->formats_offset);
3781}
3782
3783static inline struct drm_format_modifier *
3784modifiers_ptr(struct drm_format_modifier_blob *blob)
3785{
3786 return (struct drm_format_modifier *)
3787 (((char *)blob) + blob->modifiers_offset);
3788}
3789#endif
3790
3791/**
3792 * Populates the plane's formats array, using either the IN_FORMATS blob
3793 * property (if available), or the plane's format list if not.
3794 */
3795static int
3796drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
3797 const drmModeObjectProperties *props)
3798{
3799 unsigned i;
3800#ifdef HAVE_DRM_FORMATS_BLOB
3801 drmModePropertyBlobRes *blob;
3802 struct drm_format_modifier_blob *fmt_mod_blob;
3803 struct drm_format_modifier *blob_modifiers;
3804 uint32_t *blob_formats;
3805 uint32_t blob_id;
3806
3807 blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
3808 props,
3809 0);
3810 if (blob_id == 0)
3811 goto fallback;
3812
3813 blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
3814 if (!blob)
3815 goto fallback;
3816
3817 fmt_mod_blob = blob->data;
3818 blob_formats = formats_ptr(fmt_mod_blob);
3819 blob_modifiers = modifiers_ptr(fmt_mod_blob);
3820
3821 if (plane->count_formats != fmt_mod_blob->count_formats) {
3822 weston_log("DRM backend: format count differs between "
3823 "plane (%d) and IN_FORMATS (%d)\n",
3824 plane->count_formats,
3825 fmt_mod_blob->count_formats);
3826 weston_log("This represents a kernel bug; Weston is "
3827 "unable to continue.\n");
3828 abort();
3829 }
3830
3831 for (i = 0; i < fmt_mod_blob->count_formats; i++) {
3832 uint32_t count_modifiers = 0;
3833 uint64_t *modifiers = NULL;
3834 unsigned j;
3835
3836 for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
3837 struct drm_format_modifier *mod = &blob_modifiers[j];
3838
3839 if ((i < mod->offset) || (i > mod->offset + 63))
3840 continue;
3841 if (!(mod->formats & (1 << (i - mod->offset))))
3842 continue;
3843
3844 modifiers = realloc(modifiers,
3845 (count_modifiers + 1) *
3846 sizeof(modifiers[0]));
3847 assert(modifiers);
3848 modifiers[count_modifiers++] = mod->modifier;
3849 }
3850
3851 plane->formats[i].format = blob_formats[i];
3852 plane->formats[i].modifiers = modifiers;
3853 plane->formats[i].count_modifiers = count_modifiers;
3854 }
3855
3856 drmModeFreePropertyBlob(blob);
3857
3858 return 0;
3859
3860fallback:
3861#endif
3862 /* No IN_FORMATS blob available, so just use the old. */
3863 assert(plane->count_formats == kplane->count_formats);
3864 for (i = 0; i < kplane->count_formats; i++)
3865 plane->formats[i].format = kplane->formats[i];
3866
3867 return 0;
3868}
3869
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003870/**
Pekka Paalanenec272712014-06-05 11:22:25 +03003871 * Create a drm_plane for a hardware plane
3872 *
3873 * Creates one drm_plane structure for a hardware plane, and initialises its
3874 * properties and formats.
3875 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003876 * In the absence of universal plane support, where KMS does not explicitly
3877 * expose the primary and cursor planes to userspace, this may also create
3878 * an 'internal' plane for internal management.
3879 *
Pekka Paalanenec272712014-06-05 11:22:25 +03003880 * This function does not add the plane to the list of usable planes in Weston
3881 * itself; the caller is responsible for this.
3882 *
3883 * Call drm_plane_destroy to clean up the plane.
3884 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003885 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +03003886 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +01003887 * @param kplane DRM plane to create, or NULL if creating internal plane
3888 * @param output Output to create internal plane for, or NULL
3889 * @param type Type to use when creating internal plane, or invalid
3890 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +03003891 */
3892static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003893drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
3894 struct drm_output *output, enum wdrm_plane_type type,
3895 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +03003896{
3897 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003898 drmModeObjectProperties *props;
Sergi Granellf4456222017-01-12 17:17:32 +00003899 uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003900
Daniel Stone2ba17f42015-05-19 20:02:41 +01003901 plane = zalloc(sizeof(*plane) +
Sergi Granellf4456222017-01-12 17:17:32 +00003902 (sizeof(plane->formats[0]) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +03003903 if (!plane) {
3904 weston_log("%s: out of memory\n", __func__);
3905 return NULL;
3906 }
3907
3908 plane->backend = b;
Sergi Granellf4456222017-01-12 17:17:32 +00003909 plane->count_formats = num_formats;
Daniel Stonebc15f682016-11-14 16:57:01 +00003910 plane->state_cur = drm_plane_state_alloc(NULL, plane);
3911 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +03003912
Daniel Stone2ba17f42015-05-19 20:02:41 +01003913 if (kplane) {
3914 plane->possible_crtcs = kplane->possible_crtcs;
3915 plane->plane_id = kplane->plane_id;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003916
3917 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
3918 DRM_MODE_OBJECT_PLANE);
3919 if (!props) {
3920 weston_log("couldn't get plane properties\n");
3921 goto err;
3922 }
3923 drm_property_info_populate(b, plane_props, plane->props,
3924 WDRM_PLANE__COUNT, props);
3925 plane->type =
3926 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
3927 props,
3928 WDRM_PLANE_TYPE__COUNT);
Sergi Granellf4456222017-01-12 17:17:32 +00003929
3930 if (drm_plane_populate_formats(plane, kplane, props) < 0) {
3931 drmModeFreeObjectProperties(props);
3932 goto err;
3933 }
3934
Daniel Stone2ba17f42015-05-19 20:02:41 +01003935 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003936 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003937 else {
3938 plane->possible_crtcs = (1 << output->pipe);
3939 plane->plane_id = 0;
3940 plane->count_formats = 1;
Sergi Granellf4456222017-01-12 17:17:32 +00003941 plane->formats[0].format = format;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003942 plane->type = type;
3943 }
3944
3945 if (plane->type == WDRM_PLANE_TYPE__COUNT)
3946 goto err_props;
3947
3948 /* With universal planes, everything is a DRM plane; without
3949 * universal planes, the only DRM planes are overlay planes.
3950 * Everything else is a fake plane. */
3951 if (b->universal_planes) {
3952 assert(kplane);
3953 } else {
3954 if (kplane)
3955 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
3956 else
3957 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
3958 output);
3959 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003960
Pekka Paalanenec272712014-06-05 11:22:25 +03003961 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01003962 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +03003963
3964 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003965
3966err_props:
3967 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
3968err:
3969 drm_plane_state_free(plane->state_cur, true);
3970 free(plane);
3971 return NULL;
3972}
3973
3974/**
3975 * Find, or create, a special-purpose plane
3976 *
3977 * Primary and cursor planes are a special case, in that before universal
3978 * planes, they are driven by non-plane API calls. Without universal plane
3979 * support, the only way to configure a primary plane is via drmModeSetCrtc,
3980 * and the only way to configure a cursor plane is drmModeSetCursor2.
3981 *
3982 * Although they may actually be regular planes in the hardware, without
3983 * universal plane support, these planes are not actually exposed to
3984 * userspace in the regular plane list.
3985 *
3986 * However, for ease of internal tracking, we want to manage all planes
3987 * through the same drm_plane structures. Therefore, when we are running
3988 * without universal plane support, we create fake drm_plane structures
3989 * to track these planes.
3990 *
3991 * @param b DRM backend
3992 * @param output Output to use for plane
3993 * @param type Type of plane
3994 */
3995static struct drm_plane *
3996drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
3997 enum wdrm_plane_type type)
3998{
3999 struct drm_plane *plane;
4000
4001 if (!b->universal_planes) {
4002 uint32_t format;
4003
4004 switch (type) {
4005 case WDRM_PLANE_TYPE_CURSOR:
4006 format = GBM_FORMAT_ARGB8888;
4007 break;
Daniel Stonee2e80132018-01-16 15:37:33 +00004008 case WDRM_PLANE_TYPE_PRIMARY:
4009 /* We don't know what formats the primary plane supports
4010 * before universal planes, so we just assume that the
4011 * GBM format works; however, this isn't set until after
4012 * the output is created. */
4013 format = 0;
4014 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +01004015 default:
4016 assert(!"invalid type in drm_output_find_special_plane");
4017 break;
4018 }
4019
4020 return drm_plane_create(b, NULL, output, type, format);
4021 }
4022
4023 wl_list_for_each(plane, &b->plane_list, link) {
4024 struct drm_output *tmp;
4025 bool found_elsewhere = false;
4026
4027 if (plane->type != type)
4028 continue;
4029 if (!drm_plane_is_available(plane, output))
4030 continue;
4031
4032 /* On some platforms, primary/cursor planes can roam
4033 * between different CRTCs, so make sure we don't claim the
4034 * same plane for two outputs. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01004035 wl_list_for_each(tmp, &b->compositor->output_list,
4036 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +00004037 if (tmp->cursor_plane == plane ||
4038 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +01004039 found_elsewhere = true;
4040 break;
4041 }
4042 }
4043
4044 if (found_elsewhere)
4045 continue;
4046
4047 plane->possible_crtcs = (1 << output->pipe);
4048 return plane;
4049 }
4050
4051 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +03004052}
4053
4054/**
4055 * Destroy one DRM plane
4056 *
4057 * Destroy a DRM plane, removing it from screen and releasing its retained
4058 * buffers in the process. The counterpart to drm_plane_create.
4059 *
4060 * @param plane Plane to deallocate (will be freed)
4061 */
4062static void
4063drm_plane_destroy(struct drm_plane *plane)
4064{
Daniel Stone2ba17f42015-05-19 20:02:41 +01004065 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
4066 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
4067 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +00004068 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01004069 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +03004070 weston_plane_release(&plane->base);
4071 wl_list_remove(&plane->link);
4072 free(plane);
4073}
4074
4075/**
4076 * Initialise sprites (overlay planes)
4077 *
4078 * Walk the list of provided DRM planes, and add overlay planes.
4079 *
4080 * Call destroy_sprites to free these planes.
4081 *
4082 * @param b DRM compositor backend
4083 */
4084static void
4085create_sprites(struct drm_backend *b)
4086{
4087 drmModePlaneRes *kplane_res;
4088 drmModePlane *kplane;
4089 struct drm_plane *drm_plane;
4090 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +03004091 kplane_res = drmModeGetPlaneResources(b->drm.fd);
4092 if (!kplane_res) {
4093 weston_log("failed to get plane resources: %s\n",
4094 strerror(errno));
4095 return;
4096 }
4097
4098 for (i = 0; i < kplane_res->count_planes; i++) {
4099 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
4100 if (!kplane)
4101 continue;
4102
Daniel Stone2ba17f42015-05-19 20:02:41 +01004103 drm_plane = drm_plane_create(b, kplane, NULL,
4104 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +03004105 drmModeFreePlane(kplane);
4106 if (!drm_plane)
4107 continue;
4108
Daniel Stone085d2b92015-05-21 00:00:57 +01004109 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
4110 weston_compositor_stack_plane(b->compositor,
4111 &drm_plane->base,
4112 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +03004113 }
4114
4115 drmModeFreePlaneResources(kplane_res);
4116}
4117
4118/**
4119 * Clean up sprites (overlay planes)
4120 *
4121 * The counterpart to create_sprites.
4122 *
4123 * @param b DRM compositor backend
4124 */
4125static void
4126destroy_sprites(struct drm_backend *b)
4127{
4128 struct drm_plane *plane, *next;
4129
Daniel Stone085d2b92015-05-21 00:00:57 +01004130 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03004131 drm_plane_destroy(plane);
4132}
4133
Pekka Paalanendc14fd42017-11-10 15:31:39 +02004134static uint32_t
4135drm_refresh_rate_mHz(const drmModeModeInfo *info)
4136{
4137 uint64_t refresh;
4138
4139 /* Calculate higher precision (mHz) refresh rate */
4140 refresh = (info->clock * 1000000LL / info->htotal +
4141 info->vtotal / 2) / info->vtotal;
4142
4143 if (info->flags & DRM_MODE_FLAG_INTERLACE)
4144 refresh *= 2;
4145 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
4146 refresh /= 2;
4147 if (info->vscan > 1)
4148 refresh /= info->vscan;
4149
4150 return refresh;
4151}
4152
Pekka Paalanenec272712014-06-05 11:22:25 +03004153/**
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004154 * Add a mode to output's mode list
4155 *
4156 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
4157 * output's mode list.
4158 *
4159 * @param output DRM output to add mode to
4160 * @param info DRM mode structure to add
4161 * @returns Newly-allocated Weston/DRM mode structure
4162 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03004163static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004164drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004165{
4166 struct drm_mode *mode;
4167
4168 mode = malloc(sizeof *mode);
4169 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03004170 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004171
4172 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02004173 mode->base.width = info->hdisplay;
4174 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04004175
Pekka Paalanendc14fd42017-11-10 15:31:39 +02004176 mode->base.refresh = drm_refresh_rate_mHz(info);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004177 mode->mode_info = *info;
Daniel Stoned5526cb2016-11-16 10:54:10 +00004178 mode->blob_id = 0;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04004179
4180 if (info->type & DRM_MODE_TYPE_PREFERRED)
4181 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
4182
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304183 mode->base.aspect_ratio = drm_to_weston_mode_aspect_ratio(info->flags);
4184
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004185 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
4186
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03004187 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004188}
4189
Daniel Stoned5526cb2016-11-16 10:54:10 +00004190/**
4191 * Destroys a mode, and removes it from the list.
4192 */
4193static void
4194drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
4195{
4196 if (mode->blob_id)
4197 drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
4198 wl_list_remove(&mode->base.link);
4199 free(mode);
4200}
4201
Pekka Paalanen383b3af2017-09-11 14:40:48 +03004202/** Destroy a list of drm_modes
4203 *
4204 * @param backend The backend for releasing mode property blobs.
4205 * @param mode_list The list linked by drm_mode::base.link.
4206 */
4207static void
4208drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
4209{
4210 struct drm_mode *mode, *next;
4211
4212 wl_list_for_each_safe(mode, next, mode_list, base.link)
4213 drm_output_destroy_mode(backend, mode);
4214}
4215
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04004216static int
4217drm_subpixel_to_wayland(int drm_value)
4218{
4219 switch (drm_value) {
4220 default:
4221 case DRM_MODE_SUBPIXEL_UNKNOWN:
4222 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
4223 case DRM_MODE_SUBPIXEL_NONE:
4224 return WL_OUTPUT_SUBPIXEL_NONE;
4225 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
4226 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
4227 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
4228 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
4229 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
4230 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
4231 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
4232 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
4233 }
4234}
4235
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004236/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004237static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +03004238drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004239{
4240 long brightness, max_brightness, norm;
4241
Pekka Paalanence724242017-09-04 12:21:24 +03004242 brightness = backlight_get_brightness(head->backlight);
4243 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004244
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004245 /* convert it on a scale of 0 to 255 */
4246 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004247
4248 return (uint32_t) norm;
4249}
4250
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03004251/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004252static void
4253drm_set_backlight(struct weston_output *output_base, uint32_t value)
4254{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004255 struct drm_output *output = to_drm_output(output_base);
4256 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004257 long max_brightness, new_brightness;
4258
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04004259 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004260 return;
4261
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004262 wl_list_for_each(head, &output->base.head_list, base.output_link) {
4263 if (!head->backlight)
4264 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004265
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004266 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004267
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03004268 /* get denormalized value */
4269 new_brightness = (value * max_brightness) / 255;
4270
4271 backlight_set_brightness(head->backlight, new_brightness);
4272 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004273}
4274
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02004275static void
4276drm_output_init_backlight(struct drm_output *output)
4277{
4278 struct weston_head *base;
4279 struct drm_head *head;
4280
4281 output->base.set_backlight = NULL;
4282
4283 wl_list_for_each(base, &output->base.head_list, output_link) {
4284 head = to_drm_head(base);
4285
4286 if (head->backlight) {
4287 weston_log("Initialized backlight for head '%s', device %s\n",
4288 head->base.name, head->backlight->path);
4289
4290 if (!output->base.set_backlight) {
4291 output->base.set_backlight = drm_set_backlight;
4292 output->base.backlight_current =
4293 drm_get_backlight(head);
4294 }
4295 }
4296 }
4297
4298 if (!output->base.set_backlight) {
4299 weston_log("No backlight control for output '%s'\n",
4300 output->base.name);
4301 }
4302}
4303
Daniel Stonea08512f2016-11-08 17:46:10 +00004304/**
4305 * Power output on or off
4306 *
4307 * The DPMS/power level of an output is used to switch it on or off. This
4308 * is DRM's hook for doing so, which can called either as part of repaint,
4309 * or independently of the repaint loop.
4310 *
4311 * If we are called as part of repaint, we simply set the relevant bit in
4312 * state and return.
4313 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004314static void
4315drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
4316{
Armin Krezović545dba62016-08-05 15:54:18 +02004317 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00004318 struct drm_backend *b = to_drm_backend(output_base->compositor);
4319 struct drm_pending_state *pending_state = b->repaint_data;
4320 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01004321 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004322
Daniel Stonea08512f2016-11-08 17:46:10 +00004323 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004324 return;
4325
Daniel Stonea08512f2016-11-08 17:46:10 +00004326 /* If we're being called during the repaint loop, then this is
4327 * simple: discard any previously-generated state, and create a new
4328 * state where we disable everything. When we come to flush, this
4329 * will be applied.
4330 *
4331 * However, we need to be careful: we can be called whilst another
4332 * output is in its repaint cycle (pending_state exists), but our
4333 * output still has an incomplete state application outstanding.
4334 * In that case, we need to wait until that completes. */
4335 if (pending_state && !output->state_last) {
4336 /* The repaint loop already sets DPMS on; we don't need to
4337 * explicitly set it on here, as it will already happen
4338 * whilst applying the repaint state. */
4339 if (level == WESTON_DPMS_ON)
4340 return;
4341
4342 state = drm_pending_state_get_output(pending_state, output);
4343 if (state)
4344 drm_output_state_free(state);
4345 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01004346 return;
4347 }
4348
Daniel Stonea08512f2016-11-08 17:46:10 +00004349 /* As we throw everything away when disabling, just send us back through
4350 * a repaint cycle. */
4351 if (level == WESTON_DPMS_ON) {
4352 if (output->dpms_off_pending)
4353 output->dpms_off_pending = 0;
4354 weston_output_schedule_repaint(output_base);
4355 return;
4356 }
4357
4358 /* If we've already got a request in the pipeline, then we need to
4359 * park our DPMS request until that request has quiesced. */
4360 if (output->state_last) {
4361 output->dpms_off_pending = 1;
4362 return;
4363 }
4364
4365 pending_state = drm_pending_state_alloc(b);
4366 drm_output_get_disable_state(pending_state, output);
4367 ret = drm_pending_state_apply_sync(pending_state);
4368 if (ret != 0)
4369 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02004370}
4371
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004372static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004373 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
4374 [DRM_MODE_CONNECTOR_VGA] = "VGA",
4375 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
4376 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
4377 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
4378 [DRM_MODE_CONNECTOR_Composite] = "Composite",
4379 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
4380 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
4381 [DRM_MODE_CONNECTOR_Component] = "Component",
4382 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
4383 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
4384 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
4385 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
4386 [DRM_MODE_CONNECTOR_TV] = "TV",
4387 [DRM_MODE_CONNECTOR_eDP] = "eDP",
Pekka Paalanenab81f152015-08-24 14:27:07 +03004388#ifdef DRM_MODE_CONNECTOR_DSI
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004389 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
4390 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Pekka Paalanenab81f152015-08-24 14:27:07 +03004391#endif
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04004392};
4393
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004394/** Create a name given a DRM connector
4395 *
4396 * \param con The DRM connector whose type and id form the name.
4397 * \return A newly allocate string, or NULL on error. Must be free()'d
4398 * after use.
4399 *
4400 * The name does not identify the DRM display device.
4401 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004402static char *
4403make_connector_name(const drmModeConnector *con)
4404{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004405 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004406 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004407 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004408
4409 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
4410 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004411
4412 if (!type_name)
4413 type_name = "UNNAMED";
4414
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004415 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
4416 if (ret < 0)
4417 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004418
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004419 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004420}
4421
Daniel Stonee4256832017-04-04 17:54:27 +01004422static void drm_output_fini_cursor_egl(struct drm_output *output)
4423{
4424 unsigned int i;
4425
4426 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
4427 drm_fb_unref(output->gbm_cursor_fb[i]);
4428 output->gbm_cursor_fb[i] = NULL;
4429 }
4430}
4431
4432static int
4433drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
4434{
4435 unsigned int i;
4436
Daniel Stone2ba17f42015-05-19 20:02:41 +01004437 /* No point creating cursors if we don't have a plane for them. */
4438 if (!output->cursor_plane)
4439 return 0;
4440
Daniel Stonee4256832017-04-04 17:54:27 +01004441 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
4442 struct gbm_bo *bo;
4443
4444 bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
4445 GBM_FORMAT_ARGB8888,
4446 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
4447 if (!bo)
4448 goto err;
4449
4450 output->gbm_cursor_fb[i] =
Daniel Stonedb10df12016-12-08 13:15:58 +00004451 drm_fb_get_from_bo(bo, b, false, BUFFER_CURSOR);
Daniel Stonee4256832017-04-04 17:54:27 +01004452 if (!output->gbm_cursor_fb[i]) {
4453 gbm_bo_destroy(bo);
4454 goto err;
4455 }
4456 }
4457
4458 return 0;
4459
4460err:
4461 weston_log("cursor buffers unavailable, using gl cursors\n");
4462 b->cursors_are_broken = 1;
4463 drm_output_fini_cursor_egl(output);
4464 return -1;
4465}
4466
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004467/* Init output state that depends on gl or gbm */
4468static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004469drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004470{
Derek Foremanc4cfe852015-05-15 12:12:40 -05004471 EGLint format[2] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004472 output->gbm_format,
4473 fallback_format_for(output->gbm_format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05004474 };
Daniel Stonee4256832017-04-04 17:54:27 +01004475 int n_formats = 1;
Daniel Stone244244d2016-11-18 18:02:08 +00004476 struct weston_mode *mode = output->base.current_mode;
4477 struct drm_plane *plane = output->scanout_plane;
4478 unsigned int i;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004479
Daniel Stone244244d2016-11-18 18:02:08 +00004480 for (i = 0; i < plane->count_formats; i++) {
4481 if (plane->formats[i].format == output->gbm_format)
4482 break;
4483 }
4484
4485 if (i == plane->count_formats) {
4486 weston_log("format 0x%x not supported by output %s\n",
4487 output->gbm_format, output->base.name);
4488 return -1;
4489 }
4490
4491#ifdef HAVE_GBM_MODIFIERS
4492 if (plane->formats[i].count_modifiers > 0) {
4493 output->gbm_surface =
4494 gbm_surface_create_with_modifiers(b->gbm,
4495 mode->width,
4496 mode->height,
4497 output->gbm_format,
4498 plane->formats[i].modifiers,
4499 plane->formats[i].count_modifiers);
4500 } else
4501#endif
4502 {
4503 output->gbm_surface =
4504 gbm_surface_create(b->gbm, mode->width, mode->height,
4505 output->gbm_format,
4506 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
4507 }
4508
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004509 if (!output->gbm_surface) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004510 weston_log("failed to create gbm surface\n");
4511 return -1;
4512 }
4513
Derek Foremanc4cfe852015-05-15 12:12:40 -05004514 if (format[1])
4515 n_formats = 2;
Miguel A. Vicoc095cde2016-05-18 17:43:00 +02004516 if (gl_renderer->output_window_create(&output->base,
4517 (EGLNativeWindowType)output->gbm_surface,
4518 output->gbm_surface,
4519 gl_renderer->opaque_attribs,
4520 format,
4521 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004522 weston_log("failed to create gl renderer output state\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004523 gbm_surface_destroy(output->gbm_surface);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004524 return -1;
4525 }
4526
Daniel Stonee4256832017-04-04 17:54:27 +01004527 drm_output_init_cursor_egl(output, b);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004528
4529 return 0;
4530}
4531
Daniel Stone3e661f72016-11-04 17:24:06 +00004532static void
4533drm_output_fini_egl(struct drm_output *output)
4534{
Daniel Stonee2e80132018-01-16 15:37:33 +00004535 struct drm_backend *b = to_drm_backend(output->base.compositor);
4536
4537 /* Destroying the GBM surface will destroy all our GBM buffers,
4538 * regardless of refcount. Ensure we destroy them here. */
4539 if (!b->shutting_down &&
4540 output->scanout_plane->state_cur->fb &&
4541 output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
4542 drm_plane_state_free(output->scanout_plane->state_cur, true);
4543 output->scanout_plane->state_cur =
4544 drm_plane_state_alloc(NULL, output->scanout_plane);
4545 output->scanout_plane->state_cur->complete = true;
4546 }
4547
Daniel Stone3e661f72016-11-04 17:24:06 +00004548 gl_renderer->output_destroy(&output->base);
4549 gbm_surface_destroy(output->gbm_surface);
Daniel Stonee4256832017-04-04 17:54:27 +01004550 drm_output_fini_cursor_egl(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00004551}
4552
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04004553static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004554drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004555{
Hardeningff39efa2013-09-18 23:56:35 +02004556 int w = output->base.current_mode->width;
4557 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004558 uint32_t format = output->gbm_format;
4559 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004560 unsigned int i;
Pekka Paalanendee412d2018-04-23 11:44:58 +02004561 uint32_t flags = 0;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004562
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004563 switch (format) {
4564 case GBM_FORMAT_XRGB8888:
4565 pixman_format = PIXMAN_x8r8g8b8;
4566 break;
4567 case GBM_FORMAT_RGB565:
4568 pixman_format = PIXMAN_r5g6b5;
4569 break;
4570 default:
4571 weston_log("Unsupported pixman format 0x%x\n", format);
4572 return -1;
4573 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004574
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004575 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004576 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004577 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004578 if (!output->dumb[i])
4579 goto err;
4580
4581 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004582 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004583 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00004584 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004585 if (!output->image[i])
4586 goto err;
4587 }
4588
Pekka Paalanendee412d2018-04-23 11:44:58 +02004589 if (b->use_pixman_shadow)
4590 flags |= PIXMAN_RENDERER_OUTPUT_USE_SHADOW;
4591
4592 if (pixman_renderer_output_create(&output->base, flags) < 0)
4593 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304594
Pekka Paalanendee412d2018-04-23 11:44:58 +02004595 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
4596 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004597
4598 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02004599 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004600
4601 return 0;
4602
4603err:
4604 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
4605 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01004606 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004607 if (output->image[i])
4608 pixman_image_unref(output->image[i]);
4609
4610 output->dumb[i] = NULL;
4611 output->image[i] = NULL;
4612 }
4613
4614 return -1;
4615}
4616
4617static void
4618drm_output_fini_pixman(struct drm_output *output)
4619{
Daniel Stonee2e80132018-01-16 15:37:33 +00004620 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004621 unsigned int i;
4622
Daniel Stonee2e80132018-01-16 15:37:33 +00004623 /* Destroying the Pixman surface will destroy all our buffers,
4624 * regardless of refcount. Ensure we destroy them here. */
4625 if (!b->shutting_down &&
4626 output->scanout_plane->state_cur->fb &&
4627 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
4628 drm_plane_state_free(output->scanout_plane->state_cur, true);
4629 output->scanout_plane->state_cur =
4630 drm_plane_state_alloc(NULL, output->scanout_plane);
4631 output->scanout_plane->state_cur->complete = true;
4632 }
4633
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004634 pixman_renderer_output_destroy(&output->base);
4635 pixman_region32_fini(&output->previous_damage);
4636
4637 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004638 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01004639 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004640 output->dumb[i] = NULL;
4641 output->image[i] = NULL;
4642 }
4643}
4644
Richard Hughes2b2092a2013-04-24 14:58:02 +01004645static void
4646edid_parse_string(const uint8_t *data, char text[])
4647{
4648 int i;
4649 int replaced = 0;
4650
4651 /* this is always 12 bytes, but we can't guarantee it's null
4652 * terminated or not junk. */
4653 strncpy(text, (const char *) data, 12);
4654
Bryce Harrington9c7de162015-08-28 13:04:26 -07004655 /* guarantee our new string is null-terminated */
4656 text[12] = '\0';
4657
Richard Hughes2b2092a2013-04-24 14:58:02 +01004658 /* remove insane chars */
4659 for (i = 0; text[i] != '\0'; i++) {
4660 if (text[i] == '\n' ||
4661 text[i] == '\r') {
4662 text[i] = '\0';
4663 break;
4664 }
4665 }
4666
4667 /* ensure string is printable */
4668 for (i = 0; text[i] != '\0'; i++) {
4669 if (!isprint(text[i])) {
4670 text[i] = '-';
4671 replaced++;
4672 }
4673 }
4674
4675 /* if the string is random junk, ignore the string */
4676 if (replaced > 4)
4677 text[0] = '\0';
4678}
4679
4680#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
4681#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
4682#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
4683#define EDID_OFFSET_DATA_BLOCKS 0x36
4684#define EDID_OFFSET_LAST_BLOCK 0x6c
4685#define EDID_OFFSET_PNPID 0x08
4686#define EDID_OFFSET_SERIAL 0x0c
4687
4688static int
4689edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
4690{
4691 int i;
4692 uint32_t serial_number;
4693
4694 /* check header */
4695 if (length < 128)
4696 return -1;
4697 if (data[0] != 0x00 || data[1] != 0xff)
4698 return -1;
4699
4700 /* decode the PNP ID from three 5 bit words packed into 2 bytes
4701 * /--08--\/--09--\
4702 * 7654321076543210
4703 * |\---/\---/\---/
4704 * R C1 C2 C3 */
4705 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
4706 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
4707 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
4708 edid->pnp_id[3] = '\0';
4709
4710 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
4711 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
4712 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
4713 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
4714 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
4715 if (serial_number > 0)
4716 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
4717
4718 /* parse EDID data */
4719 for (i = EDID_OFFSET_DATA_BLOCKS;
4720 i <= EDID_OFFSET_LAST_BLOCK;
4721 i += 18) {
4722 /* ignore pixel clock data */
4723 if (data[i] != 0)
4724 continue;
4725 if (data[i+2] != 0)
4726 continue;
4727
4728 /* any useful blocks? */
4729 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
4730 edid_parse_string(&data[i+5],
4731 edid->monitor_name);
4732 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
4733 edid_parse_string(&data[i+5],
4734 edid->serial_number);
4735 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
4736 edid_parse_string(&data[i+5],
4737 edid->eisa_id);
4738 }
4739 }
4740 return 0;
4741}
4742
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004743/** Parse monitor make, model and serial from EDID
4744 *
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004745 * \param head The head whose \c drm_edid to fill in.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004746 * \param props The DRM connector properties to get the EDID from.
4747 * \param make[out] The monitor make (PNP ID).
4748 * \param model[out] The monitor model (name).
4749 * \param serial_number[out] The monitor serial number.
4750 *
4751 * Each of \c *make, \c *model and \c *serial_number are set only if the
4752 * information is found in the EDID. The pointers they are set to must not
4753 * be free()'d explicitly, instead they get implicitly freed when the
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004754 * \c drm_head is destroyed.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004755 */
Richard Hughes2b2092a2013-04-24 14:58:02 +01004756static void
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004757find_and_parse_output_edid(struct drm_head *head,
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004758 drmModeObjectPropertiesPtr props,
4759 const char **make,
4760 const char **model,
4761 const char **serial_number)
Richard Hughes2b2092a2013-04-24 14:58:02 +01004762{
4763 drmModePropertyBlobPtr edid_blob = NULL;
Daniel Stone02cf4662017-03-03 16:19:39 +00004764 uint32_t blob_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004765 int rc;
4766
Daniel Stone02cf4662017-03-03 16:19:39 +00004767 blob_id =
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004768 drm_property_get_value(&head->props_conn[WDRM_CONNECTOR_EDID],
Daniel Stone02cf4662017-03-03 16:19:39 +00004769 props, 0);
4770 if (!blob_id)
4771 return;
4772
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004773 edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id);
Richard Hughes2b2092a2013-04-24 14:58:02 +01004774 if (!edid_blob)
4775 return;
4776
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004777 rc = edid_parse(&head->edid,
Richard Hughes2b2092a2013-04-24 14:58:02 +01004778 edid_blob->data,
4779 edid_blob->length);
4780 if (!rc) {
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004781 if (head->edid.pnp_id[0] != '\0')
4782 *make = head->edid.pnp_id;
4783 if (head->edid.monitor_name[0] != '\0')
4784 *model = head->edid.monitor_name;
4785 if (head->edid.serial_number[0] != '\0')
4786 *serial_number = head->edid.serial_number;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004787 }
4788 drmModeFreePropertyBlob(edid_blob);
4789}
4790
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004791static int
4792parse_modeline(const char *s, drmModeModeInfo *mode)
4793{
4794 char hsync[16];
4795 char vsync[16];
4796 float fclock;
4797
Pekka Paalanendc4e3c62017-12-05 15:37:41 +02004798 memset(mode, 0, sizeof *mode);
4799
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004800 mode->type = DRM_MODE_TYPE_USERDEF;
4801 mode->hskew = 0;
4802 mode->vscan = 0;
4803 mode->vrefresh = 0;
4804 mode->flags = 0;
4805
Rob Bradford307e09e2013-07-26 16:29:40 +01004806 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004807 &fclock,
4808 &mode->hdisplay,
4809 &mode->hsync_start,
4810 &mode->hsync_end,
4811 &mode->htotal,
4812 &mode->vdisplay,
4813 &mode->vsync_start,
4814 &mode->vsync_end,
4815 &mode->vtotal, hsync, vsync) != 11)
4816 return -1;
4817
4818 mode->clock = fclock * 1000;
Guido Günther92278e02018-06-26 20:40:08 +02004819 if (strcasecmp(hsync, "+hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004820 mode->flags |= DRM_MODE_FLAG_PHSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02004821 else if (strcasecmp(hsync, "-hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004822 mode->flags |= DRM_MODE_FLAG_NHSYNC;
4823 else
4824 return -1;
4825
Guido Günther92278e02018-06-26 20:40:08 +02004826 if (strcasecmp(vsync, "+vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004827 mode->flags |= DRM_MODE_FLAG_PVSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02004828 else if (strcasecmp(vsync, "-vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004829 mode->flags |= DRM_MODE_FLAG_NVSYNC;
4830 else
4831 return -1;
4832
Emmanuel Gil Peyrota62138b2016-05-02 22:40:11 +01004833 snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
4834 mode->hdisplay, mode->vdisplay, fclock);
4835
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004836 return 0;
4837}
4838
Rob Bradford66bd9f52013-06-25 18:56:42 +01004839static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03004840setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01004841 struct weston_output *output,
4842 const char *s)
4843{
4844 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05004845 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004846 struct udev_seat *seat;
4847
Giulio Camuffo954f1832014-10-11 18:27:30 +03004848 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05004849 if (!seat)
4850 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004851
Derek Foreman0720ea32015-07-15 13:00:35 -05004852 seat->base.output = output;
4853
Derek Foreman1281a362015-07-31 16:55:32 -05004854 pointer = weston_seat_get_pointer(&seat->base);
4855 if (pointer)
4856 weston_pointer_clamp(pointer,
4857 &pointer->x,
4858 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01004859 }
4860}
4861
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004862static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03004863drm_output_attach_head(struct weston_output *output_base,
4864 struct weston_head *head_base)
4865{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004866 struct drm_backend *b = to_drm_backend(output_base->compositor);
4867
Pekka Paalanenc112f002017-08-28 16:27:20 +03004868 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
4869 return -1;
4870
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004871 if (!output_base->enabled)
4872 return 0;
4873
4874 /* XXX: ensure the configuration will work.
4875 * This is actually impossible without major infrastructure
4876 * work. */
4877
4878 /* Need to go through modeset to add connectors. */
4879 /* XXX: Ideally we'd do this per-output, not globally. */
4880 /* XXX: Doing it globally, what guarantees another output's update
4881 * will not clear the flag before this output is updated?
4882 */
4883 b->state_invalid = true;
4884
4885 weston_output_schedule_repaint(output_base);
4886
Pekka Paalanenc112f002017-08-28 16:27:20 +03004887 return 0;
4888}
4889
Pekka Paalanen7f853792017-11-29 14:33:33 +02004890static void
4891drm_output_detach_head(struct weston_output *output_base,
4892 struct weston_head *head_base)
4893{
4894 struct drm_backend *b = to_drm_backend(output_base->compositor);
4895
4896 if (!output_base->enabled)
4897 return;
4898
4899 /* Need to go through modeset to drop connectors that should no longer
4900 * be driven. */
4901 /* XXX: Ideally we'd do this per-output, not globally. */
4902 b->state_invalid = true;
4903
4904 weston_output_schedule_repaint(output_base);
4905}
4906
Pekka Paalanenc112f002017-08-28 16:27:20 +03004907static int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004908parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004909{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004910 int ret = 0;
4911
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004912 if (s == NULL)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004913 *gbm_format = default_value;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004914 else if (strcmp(s, "xrgb8888") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004915 *gbm_format = GBM_FORMAT_XRGB8888;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004916 else if (strcmp(s, "rgb565") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004917 *gbm_format = GBM_FORMAT_RGB565;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004918 else if (strcmp(s, "xrgb2101010") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004919 *gbm_format = GBM_FORMAT_XRGB2101010;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004920 else {
4921 weston_log("fatal: unrecognized pixel format: %s\n", s);
4922 ret = -1;
4923 }
4924
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004925 return ret;
4926}
4927
Pekka Paalanenf005f252017-11-10 16:34:39 +02004928static uint32_t
4929u32distance(uint32_t a, uint32_t b)
4930{
4931 if (a < b)
4932 return b - a;
4933 else
4934 return a - b;
4935}
4936
4937/** Choose equivalent mode
4938 *
4939 * If the two modes are not equivalent, return NULL.
4940 * Otherwise return the mode that is more likely to work in place of both.
4941 *
4942 * None of the fuzzy matching criteria in this function have any justification.
4943 *
4944 * typedef struct _drmModeModeInfo {
4945 * uint32_t clock;
4946 * uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
4947 * uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
4948 *
4949 * uint32_t vrefresh;
4950 *
4951 * uint32_t flags;
4952 * uint32_t type;
4953 * char name[DRM_DISPLAY_MODE_LEN];
4954 * } drmModeModeInfo, *drmModeModeInfoPtr;
4955 */
4956static const drmModeModeInfo *
4957drm_mode_pick_equivalent(const drmModeModeInfo *a, const drmModeModeInfo *b)
4958{
4959 uint32_t refresh_a, refresh_b;
4960
4961 if (a->hdisplay != b->hdisplay || a->vdisplay != b->vdisplay)
4962 return NULL;
4963
4964 if (a->flags != b->flags)
4965 return NULL;
4966
4967 /* kHz */
4968 if (u32distance(a->clock, b->clock) > 500)
4969 return NULL;
4970
4971 refresh_a = drm_refresh_rate_mHz(a);
4972 refresh_b = drm_refresh_rate_mHz(b);
4973 if (u32distance(refresh_a, refresh_b) > 50)
4974 return NULL;
4975
4976 if ((a->type ^ b->type) & DRM_MODE_TYPE_PREFERRED) {
4977 if (a->type & DRM_MODE_TYPE_PREFERRED)
4978 return a;
4979 else
4980 return b;
4981 }
4982
4983 return a;
4984}
4985
4986/* If the given mode info is not already in the list, add it.
4987 * If it is in the list, either keep the existing or replace it,
4988 * depending on which one is "better".
4989 */
4990static int
4991drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
4992{
4993 struct weston_mode *base;
4994 struct drm_mode *mode;
4995 struct drm_backend *backend;
4996 const drmModeModeInfo *chosen = NULL;
4997
4998 assert(info);
4999
5000 wl_list_for_each(base, &output->base.mode_list, link) {
5001 mode = to_drm_mode(base);
5002 chosen = drm_mode_pick_equivalent(&mode->mode_info, info);
5003 if (chosen)
5004 break;
5005 }
5006
5007 if (chosen == info) {
5008 backend = to_drm_backend(output->base.compositor);
5009 drm_output_destroy_mode(backend, mode);
5010 chosen = NULL;
5011 }
5012
5013 if (!chosen) {
5014 mode = drm_output_add_mode(output, info);
5015 if (!mode)
5016 return -1;
5017 }
5018 /* else { the equivalent mode is already in the list } */
5019
5020 return 0;
5021}
5022
Pekka Paalanen4be24852017-09-11 15:01:12 +03005023/** Rewrite the output's mode list
5024 *
5025 * @param output The output.
5026 * @return 0 on success, -1 on failure.
5027 *
5028 * Destroy all existing modes in the list, and reconstruct a new list from
5029 * scratch, based on the currently attached heads.
5030 *
5031 * On failure the output's mode list may contain some modes.
5032 */
5033static int
5034drm_output_update_modelist_from_heads(struct drm_output *output)
5035{
5036 struct drm_backend *backend = to_drm_backend(output->base.compositor);
5037 struct weston_head *head_base;
5038 struct drm_head *head;
Pekka Paalanen4be24852017-09-11 15:01:12 +03005039 int i;
Pekka Paalanenf005f252017-11-10 16:34:39 +02005040 int ret;
Pekka Paalanen4be24852017-09-11 15:01:12 +03005041
5042 assert(!output->base.enabled);
5043
5044 drm_mode_list_destroy(backend, &output->base.mode_list);
5045
Pekka Paalanenf005f252017-11-10 16:34:39 +02005046 wl_list_for_each(head_base, &output->base.head_list, output_link) {
5047 head = to_drm_head(head_base);
5048 for (i = 0; i < head->connector->count_modes; i++) {
5049 ret = drm_output_try_add_mode(output,
5050 &head->connector->modes[i]);
5051 if (ret < 0)
5052 return -1;
5053 }
Pekka Paalanen4be24852017-09-11 15:01:12 +03005054 }
5055
5056 return 0;
5057}
5058
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005059/**
5060 * Choose suitable mode for an output
5061 *
5062 * Find the most suitable mode to use for initial setup (or reconfiguration on
5063 * hotplug etc) for a DRM output.
5064 *
5065 * @param output DRM output to choose mode for
5066 * @param kind Strategy and preference to use when choosing mode
5067 * @param width Desired width for this output
5068 * @param height Desired height for this output
5069 * @param current_mode Mode currently being displayed on this output
5070 * @param modeline Manually-entered mode (may be NULL)
5071 * @returns A mode from the output's mode list, or NULL if none available
5072 */
5073static struct drm_mode *
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005074drm_output_choose_initial_mode(struct drm_backend *backend,
5075 struct drm_output *output,
5076 enum weston_drm_backend_output_mode mode,
Armin Krezović08368132016-09-30 14:11:05 +02005077 const char *modeline,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005078 const drmModeModeInfo *current_mode)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005079{
5080 struct drm_mode *preferred = NULL;
5081 struct drm_mode *current = NULL;
5082 struct drm_mode *configured = NULL;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305083 struct drm_mode *config_fall_back = NULL;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005084 struct drm_mode *best = NULL;
5085 struct drm_mode *drm_mode;
Armin Krezović08368132016-09-30 14:11:05 +02005086 drmModeModeInfo drm_modeline;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005087 int32_t width = 0;
5088 int32_t height = 0;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01005089 uint32_t refresh = 0;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305090 uint32_t aspect_width = 0;
5091 uint32_t aspect_height = 0;
5092 enum weston_mode_aspect_ratio aspect_ratio = WESTON_MODE_PIC_AR_NONE;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01005093 int n;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005094
Armin Krezović08368132016-09-30 14:11:05 +02005095 if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305096 n = sscanf(modeline, "%dx%d@%d %u:%u", &width, &height,
5097 &refresh, &aspect_width, &aspect_height);
5098 if (backend->aspect_ratio_supported && n == 5) {
5099 if (aspect_width == 4 && aspect_height == 3)
5100 aspect_ratio = WESTON_MODE_PIC_AR_4_3;
5101 else if (aspect_width == 16 && aspect_height == 9)
5102 aspect_ratio = WESTON_MODE_PIC_AR_16_9;
5103 else if (aspect_width == 64 && aspect_height == 27)
5104 aspect_ratio = WESTON_MODE_PIC_AR_64_27;
5105 else if (aspect_width == 256 && aspect_height == 135)
5106 aspect_ratio = WESTON_MODE_PIC_AR_256_135;
5107 else
5108 weston_log("Invalid modeline \"%s\" for output %s\n",
5109 modeline, output->base.name);
5110 }
5111 if (n != 2 && n != 3 && n != 5) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005112 width = -1;
5113
Armin Krezović08368132016-09-30 14:11:05 +02005114 if (parse_modeline(modeline, &drm_modeline) == 0) {
5115 configured = drm_output_add_mode(output, &drm_modeline);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005116 if (!configured)
5117 return NULL;
5118 } else {
5119 weston_log("Invalid modeline \"%s\" for output %s\n",
Armin Krezović08368132016-09-30 14:11:05 +02005120 modeline, output->base.name);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005121 }
5122 }
5123 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005124
5125 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005126 if (width == drm_mode->base.width &&
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01005127 height == drm_mode->base.height &&
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305128 (refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) {
5129 if (!backend->aspect_ratio_supported ||
5130 aspect_ratio == drm_mode->base.aspect_ratio)
5131 configured = drm_mode;
5132 else
5133 config_fall_back = drm_mode;
5134 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005135
comic fans7a5c5622016-03-17 14:29:27 +02005136 if (memcmp(current_mode, &drm_mode->mode_info,
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005137 sizeof *current_mode) == 0)
5138 current = drm_mode;
5139
5140 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
5141 preferred = drm_mode;
5142
5143 best = drm_mode;
5144 }
5145
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005146 if (current == NULL && current_mode->clock != 0) {
5147 current = drm_output_add_mode(output, current_mode);
5148 if (!current)
5149 return NULL;
5150 }
5151
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005152 if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005153 configured = current;
5154
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005155 if (configured)
5156 return configured;
5157
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305158 if (config_fall_back)
5159 return config_fall_back;
5160
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005161 if (preferred)
5162 return preferred;
5163
5164 if (current)
5165 return current;
5166
5167 if (best)
5168 return best;
5169
5170 weston_log("no available modes for %s\n", output->base.name);
5171 return NULL;
5172}
5173
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005174static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005175drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005176{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005177 int drm_fd = backend->drm.fd;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005178 drmModeEncoder *encoder;
5179 drmModeCrtc *crtc;
5180
5181 /* Get the current mode on the crtc that's currently driving
5182 * this connector. */
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005183 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005184 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005185 head->inherited_crtc_id = encoder->crtc_id;
5186
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005187 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
5188 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005189
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005190 if (crtc == NULL)
5191 return -1;
5192 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02005193 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03005194 drmModeFreeCrtc(crtc);
5195 }
5196
5197 return 0;
5198}
5199
Neil Roberts77c1a5b2014-03-07 18:05:50 +00005200static int
Armin Krezović08368132016-09-30 14:11:05 +02005201drm_output_set_mode(struct weston_output *base,
5202 enum weston_drm_backend_output_mode mode,
5203 const char *modeline)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005204{
Armin Krezović08368132016-09-30 14:11:05 +02005205 struct drm_output *output = to_drm_output(base);
5206 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005207 struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07005208
Armin Krezović445b41b2016-10-09 23:48:16 +02005209 struct drm_mode *current;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005210
Pekka Paalanen4be24852017-09-11 15:01:12 +03005211 if (drm_output_update_modelist_from_heads(output) < 0)
5212 return -1;
5213
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005214 current = drm_output_choose_initial_mode(b, output, mode, modeline,
5215 &head->inherited_mode);
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005216 if (!current)
Armin Krezović445b41b2016-10-09 23:48:16 +02005217 return -1;
Armin Krezović08368132016-09-30 14:11:05 +02005218
Pekka Paalanen7b36b422014-06-04 14:00:53 +03005219 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02005220 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04005221
Armin Krezović08368132016-09-30 14:11:05 +02005222 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
5223 output->base.native_mode = output->base.current_mode;
5224 output->base.native_scale = output->base.current_scale;
5225
Armin Krezović08368132016-09-30 14:11:05 +02005226 return 0;
Armin Krezović08368132016-09-30 14:11:05 +02005227}
5228
5229static void
5230drm_output_set_gbm_format(struct weston_output *base,
5231 const char *gbm_format)
5232{
5233 struct drm_output *output = to_drm_output(base);
5234 struct drm_backend *b = to_drm_backend(base->compositor);
5235
5236 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
5237 output->gbm_format = b->gbm_format;
Daniel Stonee2e80132018-01-16 15:37:33 +00005238
5239 /* Without universal planes, we can't discover which formats are
5240 * supported by the primary plane; we just hope that the GBM format
5241 * works. */
5242 if (!b->universal_planes)
Sergi Granellf4456222017-01-12 17:17:32 +00005243 output->scanout_plane->formats[0].format = output->gbm_format;
Armin Krezović08368132016-09-30 14:11:05 +02005244}
5245
5246static void
5247drm_output_set_seat(struct weston_output *base,
5248 const char *seat)
5249{
5250 struct drm_output *output = to_drm_output(base);
5251 struct drm_backend *b = to_drm_backend(base->compositor);
5252
5253 setup_output_seat_constraint(b, &output->base,
5254 seat ? seat : "");
5255}
5256
5257static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03005258drm_output_init_gamma_size(struct drm_output *output)
5259{
5260 struct drm_backend *backend = to_drm_backend(output->base.compositor);
5261 drmModeCrtc *crtc;
5262
5263 assert(output->base.compositor);
5264 assert(output->crtc_id != 0);
5265 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
5266 if (!crtc)
5267 return -1;
5268
5269 output->base.gamma_size = crtc->gamma_size;
5270
5271 drmModeFreeCrtc(crtc);
5272
5273 return 0;
5274}
5275
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005276static uint32_t
5277drm_head_get_possible_crtcs_mask(struct drm_head *head)
5278{
5279 uint32_t possible_crtcs = 0;
5280 drmModeEncoder *encoder;
5281 int i;
5282
5283 for (i = 0; i < head->connector->count_encoders; i++) {
5284 encoder = drmModeGetEncoder(head->backend->drm.fd,
5285 head->connector->encoders[i]);
5286 if (!encoder)
5287 continue;
5288
5289 possible_crtcs |= encoder->possible_crtcs;
5290 drmModeFreeEncoder(encoder);
5291 }
5292
5293 return possible_crtcs;
5294}
5295
5296static int
5297drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
5298{
5299 int i;
5300
5301 for (i = 0; i < resources->count_crtcs; i++) {
5302 if (resources->crtcs[i] == crtc_id)
5303 return i;
5304 }
5305
5306 assert(0 && "unknown crtc id");
5307 return -1;
5308}
5309
5310/** Pick a CRTC that might be able to drive all attached connectors
5311 *
5312 * @param output The output whose attached heads to include.
5313 * @param resources The DRM KMS resources.
5314 * @return CRTC index, or -1 on failure or not found.
5315 */
5316static int
5317drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
5318{
5319 struct drm_backend *backend;
5320 struct weston_head *base;
5321 struct drm_head *head;
5322 uint32_t possible_crtcs = 0xffffffff;
5323 int existing_crtc[32];
5324 unsigned j, n = 0;
5325 uint32_t crtc_id;
5326 int best_crtc_index = -1;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005327 int fallback_crtc_index = -1;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005328 int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005329 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005330
5331 backend = to_drm_backend(output->base.compositor);
5332
5333 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
5334 * because it is more often set wrong than not in the kernel. */
5335
5336 /* Accumulate a mask of possible crtcs and find existing routings. */
5337 wl_list_for_each(base, &output->base.head_list, output_link) {
5338 head = to_drm_head(base);
5339
5340 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
5341
5342 crtc_id = head->inherited_crtc_id;
5343 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
5344 existing_crtc[n++] = drm_crtc_get_index(resources,
5345 crtc_id);
5346 }
5347
5348 /* Find a crtc that could drive each connector individually at least,
5349 * and prefer existing routings. */
5350 for (i = 0; i < resources->count_crtcs; i++) {
5351 crtc_id = resources->crtcs[i];
5352
5353 /* Could the crtc not drive each connector? */
5354 if (!(possible_crtcs & (1 << i)))
5355 continue;
5356
5357 /* Is the crtc already in use? */
5358 if (drm_output_find_by_crtc(backend, crtc_id))
5359 continue;
5360
5361 /* Try to preserve the existing CRTC -> connector routing;
5362 * it makes initialisation faster, and also since we have a
5363 * very dumb picking algorithm, may preserve a better
5364 * choice. */
5365 for (j = 0; j < n; j++) {
5366 if (existing_crtc[j] == i)
5367 return i;
5368 }
5369
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005370 /* Check if any other head had existing routing to this CRTC.
5371 * If they did, this is not the best CRTC as it might be needed
5372 * for another output we haven't enabled yet. */
5373 match = false;
5374 wl_list_for_each(base, &backend->compositor->head_list,
5375 compositor_link) {
5376 head = to_drm_head(base);
5377
5378 if (head->base.output == &output->base)
5379 continue;
5380
5381 if (weston_head_is_enabled(&head->base))
5382 continue;
5383
5384 if (head->inherited_crtc_id == crtc_id) {
5385 match = true;
5386 break;
5387 }
5388 }
5389 if (!match)
5390 best_crtc_index = i;
5391
5392 fallback_crtc_index = i;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005393 }
5394
5395 if (best_crtc_index != -1)
5396 return best_crtc_index;
5397
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005398 if (fallback_crtc_index != -1)
5399 return fallback_crtc_index;
5400
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005401 /* Likely possible_crtcs was empty due to asking for clones,
5402 * but since the DRM documentation says the kernel lies, let's
5403 * pick one crtc anyway. Trial and error is the only way to
5404 * be sure if something doesn't work. */
5405
5406 /* First pick any existing assignment. */
5407 for (j = 0; j < n; j++) {
5408 crtc_id = resources->crtcs[existing_crtc[j]];
5409 if (!drm_output_find_by_crtc(backend, crtc_id))
5410 return existing_crtc[j];
5411 }
5412
5413 /* Otherwise pick any available crtc. */
5414 for (i = 0; i < resources->count_crtcs; i++) {
5415 crtc_id = resources->crtcs[i];
5416
5417 if (!drm_output_find_by_crtc(backend, crtc_id))
5418 return i;
5419 }
5420
5421 return -1;
5422}
5423
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005424/** Allocate a CRTC for the output
5425 *
5426 * @param output The output with no allocated CRTC.
5427 * @param resources DRM KMS resources.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005428 * @return 0 on success, -1 on failure.
5429 *
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005430 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005431 * for the output, and loads the CRTC properties.
5432 *
5433 * Populates the cursor and scanout planes.
5434 *
5435 * On failure, the output remains without a CRTC.
5436 */
5437static int
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005438drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005439{
5440 struct drm_backend *b = to_drm_backend(output->base.compositor);
5441 drmModeObjectPropertiesPtr props;
5442 int i;
5443
5444 assert(output->crtc_id == 0);
5445
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005446 i = drm_output_pick_crtc(output, resources);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005447 if (i < 0) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005448 weston_log("Output '%s': No available CRTCs.\n",
5449 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005450 return -1;
5451 }
5452
5453 output->crtc_id = resources->crtcs[i];
5454 output->pipe = i;
5455
5456 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
5457 DRM_MODE_OBJECT_CRTC);
5458 if (!props) {
5459 weston_log("failed to get CRTC properties\n");
5460 goto err_crtc;
5461 }
5462 drm_property_info_populate(b, crtc_props, output->props_crtc,
5463 WDRM_CRTC__COUNT, props);
5464 drmModeFreeObjectProperties(props);
5465
5466 output->scanout_plane =
5467 drm_output_find_special_plane(b, output,
5468 WDRM_PLANE_TYPE_PRIMARY);
5469 if (!output->scanout_plane) {
5470 weston_log("Failed to find primary plane for output %s\n",
5471 output->base.name);
5472 goto err_crtc;
5473 }
5474
5475 /* Failing to find a cursor plane is not fatal, as we'll fall back
5476 * to software cursor. */
5477 output->cursor_plane =
5478 drm_output_find_special_plane(b, output,
5479 WDRM_PLANE_TYPE_CURSOR);
5480
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005481 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
5482
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005483 return 0;
5484
5485err_crtc:
5486 output->crtc_id = 0;
5487 output->pipe = 0;
5488
5489 return -1;
5490}
5491
5492/** Free the CRTC from the output
5493 *
5494 * @param output The output whose CRTC to deallocate.
5495 *
5496 * The CRTC reserved for the given output becomes free to use again.
5497 */
5498static void
5499drm_output_fini_crtc(struct drm_output *output)
5500{
5501 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005502 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005503
5504 if (!b->universal_planes && !b->shutting_down) {
5505 /* With universal planes, the 'special' planes are allocated at
5506 * startup, freed at shutdown, and live on the plane list in
5507 * between. We want the planes to continue to exist and be freed
5508 * up for other outputs.
5509 *
5510 * Without universal planes, our special planes are
5511 * pseudo-planes allocated at output creation, freed at output
5512 * destruction, and not usable by other outputs.
5513 *
5514 * On the other hand, if the compositor is already shutting down,
5515 * the plane has already been destroyed.
5516 */
5517 if (output->cursor_plane)
5518 drm_plane_destroy(output->cursor_plane);
5519 if (output->scanout_plane)
5520 drm_plane_destroy(output->scanout_plane);
5521 }
5522
5523 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005524
5525 assert(output->crtc_id != 0);
5526
5527 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
5528 *unused = output->crtc_id;
5529
5530 /* Force resetting unused CRTCs */
5531 b->state_invalid = true;
5532
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005533 output->crtc_id = 0;
5534 output->cursor_plane = NULL;
5535 output->scanout_plane = NULL;
5536}
5537
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005538static void
5539drm_output_print_modes(struct drm_output *output)
5540{
5541 struct weston_mode *m;
5542 struct drm_mode *dm;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305543 const char *aspect_ratio;
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005544
5545 wl_list_for_each(m, &output->base.mode_list, link) {
5546 dm = to_drm_mode(m);
5547
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305548 aspect_ratio = aspect_ratio_to_string(m->aspect_ratio);
5549 weston_log_continue(STAMP_SPACE "%dx%d@%.1f%s%s%s, %.1f MHz\n",
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005550 m->width, m->height, m->refresh / 1000.0,
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305551 aspect_ratio,
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005552 m->flags & WL_OUTPUT_MODE_PREFERRED ?
5553 ", preferred" : "",
5554 m->flags & WL_OUTPUT_MODE_CURRENT ?
5555 ", current" : "",
5556 dm->mode_info.clock / 1000.0);
5557 }
5558}
5559
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03005560static int
Armin Krezović08368132016-09-30 14:11:05 +02005561drm_output_enable(struct weston_output *base)
5562{
5563 struct drm_output *output = to_drm_output(base);
5564 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005565 drmModeRes *resources;
5566 int ret;
5567
5568 resources = drmModeGetResources(b->drm.fd);
5569 if (!resources) {
5570 weston_log("drmModeGetResources failed\n");
5571 return -1;
5572 }
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005573 ret = drm_output_init_crtc(output, resources);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005574 drmModeFreeResources(resources);
5575 if (ret < 0)
5576 return -1;
5577
5578 if (drm_output_init_gamma_size(output) < 0)
5579 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02005580
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005581 if (b->pageflip_timeout)
5582 drm_output_pageflip_timer_create(output);
5583
Giulio Camuffo954f1832014-10-11 18:27:30 +03005584 if (b->use_pixman) {
5585 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005586 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005587 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005588 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03005589 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005590 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005591 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04005592 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04005593
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02005594 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005595
Jonas Ådahle5a12252013-04-05 23:07:11 +02005596 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05005597 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05005598 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005599 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08005600 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01005601 output->base.set_gamma = drm_output_set_gamma;
5602
Daniel Stone2ba17f42015-05-19 20:02:41 +01005603 if (output->cursor_plane)
5604 weston_compositor_stack_plane(b->compositor,
5605 &output->cursor_plane->base,
5606 NULL);
5607 else
5608 b->cursors_are_broken = 1;
5609
Daniel Stonee2e80132018-01-16 15:37:33 +00005610 weston_compositor_stack_plane(b->compositor,
5611 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03005612 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02005613
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005614 weston_log("Output %s (crtc %d) video modes:\n",
5615 output->base.name, output->crtc_id);
5616 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04005617
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005618 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01005619
Daniel Stone02cf4662017-03-03 16:19:39 +00005620err:
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005621 drm_output_fini_crtc(output);
5622
David Herrmann0f0d54e2011-12-08 17:05:45 +01005623 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005624}
5625
Jesse Barnes58ef3792012-02-23 09:45:49 -05005626static void
Armin Krezović08368132016-09-30 14:11:05 +02005627drm_output_deinit(struct weston_output *base)
5628{
5629 struct drm_output *output = to_drm_output(base);
5630 struct drm_backend *b = to_drm_backend(base->compositor);
5631
Daniel Stone3e661f72016-11-04 17:24:06 +00005632 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02005633 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00005634 else
5635 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02005636
Daniel Stone2ba17f42015-05-19 20:02:41 +01005637 /* Since our planes are no longer in use anywhere, remove their base
5638 * weston_plane's link from the plane stacking list, unless we're
5639 * shutting down, in which case the plane has already been
5640 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00005641 if (!b->shutting_down) {
5642 wl_list_remove(&output->scanout_plane->base.link);
5643 wl_list_init(&output->scanout_plane->base.link);
5644
5645 if (output->cursor_plane) {
5646 wl_list_remove(&output->cursor_plane->base.link);
5647 wl_list_init(&output->cursor_plane->base.link);
5648 /* Turn off hardware cursor */
5649 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
5650 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01005651 }
Daniel Stone087ddf02017-02-14 17:51:30 +00005652
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005653 drm_output_fini_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02005654}
5655
5656static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03005657drm_head_destroy(struct drm_head *head);
5658
5659static void
Armin Krezović08368132016-09-30 14:11:05 +02005660drm_output_destroy(struct weston_output *base)
5661{
5662 struct drm_output *output = to_drm_output(base);
5663 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02005664
Daniel Stone598ee9d2016-11-16 11:55:20 +00005665 if (output->page_flip_pending || output->vblank_pending ||
5666 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005667 output->destroy_pending = 1;
5668 weston_log("destroy output while page flip pending\n");
5669 return;
5670 }
5671
5672 if (output->base.enabled)
5673 drm_output_deinit(&output->base);
5674
Pekka Paalanen383b3af2017-09-11 14:40:48 +03005675 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02005676
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005677 if (output->pageflip_timer)
5678 wl_event_source_remove(output->pageflip_timer);
5679
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03005680 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02005681
Daniel Stone7b2ddac2016-11-11 19:11:49 +00005682 assert(!output->state_last);
5683 drm_output_state_free(output->state_cur);
5684
Armin Krezović08368132016-09-30 14:11:05 +02005685 free(output);
5686}
5687
5688static int
5689drm_output_disable(struct weston_output *base)
5690{
5691 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02005692
Daniel Stone598ee9d2016-11-16 11:55:20 +00005693 if (output->page_flip_pending || output->vblank_pending ||
5694 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005695 output->disable_pending = 1;
5696 return -1;
5697 }
5698
Daniel Stonea08512f2016-11-08 17:46:10 +00005699 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00005700
Armin Krezović08368132016-09-30 14:11:05 +02005701 if (output->base.enabled)
5702 drm_output_deinit(&output->base);
5703
5704 output->disable_pending = 0;
5705
Armin Krezović08368132016-09-30 14:11:05 +02005706 return 0;
5707}
5708
5709/**
Daniel Stone087ddf02017-02-14 17:51:30 +00005710 * Update the list of unused connectors and CRTCs
5711 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03005712 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00005713 *
5714 * @param b Weston backend structure
5715 * @param resources DRM resources for this device
5716 */
5717static void
5718drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
5719{
5720 int i;
5721
Daniel Stone087ddf02017-02-14 17:51:30 +00005722 wl_array_release(&b->unused_crtcs);
5723 wl_array_init(&b->unused_crtcs);
5724
5725 for (i = 0; i < resources->count_crtcs; i++) {
5726 struct drm_output *output;
5727 uint32_t *crtc_id;
5728
5729 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
5730 if (output && output->base.enabled)
5731 continue;
5732
5733 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
5734 *crtc_id = resources->crtcs[i];
5735 }
5736}
5737
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005738/** Replace connector data and monitor information
5739 *
5740 * @param head The head to update.
5741 * @param connector The connector data to be owned by the head, must match
5742 * the head's connector ID.
5743 * @return 0 on success, -1 on failure.
5744 *
5745 * Takes ownership of @c connector on success, not on failure.
5746 *
5747 * May schedule a heads changed call.
5748 */
5749static int
5750drm_head_assign_connector_info(struct drm_head *head,
5751 drmModeConnector *connector)
5752{
5753 drmModeObjectProperties *props;
5754 const char *make = "unknown";
5755 const char *model = "unknown";
5756 const char *serial_number = "unknown";
5757
5758 assert(connector);
5759 assert(head->connector_id == connector->connector_id);
5760
5761 props = drmModeObjectGetProperties(head->backend->drm.fd,
5762 head->connector_id,
5763 DRM_MODE_OBJECT_CONNECTOR);
5764 if (!props) {
5765 weston_log("Error: failed to get connector '%s' properties\n",
5766 head->base.name);
5767 return -1;
5768 }
5769
5770 if (head->connector)
5771 drmModeFreeConnector(head->connector);
5772 head->connector = connector;
5773
5774 drm_property_info_populate(head->backend, connector_props,
5775 head->props_conn,
5776 WDRM_CONNECTOR__COUNT, props);
5777 find_and_parse_output_edid(head, props, &make, &model, &serial_number);
5778 weston_head_set_monitor_strings(&head->base, make, model, serial_number);
5779 weston_head_set_subpixel(&head->base,
5780 drm_subpixel_to_wayland(head->connector->subpixel));
5781
5782 weston_head_set_physical_size(&head->base, head->connector->mmWidth,
5783 head->connector->mmHeight);
5784
5785 drmModeFreeObjectProperties(props);
5786
5787 /* Unknown connection status is assumed disconnected. */
5788 weston_head_set_connection_status(&head->base,
5789 head->connector->connection == DRM_MODE_CONNECTED);
5790
5791 return 0;
5792}
5793
Pekka Paalanen456dc732017-11-09 15:10:11 +02005794static void
5795drm_head_log_info(struct drm_head *head, const char *msg)
5796{
5797 if (head->base.connected) {
5798 weston_log("DRM: head '%s' %s, connector %d is connected, "
5799 "EDID make '%s', model '%s', serial '%s'\n",
5800 head->base.name, msg, head->connector_id,
5801 head->base.make, head->base.model,
5802 head->base.serial_number ?: "");
5803 } else {
5804 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
5805 head->base.name, msg, head->connector_id);
5806 }
5807}
5808
Pekka Paalanend2e62422017-09-08 15:48:07 +03005809/** Update connector and monitor information
5810 *
5811 * @param head The head to update.
5812 *
5813 * Re-reads the DRM property lists for the connector and updates monitor
5814 * information and connection status. This may schedule a heads changed call
5815 * to the user.
5816 */
5817static void
5818drm_head_update_info(struct drm_head *head)
5819{
5820 drmModeConnector *connector;
5821
5822 connector = drmModeGetConnector(head->backend->drm.fd,
5823 head->connector_id);
5824 if (!connector) {
5825 weston_log("DRM: getting connector info for '%s' failed.\n",
5826 head->base.name);
5827 return;
5828 }
5829
5830 if (drm_head_assign_connector_info(head, connector) < 0)
5831 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005832
5833 if (head->base.device_changed)
5834 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03005835}
5836
Daniel Stone087ddf02017-02-14 17:51:30 +00005837/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03005838 * Create a Weston head for a connector
5839 *
5840 * Given a DRM connector, create a matching drm_head structure and add it
5841 * to Weston's head list.
5842 *
5843 * @param b Weston backend structure
5844 * @param connector_id DRM connector ID for the head
5845 * @param drm_device udev device pointer
5846 * @returns The new head, or NULL on failure.
5847 */
5848static struct drm_head *
5849drm_head_create(struct drm_backend *backend, uint32_t connector_id,
5850 struct udev_device *drm_device)
5851{
5852 struct drm_head *head;
5853 drmModeConnector *connector;
5854 char *name;
5855
5856 head = zalloc(sizeof *head);
5857 if (!head)
5858 return NULL;
5859
5860 connector = drmModeGetConnector(backend->drm.fd, connector_id);
5861 if (!connector)
5862 goto err_alloc;
5863
5864 name = make_connector_name(connector);
5865 if (!name)
5866 goto err_alloc;
5867
5868 weston_head_init(&head->base, name);
5869 free(name);
5870
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005871 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03005872 head->backend = backend;
5873
Pekka Paalanence724242017-09-04 12:21:24 +03005874 head->backlight = backlight_init(drm_device, connector->connector_type);
5875
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005876 if (drm_head_assign_connector_info(head, connector) < 0)
5877 goto err_init;
5878
5879 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
5880 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
5881 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03005882
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005883 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005884 weston_log("Failed to retrieve current mode from connector %d.\n",
5885 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02005886 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005887 }
5888
Pekka Paalanenc112f002017-08-28 16:27:20 +03005889 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005890 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03005891
5892 return head;
5893
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005894err_init:
5895 weston_head_release(&head->base);
5896
Pekka Paalanenc112f002017-08-28 16:27:20 +03005897err_alloc:
5898 if (connector)
5899 drmModeFreeConnector(connector);
5900
5901 free(head);
5902
5903 return NULL;
5904}
5905
5906static void
5907drm_head_destroy(struct drm_head *head)
5908{
5909 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03005910
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005911 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
5912 drmModeFreeConnector(head->connector);
5913
Pekka Paalanence724242017-09-04 12:21:24 +03005914 if (head->backlight)
5915 backlight_destroy(head->backlight);
5916
Pekka Paalanenc112f002017-08-28 16:27:20 +03005917 free(head);
5918}
5919
5920/**
Armin Krezović08368132016-09-30 14:11:05 +02005921 * Create a Weston output structure
5922 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03005923 * Create an "empty" drm_output. This is the implementation of
5924 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02005925 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03005926 * Creating an output is usually followed by drm_output_attach_head()
5927 * and drm_output_enable() to make use of it.
5928 *
5929 * @param compositor The compositor instance.
5930 * @param name Name for the new output.
5931 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02005932 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03005933static struct weston_output *
5934drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02005935{
Pekka Paalanend2e62422017-09-08 15:48:07 +03005936 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02005937 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02005938
Armin Krezović08368132016-09-30 14:11:05 +02005939 output = zalloc(sizeof *output);
5940 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03005941 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02005942
Pekka Paalanend2e62422017-09-08 15:48:07 +03005943 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005944
Armin Krezović08368132016-09-30 14:11:05 +02005945 output->base.enable = drm_output_enable;
5946 output->base.destroy = drm_output_destroy;
5947 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03005948 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02005949 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02005950
5951 output->destroy_pending = 0;
5952 output->disable_pending = 0;
Armin Krezović08368132016-09-30 14:11:05 +02005953
Pekka Paalanen01f60212017-03-24 15:39:24 +02005954 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03005955
Armin Krezović08368132016-09-30 14:11:05 +02005956 weston_compositor_add_pending_output(&output->base, b->compositor);
5957
Pekka Paalanend2e62422017-09-08 15:48:07 +03005958 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02005959}
5960
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005961static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03005962drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005963{
Pekka Paalanend2e62422017-09-08 15:48:07 +03005964 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005965 drmModeRes *resources;
5966 int i;
5967
Giulio Camuffo954f1832014-10-11 18:27:30 +03005968 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005969 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02005970 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005971 return -1;
5972 }
5973
Giulio Camuffo954f1832014-10-11 18:27:30 +03005974 b->min_width = resources->min_width;
5975 b->max_width = resources->max_width;
5976 b->min_height = resources->min_height;
5977 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05005978
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005979 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005980 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00005981
Pekka Paalanend2e62422017-09-08 15:48:07 +03005982 head = drm_head_create(b, connector_id, drm_device);
5983 if (!head) {
5984 weston_log("DRM: failed to create head for connector %d.\n",
5985 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02005986 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005987 }
5988
Daniel Stone087ddf02017-02-14 17:51:30 +00005989 drm_backend_update_unused_outputs(b, resources);
5990
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005991 drmModeFreeResources(resources);
5992
5993 return 0;
5994}
5995
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005996static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03005997drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005998{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005999 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03006000 struct weston_head *base, *next;
6001 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006002 int i;
6003
Giulio Camuffo954f1832014-10-11 18:27:30 +03006004 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006005 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02006006 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006007 return;
6008 }
6009
Pekka Paalanend2e62422017-09-08 15:48:07 +03006010 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006011 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00006012 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02006013
Pekka Paalanend2e62422017-09-08 15:48:07 +03006014 head = drm_head_find_by_connector(b, connector_id);
6015 if (head) {
6016 drm_head_update_info(head);
6017 } else {
6018 head = drm_head_create(b, connector_id, drm_device);
6019 if (!head)
6020 weston_log("DRM: failed to create head for hot-added connector %d.\n",
6021 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01006022 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006023 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006024
Pekka Paalanend2e62422017-09-08 15:48:07 +03006025 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03006026 wl_list_for_each_safe(base, next,
6027 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03006028 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006029
Pekka Paalanena0a37462017-08-31 15:41:57 +03006030 head = to_drm_head(base);
6031
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006032 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03006033 if (resources->connectors[i] == head->connector_id) {
6034 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006035 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006036 }
6037 }
Armin Krezović08368132016-09-30 14:11:05 +02006038
Pekka Paalanend2e62422017-09-08 15:48:07 +03006039 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006040 continue;
6041
Pekka Paalanend2e62422017-09-08 15:48:07 +03006042 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
6043 head->base.name, head->connector_id);
6044 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006045 }
6046
Daniel Stone087ddf02017-02-14 17:51:30 +00006047 drm_backend_update_unused_outputs(b, resources);
6048
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00006049 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006050}
6051
6052static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03006053udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006054{
David Herrmannd7488c22012-03-11 20:05:21 +01006055 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01006056 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01006057
6058 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006059 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01006060 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02006061
David Herrmann6ac52db2012-03-11 20:05:22 +01006062 val = udev_device_get_property_value(device, "HOTPLUG");
6063 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006064 return 0;
6065
David Herrmann6ac52db2012-03-11 20:05:22 +01006066 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006067}
6068
Kristian Høgsbergb1868472011-04-22 12:27:57 -04006069static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006070udev_drm_event(int fd, uint32_t mask, void *data)
6071{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006072 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006073 struct udev_device *event;
6074
Giulio Camuffo954f1832014-10-11 18:27:30 +03006075 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02006076
Giulio Camuffo954f1832014-10-11 18:27:30 +03006077 if (udev_event_is_hotplug(b, event))
Pekka Paalanend2e62422017-09-08 15:48:07 +03006078 drm_backend_update_heads(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006079
6080 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04006081
6082 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006083}
6084
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006085static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05006086drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006087{
Armin Krezović545dba62016-08-05 15:54:18 +02006088 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03006089 struct weston_head *base, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006090
Giulio Camuffo954f1832014-10-11 18:27:30 +03006091 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02006092
Giulio Camuffo954f1832014-10-11 18:27:30 +03006093 wl_event_source_remove(b->udev_drm_source);
6094 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02006095
Daniel Stoneb57c6a02017-10-05 16:27:21 +01006096 b->shutting_down = true;
6097
Giulio Camuffo954f1832014-10-11 18:27:30 +03006098 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04006099
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03006100 weston_compositor_shutdown(ec);
6101
Pekka Paalanenc112f002017-08-28 16:27:20 +03006102 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
6103 drm_head_destroy(to_drm_head(base));
6104
Giulio Camuffo954f1832014-10-11 18:27:30 +03006105 if (b->gbm)
6106 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006107
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02006108 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03006109 udev_unref(b->udev);
6110
Giulio Camuffo954f1832014-10-11 18:27:30 +03006111 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006112
Daniel Stone087ddf02017-02-14 17:51:30 +00006113 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00006114
Giulio Camuffo954f1832014-10-11 18:27:30 +03006115 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02006116 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006117 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05006118}
6119
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006120static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006121session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006122{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006123 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02006124 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01006125 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04006126 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006127
Giulio Camuffo954f1832014-10-11 18:27:30 +03006128 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006129 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00006130 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05006131 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00006132 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006133 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07006134 } else {
6135 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03006136 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04006137
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01006138 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04006139
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05006140 /* If we have a repaint scheduled (either from a
6141 * pending pageflip or the idle handler), make sure we
6142 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01006143 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05006144 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05006145 * back, we schedule a repaint, which will process
6146 * pending frame callbacks. */
6147
Giulio Camuffo954f1832014-10-11 18:27:30 +03006148 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00006149 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01006150 if (output->cursor_plane)
6151 drmModeSetCursor(b->drm.fd, output->crtc_id,
6152 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05006153 }
6154
Giulio Camuffo954f1832014-10-11 18:27:30 +03006155 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04006156 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05006157
Daniel Stone085d2b92015-05-21 00:00:57 +01006158 wl_list_for_each(plane, &b->plane_list, link) {
6159 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
6160 continue;
6161
Giulio Camuffo954f1832014-10-11 18:27:30 +03006162 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01006163 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04006164 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05006165 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01006166 }
6167 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04006168}
6169
Daniel Stoneefa504f2016-12-19 16:48:20 +00006170/**
6171 * Determines whether or not a device is capable of modesetting. If successful,
6172 * sets b->drm.fd and b->drm.filename to the opened device.
6173 */
6174static bool
6175drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
6176{
6177 const char *filename = udev_device_get_devnode(device);
6178 const char *sysnum = udev_device_get_sysnum(device);
6179 drmModeRes *res;
6180 int id, fd;
6181
6182 if (!filename)
6183 return false;
6184
6185 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
6186 if (fd < 0)
6187 return false;
6188
6189 res = drmModeGetResources(fd);
6190 if (!res)
6191 goto out_fd;
6192
6193 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
6194 res->count_encoders <= 0)
6195 goto out_res;
6196
6197 if (sysnum)
6198 id = atoi(sysnum);
6199 if (!sysnum || id < 0) {
6200 weston_log("couldn't get sysnum for device %s\n", filename);
6201 goto out_res;
6202 }
6203
6204 /* We can be called successfully on multiple devices; if we have,
6205 * clean up old entries. */
6206 if (b->drm.fd >= 0)
6207 weston_launcher_close(b->compositor->launcher, b->drm.fd);
6208 free(b->drm.filename);
6209
6210 b->drm.fd = fd;
6211 b->drm.id = id;
6212 b->drm.filename = strdup(filename);
6213
Sergi Granellceb59812017-03-28 12:44:04 +02006214 drmModeFreeResources(res);
6215
Daniel Stoneefa504f2016-12-19 16:48:20 +00006216 return true;
6217
6218out_res:
6219 drmModeFreeResources(res);
6220out_fd:
6221 weston_launcher_close(b->compositor->launcher, fd);
6222 return false;
6223}
6224
David Herrmann0af066f2012-10-29 19:21:16 +01006225/*
6226 * Find primary GPU
6227 * Some systems may have multiple DRM devices attached to a single seat. This
6228 * function loops over all devices and tries to find a PCI device with the
6229 * boot_vga sysfs attribute set to 1.
6230 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00006231 * Devices are also vetted to make sure they are are capable of modesetting,
6232 * rather than pure render nodes (GPU with no display), or pure
6233 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01006234 */
6235static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03006236find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01006237{
6238 struct udev_enumerate *e;
6239 struct udev_list_entry *entry;
6240 const char *path, *device_seat, *id;
6241 struct udev_device *device, *drm_device, *pci;
6242
Giulio Camuffo954f1832014-10-11 18:27:30 +03006243 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01006244 udev_enumerate_add_match_subsystem(e, "drm");
6245 udev_enumerate_add_match_sysname(e, "card[0-9]*");
6246
6247 udev_enumerate_scan_devices(e);
6248 drm_device = NULL;
6249 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00006250 bool is_boot_vga = false;
6251
David Herrmann0af066f2012-10-29 19:21:16 +01006252 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006253 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01006254 if (!device)
6255 continue;
6256 device_seat = udev_device_get_property_value(device, "ID_SEAT");
6257 if (!device_seat)
6258 device_seat = default_seat;
6259 if (strcmp(device_seat, seat)) {
6260 udev_device_unref(device);
6261 continue;
6262 }
6263
6264 pci = udev_device_get_parent_with_subsystem_devtype(device,
6265 "pci", NULL);
6266 if (pci) {
6267 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00006268 if (id && !strcmp(id, "1"))
6269 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01006270 }
6271
Daniel Stoneefa504f2016-12-19 16:48:20 +00006272 /* If we already have a modesetting-capable device, and this
6273 * device isn't our boot-VGA device, we aren't going to use
6274 * it. */
6275 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01006276 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006277 continue;
6278 }
6279
6280 /* Make sure this device is actually capable of modesetting;
6281 * if this call succeeds, b->drm.{fd,filename} will be set,
6282 * and any old values freed. */
6283 if (!drm_device_is_kms(b, device)) {
6284 udev_device_unref(device);
6285 continue;
6286 }
6287
6288 /* There can only be one boot_vga device, and we try to use it
6289 * at all costs. */
6290 if (is_boot_vga) {
6291 if (drm_device)
6292 udev_device_unref(drm_device);
6293 drm_device = device;
6294 break;
6295 }
6296
6297 /* Per the (!is_boot_vga && drm_device) test above, we only
6298 * trump existing saved devices with boot-VGA devices, so if
6299 * we end up here, this must be the first device we've seen. */
6300 assert(!drm_device);
6301 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01006302 }
6303
Daniel Stoneefa504f2016-12-19 16:48:20 +00006304 /* If we're returning a device to use, we must have an open FD for
6305 * it. */
6306 assert(!!drm_device == (b->drm.fd >= 0));
6307
David Herrmann0af066f2012-10-29 19:21:16 +01006308 udev_enumerate_unref(e);
6309 return drm_device;
6310}
6311
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03006312static struct udev_device *
6313open_specific_drm_device(struct drm_backend *b, const char *name)
6314{
6315 struct udev_device *device;
6316
6317 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
6318 if (!device) {
6319 weston_log("ERROR: could not open DRM device '%s'\n", name);
6320 return NULL;
6321 }
6322
6323 if (!drm_device_is_kms(b, device)) {
6324 udev_device_unref(device);
6325 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
6326 return NULL;
6327 }
6328
6329 /* If we're returning a device to use, we must have an open FD for
6330 * it. */
6331 assert(b->drm.fd >= 0);
6332
6333 return device;
6334}
6335
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006336static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006337planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6338 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006339{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006340 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006341
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006342 switch (key) {
6343 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006344 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006345 break;
6346 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006347 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006348 break;
6349 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006350 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02006351 break;
6352 default:
6353 break;
6354 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02006355}
6356
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07006357#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006358static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006359recorder_destroy(struct drm_output *output)
6360{
6361 vaapi_recorder_destroy(output->recorder);
6362 output->recorder = NULL;
6363
6364 output->base.disable_planes--;
6365
6366 wl_list_remove(&output->recorder_frame_listener.link);
6367 weston_log("[libva recorder] done\n");
6368}
6369
6370static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006371recorder_frame_notify(struct wl_listener *listener, void *data)
6372{
6373 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006374 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006375 int fd, ret;
6376
6377 output = container_of(listener, struct drm_output,
6378 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02006379 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006380
6381 if (!output->recorder)
6382 return;
6383
Daniel Stonee2e80132018-01-16 15:37:33 +00006384 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00006385 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006386 DRM_CLOEXEC, &fd);
6387 if (ret) {
6388 weston_log("[libva recorder] "
6389 "failed to create prime fd for front buffer\n");
6390 return;
6391 }
6392
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006393 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00006394 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006395 if (ret < 0) {
6396 weston_log("[libva recorder] aborted: %m\n");
6397 recorder_destroy(output);
6398 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006399}
6400
6401static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03006402create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006403 const char *filename)
6404{
6405 int fd;
6406 drm_magic_t magic;
6407
Giulio Camuffo954f1832014-10-11 18:27:30 +03006408 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006409 if (fd < 0)
6410 return NULL;
6411
6412 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006413 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006414
6415 return vaapi_recorder_create(fd, width, height, filename);
6416}
6417
6418static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006419recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6420 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006421{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006422 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006423 struct drm_output *output;
6424 int width, height;
6425
Giulio Camuffo954f1832014-10-11 18:27:30 +03006426 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006427 struct drm_output, base.link);
6428
6429 if (!output->recorder) {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01006430 if (output->gbm_format != GBM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03006431 weston_log("failed to start vaapi recorder: "
6432 "output format not supported\n");
6433 return;
6434 }
6435
Hardeningff39efa2013-09-18 23:56:35 +02006436 width = output->base.current_mode->width;
6437 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006438
6439 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03006440 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006441 if (!output->recorder) {
6442 weston_log("failed to create vaapi recorder\n");
6443 return;
6444 }
6445
6446 output->base.disable_planes++;
6447
6448 output->recorder_frame_listener.notify = recorder_frame_notify;
6449 wl_signal_add(&output->base.frame_signal,
6450 &output->recorder_frame_listener);
6451
6452 weston_output_schedule_repaint(&output->base);
6453
6454 weston_log("[libva recorder] initialized\n");
6455 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006456 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006457 }
6458}
6459#else
6460static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006461recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6462 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006463{
6464 weston_log("Compiled without libva support\n");
6465}
6466#endif
6467
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006468static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03006469switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006470{
6471 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006472 bool dmabuf_support_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006473
Giulio Camuffo954f1832014-10-11 18:27:30 +03006474 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006475 return;
6476
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006477 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
6478
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006479 weston_log("Switching to GL renderer\n");
6480
Giulio Camuffo954f1832014-10-11 18:27:30 +03006481 b->gbm = create_gbm_device(b->drm.fd);
6482 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006483 weston_log("Failed to create gbm device. "
6484 "Aborting renderer switch\n");
6485 return;
6486 }
6487
Giulio Camuffo954f1832014-10-11 18:27:30 +03006488 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006489 pixman_renderer_output_destroy(&output->base);
6490
Giulio Camuffo954f1832014-10-11 18:27:30 +03006491 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006492
Giulio Camuffo954f1832014-10-11 18:27:30 +03006493 if (drm_backend_create_gl_renderer(b) < 0) {
6494 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006495 weston_log("Failed to create GL renderer. Quitting.\n");
6496 /* FIXME: we need a function to shutdown cleanly */
6497 assert(0);
6498 }
6499
Giulio Camuffo954f1832014-10-11 18:27:30 +03006500 wl_list_for_each(output, &b->compositor->output_list, base.link)
6501 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006502
Giulio Camuffo954f1832014-10-11 18:27:30 +03006503 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006504
6505 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
6506 if (linux_dmabuf_setup(b->compositor) < 0)
6507 weston_log("Error: initializing dmabuf "
6508 "support failed.\n");
6509 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006510}
6511
6512static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006513renderer_switch_binding(struct weston_keyboard *keyboard,
6514 const struct timespec *time, uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006515{
Derek Foreman8ae2db52015-07-15 13:00:36 -05006516 struct drm_backend *b =
Armin Krezović545dba62016-08-05 15:54:18 +02006517 to_drm_backend(keyboard->seat->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006518
Giulio Camuffo954f1832014-10-11 18:27:30 +03006519 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006520}
6521
Armin Krezović08368132016-09-30 14:11:05 +02006522static const struct weston_drm_output_api api = {
6523 drm_output_set_mode,
6524 drm_output_set_gbm_format,
6525 drm_output_set_seat,
6526};
6527
Giulio Camuffo954f1832014-10-11 18:27:30 +03006528static struct drm_backend *
6529drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006530 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006531{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006532 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01006533 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006534 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006535 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04006536 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02006537 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006538
nerdopolisb16c4ac2018-06-29 08:17:46 -04006539 session_seat = getenv("XDG_SEAT");
6540 if (session_seat)
6541 seat_id = session_seat;
6542
6543 if (config->seat_id)
6544 seat_id = config->seat_id;
6545
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04006546 weston_log("initializing drm backend\n");
6547
Giulio Camuffo954f1832014-10-11 18:27:30 +03006548 b = zalloc(sizeof *b);
6549 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006550 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01006551
Daniel Stone6020f472018-02-05 15:46:20 +00006552 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00006553 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00006554 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006555
Pekka Paalanen68583832015-05-19 09:53:16 +03006556 /*
6557 * KMS support for hardware planes cannot properly synchronize
6558 * without nuclear page flip. Without nuclear/atomic, hw plane
6559 * and cursor plane updates would either tear or cause extra
6560 * waits for vblanks which means dropping the compositor framerate
Pekka Paalanen3f32a132015-09-07 15:38:43 +03006561 * to a fraction. For cursors, it's not so bad, so they are
6562 * enabled.
Pekka Paalanen68583832015-05-19 09:53:16 +03006563 *
6564 * These can be enabled again when nuclear/atomic support lands.
6565 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03006566 b->sprites_are_broken = 1;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006567 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006568 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00006569 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02006570 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006571
Pekka Paalanen7da9a382017-08-30 11:29:49 +03006572 compositor->backend = &b->base;
6573
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006574 if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
6575 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006576
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006577 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006578 compositor->launcher = weston_launcher_connect(compositor, config->tty,
6579 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006580 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02006581 weston_log("fatal: drm backend should be run using "
6582 "weston-launch binary, or your system should "
6583 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006584 goto err_compositor;
6585 }
6586
Giulio Camuffo954f1832014-10-11 18:27:30 +03006587 b->udev = udev_new();
6588 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006589 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006590 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006591 }
6592
Giulio Camuffo954f1832014-10-11 18:27:30 +03006593 b->session_listener.notify = session_notify;
6594 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05006595
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03006596 if (config->specific_device)
6597 drm_device = open_specific_drm_device(b, config->specific_device);
6598 else
6599 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04006600 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006601 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006602 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006603 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006604
Daniel Stoneefa504f2016-12-19 16:48:20 +00006605 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02006606 weston_log("failed to initialize kms\n");
6607 goto err_udev_dev;
6608 }
6609
Giulio Camuffo954f1832014-10-11 18:27:30 +03006610 if (b->use_pixman) {
6611 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006612 weston_log("failed to initialize pixman renderer\n");
6613 goto err_udev_dev;
6614 }
6615 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03006616 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006617 weston_log("failed to initialize egl\n");
6618 goto err_udev_dev;
6619 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006620 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05006621
Giulio Camuffo954f1832014-10-11 18:27:30 +03006622 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00006623 b->base.repaint_begin = drm_repaint_begin;
6624 b->base.repaint_flush = drm_repaint_flush;
6625 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03006626 b->base.create_output = drm_output_create;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02006627
Bob Ham91880f12016-01-12 10:21:47 +00006628 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04006629
Daniel Stone085d2b92015-05-21 00:00:57 +01006630 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006631 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05006632
Giulio Camuffo954f1832014-10-11 18:27:30 +03006633 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03006634 compositor, b->udev, seat_id,
6635 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006636 weston_log("failed to create input devices\n");
6637 goto err_sprite;
6638 }
6639
Pekka Paalanend2e62422017-09-08 15:48:07 +03006640 if (drm_backend_create_heads(b, drm_device) < 0) {
6641 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006642 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006643 }
6644
Jason Ekstrand9fc71512014-04-02 19:53:46 -05006645 /* A this point we have some idea of whether or not we have a working
6646 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03006647 if (!b->cursors_are_broken)
6648 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05006649
Giulio Camuffo954f1832014-10-11 18:27:30 +03006650 loop = wl_display_get_event_loop(compositor->wl_display);
6651 b->drm_source =
6652 wl_event_loop_add_fd(loop, b->drm.fd,
6653 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006654
Giulio Camuffo954f1832014-10-11 18:27:30 +03006655 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
6656 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05006657 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01006658 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006659 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03006660 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006661 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006662 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02006663 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03006664 udev_monitor_get_fd(b->udev_monitor),
6665 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006666
Giulio Camuffo954f1832014-10-11 18:27:30 +03006667 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02006668 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01006669 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006670 }
6671
Daniel Stonea96b93c2012-06-22 14:04:37 +01006672 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006673
Giulio Camuffo954f1832014-10-11 18:27:30 +03006674 weston_compositor_add_debug_binding(compositor, KEY_O,
6675 planes_binding, b);
6676 weston_compositor_add_debug_binding(compositor, KEY_C,
6677 planes_binding, b);
6678 weston_compositor_add_debug_binding(compositor, KEY_V,
6679 planes_binding, b);
6680 weston_compositor_add_debug_binding(compositor, KEY_Q,
6681 recorder_binding, b);
6682 weston_compositor_add_debug_binding(compositor, KEY_W,
6683 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006684
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006685 if (compositor->renderer->import_dmabuf) {
6686 if (linux_dmabuf_setup(compositor) < 0)
6687 weston_log("Error: initializing dmabuf "
6688 "support failed.\n");
6689 }
6690
Armin Krezović08368132016-09-30 14:11:05 +02006691 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
6692 &api, sizeof(api));
6693
6694 if (ret < 0) {
6695 weston_log("Failed to register output API.\n");
6696 goto err_udev_monitor;
6697 }
6698
Giulio Camuffo954f1832014-10-11 18:27:30 +03006699 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01006700
6701err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006702 wl_event_source_remove(b->udev_drm_source);
6703 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006704err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006705 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006706err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006707 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04006708err_sprite:
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01006709 if (b->gbm)
6710 gbm_device_destroy(b->gbm);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006711 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006712err_udev_dev:
6713 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006714err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006715 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006716err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006717 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006718err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006719 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006720 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006721 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006722}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006723
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006724static void
6725config_init_to_defaults(struct weston_drm_backend_config *config)
6726{
Pekka Paalanendee412d2018-04-23 11:44:58 +02006727 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006728}
6729
Giulio Camuffo954f1832014-10-11 18:27:30 +03006730WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01006731weston_backend_init(struct weston_compositor *compositor,
6732 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006733{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006734 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006735 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006736
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006737 if (config_base == NULL ||
6738 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
6739 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
6740 weston_log("drm backend config structure is invalid\n");
6741 return -1;
6742 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02006743
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006744 config_init_to_defaults(&config);
6745 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07006746
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006747 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006748 if (b == NULL)
6749 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006750
Giulio Camuffo954f1832014-10-11 18:27:30 +03006751 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006752}