blob: 0ecfc9069530060413b3e270e1318acc92dcd08f [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Pekka Paalanen925788f2018-04-19 14:20:01 +03004 * Copyright © 2017, 2018 Collabora, Ltd.
5 * Copyright © 2017, 2018 General Electric Company
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07007 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070015 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027 */
28
Daniel Stonec228e232013-05-22 18:03:19 +030029#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040030
Jesse Barnes58ef3792012-02-23 09:45:49 -050031#include <errno.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030032#include <stdint.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010034#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040035#include <string.h>
36#include <fcntl.h>
37#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040038#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070039#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030040#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020041#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030042#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030043#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040044
Benjamin Franzkec649a922011-03-02 11:56:04 +010045#include <xf86drm.h>
46#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050047#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010048
Benjamin Franzke060cf802011-04-30 09:32:11 +020049#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040050#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020051
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070052#include "compositor.h"
53#include "compositor-drm.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070054#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020055#include "shared/timespec-util.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010056#include "gl-renderer.h"
Vincent Abriouc9506672016-10-05 16:14:07 +020057#include "weston-egl-ext.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020058#include "pixman-renderer.h"
Daniel Stone0b70fa42017-04-04 17:54:23 +010059#include "pixel-formats.h"
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070060#include "libbacklight.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100061#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010062#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030063#include "vaapi-recorder.h"
Pekka Paalanenb00c79b2016-02-18 16:53:27 +020064#include "presentation-time-server-protocol.h"
Pekka Paalanene4d231e2014-06-12 15:12:48 +030065#include "linux-dmabuf.h"
Micah Fedkec8890122017-02-01 15:28:23 -050066#include "linux-dmabuf-unstable-v1-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040067
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030068#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
69#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
70#endif
71
Pekka Paalanenc5de57f2015-05-20 23:01:44 +010072#ifndef DRM_CLIENT_CAP_UNIVERSAL_PLANES
73#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
74#endif
75
Ankit Nautiyala21c3932097-03-19 00:24:57 +053076#ifndef DRM_CLIENT_CAP_ASPECT_RATIO
77#define DRM_CLIENT_CAP_ASPECT_RATIO 4
78#endif
79
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030080#ifndef DRM_CAP_CURSOR_WIDTH
81#define DRM_CAP_CURSOR_WIDTH 0x8
82#endif
83
84#ifndef DRM_CAP_CURSOR_HEIGHT
85#define DRM_CAP_CURSOR_HEIGHT 0x9
86#endif
87
88#ifndef GBM_BO_USE_CURSOR
89#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
90#endif
91
Pekka Paalanendfc06832017-11-20 14:04:38 +020092#define MAX_CLONED_CONNECTORS 4
Pekka Paalanenc112f002017-08-28 16:27:20 +030093
Daniel Stone02cf4662017-03-03 16:19:39 +000094/**
Ankit Nautiyala21c3932097-03-19 00:24:57 +053095 * aspect ratio info taken from the drmModeModeInfo flag bits 19-22,
96 * which should be used to fill the aspect ratio field in weston_mode.
97 */
98#define DRM_MODE_FLAG_PIC_AR_BITS_POS 19
99#ifndef DRM_MODE_FLAG_PIC_AR_MASK
100#define DRM_MODE_FLAG_PIC_AR_MASK (0xF << DRM_MODE_FLAG_PIC_AR_BITS_POS)
101#endif
102
103/**
Daniel Stone02cf4662017-03-03 16:19:39 +0000104 * Represents the values of an enum-type KMS property
105 */
106struct drm_property_enum_info {
107 const char *name; /**< name as string (static, not freed) */
108 bool valid; /**< true if value is supported; ignore if false */
109 uint64_t value; /**< raw value */
110};
111
112/**
113 * Holds information on a DRM property, including its ID and the enum
114 * values it holds.
115 *
116 * DRM properties are allocated dynamically, and maintained as DRM objects
117 * within the normal object ID space; they thus do not have a stable ID
118 * to refer to. This includes enum values, which must be referred to by
119 * integer values, but these are not stable.
120 *
121 * drm_property_info allows a cache to be maintained where Weston can use
122 * enum values internally to refer to properties, with the mapping to DRM
123 * ID values being maintained internally.
124 */
125struct drm_property_info {
126 const char *name; /**< name as string (static, not freed) */
127 uint32_t prop_id; /**< KMS property object ID */
128 unsigned int num_enum_values; /**< number of enum values */
129 struct drm_property_enum_info *enum_values; /**< array of enum values */
130};
131
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000132/**
Daniel Stone598ee9d2016-11-16 11:55:20 +0000133 * List of properties attached to DRM planes
134 */
135enum wdrm_plane_property {
136 WDRM_PLANE_TYPE = 0,
137 WDRM_PLANE_SRC_X,
138 WDRM_PLANE_SRC_Y,
139 WDRM_PLANE_SRC_W,
140 WDRM_PLANE_SRC_H,
141 WDRM_PLANE_CRTC_X,
142 WDRM_PLANE_CRTC_Y,
143 WDRM_PLANE_CRTC_W,
144 WDRM_PLANE_CRTC_H,
145 WDRM_PLANE_FB_ID,
146 WDRM_PLANE_CRTC_ID,
147 WDRM_PLANE__COUNT
148};
149
150/**
151 * Possible values for the WDRM_PLANE_TYPE property.
152 */
153enum wdrm_plane_type {
154 WDRM_PLANE_TYPE_PRIMARY = 0,
155 WDRM_PLANE_TYPE_CURSOR,
156 WDRM_PLANE_TYPE_OVERLAY,
157 WDRM_PLANE_TYPE__COUNT
158};
159
160static struct drm_property_enum_info plane_type_enums[] = {
161 [WDRM_PLANE_TYPE_PRIMARY] = {
162 .name = "Primary",
163 },
164 [WDRM_PLANE_TYPE_OVERLAY] = {
165 .name = "Overlay",
166 },
167 [WDRM_PLANE_TYPE_CURSOR] = {
168 .name = "Cursor",
169 },
170};
171
172static const struct drm_property_info plane_props[] = {
173 [WDRM_PLANE_TYPE] = {
174 .name = "type",
175 .enum_values = plane_type_enums,
176 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
177 },
178 [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
179 [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
180 [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
181 [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
182 [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
183 [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
184 [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
185 [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
186 [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
187 [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
188};
189
190/**
191 * List of properties attached to a DRM connector
192 */
193enum wdrm_connector_property {
194 WDRM_CONNECTOR_EDID = 0,
195 WDRM_CONNECTOR_DPMS,
196 WDRM_CONNECTOR_CRTC_ID,
197 WDRM_CONNECTOR__COUNT
198};
199
200static const struct drm_property_info connector_props[] = {
201 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
202 [WDRM_CONNECTOR_DPMS] = { .name = "DPMS" },
203 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
204};
205
206/**
Pekka Paalanencd011a62016-11-15 22:07:49 +0000207 * List of properties attached to DRM CRTCs
208 */
209enum wdrm_crtc_property {
210 WDRM_CRTC_MODE_ID = 0,
211 WDRM_CRTC_ACTIVE,
212 WDRM_CRTC__COUNT
213};
214
Daniel Stone598ee9d2016-11-16 11:55:20 +0000215static const struct drm_property_info crtc_props[] = {
216 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
217 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
218};
219
Pekka Paalanencd011a62016-11-15 22:07:49 +0000220/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000221 * Mode for drm_output_state_duplicate.
222 */
223enum drm_output_state_duplicate_mode {
224 DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
225 DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
226};
227
228/**
229 * Mode for drm_pending_state_apply and co.
230 */
231enum drm_state_apply_mode {
232 DRM_STATE_APPLY_SYNC, /**< state fully processed */
233 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
234};
235
Giulio Camuffo954f1832014-10-11 18:27:30 +0300236struct drm_backend {
237 struct weston_backend base;
238 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400239
240 struct udev *udev;
241 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400242
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100243 struct udev_monitor *udev_monitor;
244 struct wl_event_source *udev_drm_source;
245
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100246 struct {
David Herrmannd7488c22012-03-11 20:05:21 +0100247 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100248 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300249 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100250 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200251 struct gbm_device *gbm;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700252 struct wl_listener session_listener;
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +0100253 uint32_t gbm_format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200254
Rob Clark4339add2012-08-09 14:18:28 -0500255 /* we need these parameters in order to not fail drmModeAddFB2()
256 * due to out of bounds dimensions, and then mistakenly set
257 * sprites_are_broken:
258 */
Daniel Stonef214fdc2016-11-14 17:43:57 +0000259 int min_width, max_width;
260 int min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -0500261
Daniel Stone085d2b92015-05-21 00:00:57 +0100262 struct wl_list plane_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500263 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200264 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500265
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000266 void *repaint_data;
267
Daniel Stone6020f472018-02-05 15:46:20 +0000268 bool state_invalid;
269
Pekka Paalaneneacec812017-09-12 13:43:51 +0300270 /* CRTC IDs not used by any enabled output. */
Daniel Stone087ddf02017-02-14 17:51:30 +0000271 struct wl_array unused_crtcs;
272
Rob Clarkab5b1e32012-08-09 13:24:45 -0500273 int cursors_are_broken;
274
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100275 bool universal_planes;
Pekka Paalanencd011a62016-11-15 22:07:49 +0000276 bool atomic_modeset;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100277
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200278 int use_pixman;
Pekka Paalanendee412d2018-04-23 11:44:58 +0200279 bool use_pixman_shadow;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200280
Rob Bradfordd355b802013-05-31 18:09:55 +0100281 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300282
Daniel Stone70d337d2015-06-16 18:42:23 +0100283 int32_t cursor_width;
284 int32_t cursor_height;
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +0000285
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000286 uint32_t pageflip_timeout;
Daniel Stoneb57c6a02017-10-05 16:27:21 +0100287
288 bool shutting_down;
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530289
290 bool aspect_ratio_supported;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400291};
292
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400293struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500294 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400295 drmModeModeInfo mode_info;
Daniel Stoned5526cb2016-11-16 10:54:10 +0000296 uint32_t blob_id;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400297};
298
Daniel Stonefc175a72017-04-04 17:54:22 +0100299enum drm_fb_type {
300 BUFFER_INVALID = 0, /**< never used */
301 BUFFER_CLIENT, /**< directly sourced from client */
302 BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
303 BUFFER_GBM_SURFACE, /**< internal EGL rendering */
Daniel Stonee4256832017-04-04 17:54:27 +0100304 BUFFER_CURSOR, /**< internal cursor buffer */
Daniel Stonefc175a72017-04-04 17:54:22 +0100305};
306
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300307struct drm_fb {
Daniel Stonefc175a72017-04-04 17:54:22 +0100308 enum drm_fb_type type;
309
Daniel Stone6e7a9612017-04-04 17:54:26 +0100310 int refcnt;
311
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200312 uint32_t fb_id, stride, handle, size;
Daniel Stone0b70fa42017-04-04 17:54:23 +0100313 const struct pixel_format_info *format;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000314 int width, height;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200315 int fd;
Pekka Paalanende685b82012-12-04 15:58:12 +0200316 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200317
318 /* Used by gbm fbs */
319 struct gbm_bo *bo;
Daniel Stone05a5ac22017-04-04 17:54:25 +0100320 struct gbm_surface *gbm_surface;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200321
322 /* Used by dumb fbs */
323 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300324};
325
Richard Hughes2b2092a2013-04-24 14:58:02 +0100326struct drm_edid {
327 char eisa_id[13];
328 char monitor_name[13];
329 char pnp_id[5];
330 char serial_number[13];
331};
332
Daniel Stone08d4edf2017-04-04 17:54:34 +0100333/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000334 * Pending state holds one or more drm_output_state structures, collected from
335 * performing repaint. This pending state is transient, and only lives between
336 * beginning a repaint group and flushing the results: after flush, each
337 * output state will complete and be retired separately.
338 */
339struct drm_pending_state {
340 struct drm_backend *backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000341 struct wl_list output_list;
342};
343
344/*
345 * Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
346 * plus >= 1 each of encoder/connector/plane. Since everything but the planes
347 * is currently statically assigned per-output, we mainly use this to track
348 * plane state.
349 *
350 * pending_state is set when the output state is owned by a pending_state,
351 * i.e. when it is being constructed and has not yet been applied. When the
352 * output state has been applied, the owning pending_state is freed.
353 */
354struct drm_output_state {
355 struct drm_pending_state *pending_state;
356 struct drm_output *output;
357 struct wl_list link;
Daniel Stonea08512f2016-11-08 17:46:10 +0000358 enum dpms_enum dpms;
Daniel Stonebc15f682016-11-14 16:57:01 +0000359 struct wl_list plane_list;
360};
361
362/**
363 * Plane state holds the dynamic state for a plane: where it is positioned,
364 * and which buffer it is currently displaying.
365 *
366 * The plane state is owned by an output state, except when setting an initial
367 * state. See drm_output_state for notes on state object lifetime.
368 */
369struct drm_plane_state {
370 struct drm_plane *plane;
371 struct drm_output *output;
372 struct drm_output_state *output_state;
373
374 struct drm_fb *fb;
375
376 int32_t src_x, src_y;
377 uint32_t src_w, src_h;
378 int32_t dest_x, dest_y;
379 uint32_t dest_w, dest_h;
380
381 bool complete;
382
383 struct wl_list link; /* drm_output_state::plane_list */
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000384};
385
386/**
Daniel Stone08d4edf2017-04-04 17:54:34 +0100387 * A plane represents one buffer, positioned within a CRTC, and stacked
388 * relative to other planes on the same CRTC.
389 *
390 * Each CRTC has a 'primary plane', which use used to display the classic
391 * framebuffer contents, as accessed through the legacy drmModeSetCrtc
392 * call (which combines setting the CRTC's actual physical mode, and the
393 * properties of the primary plane).
394 *
395 * The cursor plane also has its own alternate legacy API.
396 *
397 * Other planes are used opportunistically to display content we do not
398 * wish to blit into the primary plane. These non-primary/cursor planes
399 * are referred to as 'sprites'.
400 */
401struct drm_plane {
Daniel Stone08d4edf2017-04-04 17:54:34 +0100402 struct weston_plane base;
403
Daniel Stone08d4edf2017-04-04 17:54:34 +0100404 struct drm_backend *backend;
405
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100406 enum wdrm_plane_type type;
407
Daniel Stone08d4edf2017-04-04 17:54:34 +0100408 uint32_t possible_crtcs;
409 uint32_t plane_id;
410 uint32_t count_formats;
411
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100412 struct drm_property_info props[WDRM_PLANE__COUNT];
413
Daniel Stonebc15f682016-11-14 16:57:01 +0000414 /* The last state submitted to the kernel for this plane. */
415 struct drm_plane_state *state_cur;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100416
Daniel Stonebc15f682016-11-14 16:57:01 +0000417 struct wl_list link;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100418
419 uint32_t formats[];
420};
421
Pekka Paalanenc112f002017-08-28 16:27:20 +0300422struct drm_head {
423 struct weston_head base;
424 struct drm_backend *backend;
425
Armin Krezović08368132016-09-30 14:11:05 +0200426 drmModeConnector *connector;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400427 uint32_t connector_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100428 struct drm_edid edid;
Daniel Stone02cf4662017-03-03 16:19:39 +0000429
430 /* Holds the properties for the connector */
431 struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300432
433 struct backlight *backlight;
Pekka Paalanen13d233e2017-09-11 14:06:11 +0300434
435 drmModeModeInfo inherited_mode; /**< Original mode on the connector */
Pekka Paalanen27cc4812017-11-20 13:31:06 +0200436 uint32_t inherited_crtc_id; /**< Original CRTC assignment */
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300437};
438
439struct drm_output {
440 struct weston_output base;
441
442 uint32_t crtc_id; /* object ID to pass to DRM functions */
443 int pipe; /* index of CRTC in resource array / bitmasks */
444
Pekka Paalanencd011a62016-11-15 22:07:49 +0000445 /* Holds the properties for the CRTC */
446 struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200447
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300448 int vblank_pending;
449 int page_flip_pending;
Daniel Stone598ee9d2016-11-16 11:55:20 +0000450 int atomic_complete_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800451 int destroy_pending;
Armin Krezović08368132016-09-30 14:11:05 +0200452 int disable_pending;
Daniel Stonea08512f2016-11-08 17:46:10 +0000453 int dpms_off_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300454
Daniel Stonee4256832017-04-04 17:54:27 +0100455 struct drm_fb *gbm_cursor_fb[2];
Daniel Stone2ba17f42015-05-19 20:02:41 +0100456 struct drm_plane *cursor_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500457 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400458 int current_cursor;
Daniel Stone5bb8f582017-04-04 17:54:28 +0100459
460 struct gbm_surface *gbm_surface;
461 uint32_t gbm_format;
462
Daniel Stonee2e80132018-01-16 15:37:33 +0000463 /* Plane being displayed directly on the CRTC */
464 struct drm_plane *scanout_plane;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200465
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000466 /* The last state submitted to the kernel for this CRTC. */
467 struct drm_output_state *state_cur;
468 /* The previously-submitted state, where the hardware has not
469 * yet acknowledged completion of state_cur. */
470 struct drm_output_state *state_last;
471
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200472 struct drm_fb *dumb[2];
473 pixman_image_t *image[2];
474 int current_image;
475 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300476
477 struct vaapi_recorder *recorder;
478 struct wl_listener recorder_frame_listener;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000479
480 struct wl_event_source *pageflip_timer;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400481};
482
Ankit Nautiyala21c3932097-03-19 00:24:57 +0530483static const char *const aspect_ratio_as_string[] = {
484 [WESTON_MODE_PIC_AR_NONE] = "",
485 [WESTON_MODE_PIC_AR_4_3] = " 4:3",
486 [WESTON_MODE_PIC_AR_16_9] = " 16:9",
487 [WESTON_MODE_PIC_AR_64_27] = " 64:27",
488 [WESTON_MODE_PIC_AR_256_135] = " 256:135",
489};
490
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300491static struct gl_renderer_interface *gl_renderer;
492
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500493static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400494
Daniel Stone087ddf02017-02-14 17:51:30 +0000495static void
496wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
497{
498 uint32_t *pos, *end;
499
500 end = (uint32_t *) ((char *) array->data + array->size);
501
502 wl_array_for_each(pos, array) {
503 if (*pos != elm)
504 continue;
505
506 array->size -= sizeof(*pos);
507 if (pos + 1 == end)
508 break;
509
510 memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
511 break;
512 }
513}
514
Pekka Paalanenc112f002017-08-28 16:27:20 +0300515static inline struct drm_head *
516to_drm_head(struct weston_head *base)
517{
518 return container_of(base, struct drm_head, base);
519}
520
Armin Krezović545dba62016-08-05 15:54:18 +0200521static inline struct drm_output *
522to_drm_output(struct weston_output *base)
523{
524 return container_of(base, struct drm_output, base);
525}
526
527static inline struct drm_backend *
528to_drm_backend(struct weston_compositor *base)
529{
530 return container_of(base->backend, struct drm_backend, base);
531}
532
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000533static int
534pageflip_timeout(void *data) {
535 /*
536 * Our timer just went off, that means we're not receiving drm
537 * page flip events anymore for that output. Let's gracefully exit
538 * weston with a return value so devs can debug what's going on.
539 */
540 struct drm_output *output = data;
541 struct weston_compositor *compositor = output->base.compositor;
542
543 weston_log("Pageflip timeout reached on output %s, your "
544 "driver is probably buggy! Exiting.\n",
545 output->base.name);
546 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
547
548 return 0;
549}
550
551/* Creates the pageflip timer. Note that it isn't armed by default */
552static int
553drm_output_pageflip_timer_create(struct drm_output *output)
554{
555 struct wl_event_loop *loop = NULL;
556 struct weston_compositor *ec = output->base.compositor;
557
558 loop = wl_display_get_event_loop(ec->wl_display);
559 assert(loop);
560 output->pageflip_timer = wl_event_loop_add_timer(loop,
561 pageflip_timeout,
562 output);
563
564 if (output->pageflip_timer == NULL) {
565 weston_log("creating drm pageflip timer failed: %m\n");
566 return -1;
567 }
568
569 return 0;
570}
571
Daniel Stonecb04cc42016-11-16 11:51:27 +0000572static inline struct drm_mode *
573to_drm_mode(struct weston_mode *base)
574{
575 return container_of(base, struct drm_mode, base);
576}
577
Daniel Stone02cf4662017-03-03 16:19:39 +0000578/**
579 * Get the current value of a KMS property
580 *
581 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
582 * for the target property, return the current value of that property,
583 * with an optional default. If the property is a KMS enum type, the return
584 * value will be translated into the appropriate internal enum.
585 *
586 * If the property is not present, the default value will be returned.
587 *
588 * @param info Internal structure for property to look up
589 * @param props Raw KMS properties for the target object
590 * @param def Value to return if property is not found
591 */
592static uint64_t
593drm_property_get_value(struct drm_property_info *info,
Daniel Stone85eebdf2018-07-05 17:55:43 +0100594 const drmModeObjectProperties *props,
Daniel Stone02cf4662017-03-03 16:19:39 +0000595 uint64_t def)
596{
597 unsigned int i;
598
599 if (info->prop_id == 0)
600 return def;
601
602 for (i = 0; i < props->count_props; i++) {
603 unsigned int j;
604
605 if (props->props[i] != info->prop_id)
606 continue;
607
608 /* Simple (non-enum) types can return the value directly */
609 if (info->num_enum_values == 0)
610 return props->prop_values[i];
611
612 /* Map from raw value to enum value */
613 for (j = 0; j < info->num_enum_values; j++) {
614 if (!info->enum_values[j].valid)
615 continue;
616 if (info->enum_values[j].value != props->prop_values[i])
617 continue;
618
619 return j;
620 }
621
622 /* We don't have a mapping for this enum; return default. */
623 break;
624 }
625
626 return def;
627}
628
629/**
630 * Cache DRM property values
631 *
632 * Update a per-object array of drm_property_info structures, given the
633 * DRM properties of the object.
634 *
635 * Call this every time an object newly appears (note that only connectors
636 * can be hotplugged), the first time it is seen, or when its status changes
637 * in a way which invalidates the potential property values (currently, the
638 * only case for this is connector hotplug).
639 *
640 * This updates the property IDs and enum values within the drm_property_info
641 * array.
642 *
643 * DRM property enum values are dynamic at runtime; the user must query the
644 * property to find out the desired runtime value for a requested string
645 * name. Using the 'type' field on planes as an example, there is no single
646 * hardcoded constant for primary plane types; instead, the property must be
647 * queried at runtime to find the value associated with the string "Primary".
648 *
649 * This helper queries and caches the enum values, to allow us to use a set
650 * of compile-time-constant enums portably across various implementations.
651 * The values given in enum_names are searched for, and stored in the
652 * same-indexed field of the map array.
653 *
654 * @param b DRM backend object
655 * @param src DRM property info array to source from
656 * @param info DRM property info array to copy into
657 * @param num_infos Number of entries in the source array
658 * @param props DRM object properties for the object
659 */
660static void
661drm_property_info_populate(struct drm_backend *b,
662 const struct drm_property_info *src,
663 struct drm_property_info *info,
664 unsigned int num_infos,
665 drmModeObjectProperties *props)
666{
667 drmModePropertyRes *prop;
668 unsigned i, j;
669
670 for (i = 0; i < num_infos; i++) {
671 unsigned int j;
672
673 info[i].name = src[i].name;
674 info[i].prop_id = 0;
675 info[i].num_enum_values = src[i].num_enum_values;
676
677 if (src[i].num_enum_values == 0)
678 continue;
679
680 info[i].enum_values =
681 malloc(src[i].num_enum_values *
682 sizeof(*info[i].enum_values));
683 assert(info[i].enum_values);
684 for (j = 0; j < info[i].num_enum_values; j++) {
685 info[i].enum_values[j].name = src[i].enum_values[j].name;
686 info[i].enum_values[j].valid = false;
687 }
688 }
689
690 for (i = 0; i < props->count_props; i++) {
691 unsigned int k;
692
693 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
694 if (!prop)
695 continue;
696
697 for (j = 0; j < num_infos; j++) {
698 if (!strcmp(prop->name, info[j].name))
699 break;
700 }
701
702 /* We don't know/care about this property. */
703 if (j == num_infos) {
704#ifdef DEBUG
705 weston_log("DRM debug: unrecognized property %u '%s'\n",
706 prop->prop_id, prop->name);
707#endif
708 drmModeFreeProperty(prop);
709 continue;
710 }
711
712 if (info[j].num_enum_values == 0 &&
713 (prop->flags & DRM_MODE_PROP_ENUM)) {
714 weston_log("DRM: expected property %s to not be an"
715 " enum, but it is; ignoring\n", prop->name);
716 drmModeFreeProperty(prop);
717 continue;
718 }
719
720 info[j].prop_id = props->props[i];
721
722 if (info[j].num_enum_values == 0) {
723 drmModeFreeProperty(prop);
724 continue;
725 }
726
727 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
728 weston_log("DRM: expected property %s to be an enum,"
729 " but it is not; ignoring\n", prop->name);
730 drmModeFreeProperty(prop);
731 info[j].prop_id = 0;
732 continue;
733 }
734
735 for (k = 0; k < info[j].num_enum_values; k++) {
736 int l;
737
738 for (l = 0; l < prop->count_enums; l++) {
739 if (!strcmp(prop->enums[l].name,
740 info[j].enum_values[k].name))
741 break;
742 }
743
744 if (l == prop->count_enums)
745 continue;
746
747 info[j].enum_values[k].valid = true;
748 info[j].enum_values[k].value = prop->enums[l].value;
749 }
750
751 drmModeFreeProperty(prop);
752 }
753
754#ifdef DEBUG
755 for (i = 0; i < num_infos; i++) {
756 if (info[i].prop_id == 0)
757 weston_log("DRM warning: property '%s' missing\n",
758 info[i].name);
759 }
760#endif
761}
762
763/**
764 * Free DRM property information
765 *
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300766 * Frees all memory associated with a DRM property info array and zeroes
767 * it out, leaving it usable for a further drm_property_info_update() or
768 * drm_property_info_free().
Daniel Stone02cf4662017-03-03 16:19:39 +0000769 *
770 * @param info DRM property info array
771 * @param num_props Number of entries in array to free
772 */
773static void
774drm_property_info_free(struct drm_property_info *info, int num_props)
775{
776 int i;
777
778 for (i = 0; i < num_props; i++)
779 free(info[i].enum_values);
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300780
781 memset(info, 0, sizeof(*info) * num_props);
Daniel Stone02cf4662017-03-03 16:19:39 +0000782}
783
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400784static void
Daniel Stone2ba17f42015-05-19 20:02:41 +0100785drm_output_set_cursor(struct drm_output_state *output_state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400786
Mario Kleinerf507ec32015-06-21 21:25:14 +0200787static void
788drm_output_update_msc(struct drm_output *output, unsigned int seq);
789
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000790static void
791drm_output_destroy(struct weston_output *output_base);
792
Daniel Stone5ff289a2017-10-07 12:59:02 +0100793/**
794 * Returns true if the plane can be used on the given output for its current
795 * repaint cycle.
796 */
797static bool
798drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100800 assert(plane->state_cur);
801
802 /* The plane still has a request not yet completed by the kernel. */
803 if (!plane->state_cur->complete)
804 return false;
805
806 /* The plane is still active on another output. */
807 if (plane->state_cur->output && plane->state_cur->output != output)
808 return false;
809
810 /* Check whether the plane can be used with this CRTC; possible_crtcs
811 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Daniel Stone08d4edf2017-04-04 17:54:34 +0100812 return !!(plane->possible_crtcs & (1 << output->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500813}
814
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000815static struct drm_output *
816drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
817{
818 struct drm_output *output;
819
820 wl_list_for_each(output, &b->compositor->output_list, base.link) {
821 if (output->crtc_id == crtc_id)
822 return output;
823 }
824
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000825 return NULL;
826}
827
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300828static struct drm_head *
829drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
830{
831 struct weston_head *base;
832 struct drm_head *head;
833
834 wl_list_for_each(base,
835 &backend->compositor->head_list, compositor_link) {
836 head = to_drm_head(base);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300837 if (head->connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300838 return head;
839 }
840
841 return NULL;
842}
843
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300844static void
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100845drm_fb_destroy(struct drm_fb *fb)
846{
847 if (fb->fb_id != 0)
848 drmModeRmFB(fb->fd, fb->fb_id);
849 weston_buffer_reference(&fb->buffer_ref, NULL);
850 free(fb);
851}
852
853static void
854drm_fb_destroy_dumb(struct drm_fb *fb)
855{
856 struct drm_mode_destroy_dumb destroy_arg;
857
858 assert(fb->type == BUFFER_PIXMAN_DUMB);
859
860 if (fb->map && fb->size > 0)
861 munmap(fb->map, fb->size);
862
863 memset(&destroy_arg, 0, sizeof(destroy_arg));
864 destroy_arg.handle = fb->handle;
865 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
866
867 drm_fb_destroy(fb);
868}
869
870static void
871drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300872{
873 struct drm_fb *fb = data;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300874
Daniel Stonee4256832017-04-04 17:54:27 +0100875 assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
876 fb->type == BUFFER_CURSOR);
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100877 drm_fb_destroy(fb);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300878}
879
880static struct drm_fb *
Daniel Stonef214fdc2016-11-14 17:43:57 +0000881drm_fb_create_dumb(struct drm_backend *b, int width, int height,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300882 uint32_t format)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200883{
884 struct drm_fb *fb;
885 int ret;
886
887 struct drm_mode_create_dumb create_arg;
888 struct drm_mode_destroy_dumb destroy_arg;
889 struct drm_mode_map_dumb map_arg;
Daniel Stone1de42522016-11-17 18:17:16 +0000890 uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200891
Peter Huttererf3d62272013-08-08 11:57:05 +1000892 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200893 if (!fb)
894 return NULL;
895
Daniel Stone6e7a9612017-04-04 17:54:26 +0100896 fb->refcnt = 1;
897
Daniel Stone0b70fa42017-04-04 17:54:23 +0100898 fb->format = pixel_format_get_info(format);
899 if (!fb->format) {
900 weston_log("failed to look up format 0x%lx\n",
901 (unsigned long) format);
902 goto err_fb;
903 }
904
905 if (!fb->format->depth || !fb->format->bpp) {
906 weston_log("format 0x%lx is not compatible with dumb buffers\n",
907 (unsigned long) format);
908 goto err_fb;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300909 }
910
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700911 memset(&create_arg, 0, sizeof create_arg);
Daniel Stone0b70fa42017-04-04 17:54:23 +0100912 create_arg.bpp = fb->format->bpp;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200913 create_arg.width = width;
914 create_arg.height = height;
915
Giulio Camuffo954f1832014-10-11 18:27:30 +0300916 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200917 if (ret)
918 goto err_fb;
919
Daniel Stonefc175a72017-04-04 17:54:22 +0100920 fb->type = BUFFER_PIXMAN_DUMB;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200921 fb->handle = create_arg.handle;
922 fb->stride = create_arg.pitch;
923 fb->size = create_arg.size;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000924 fb->width = width;
925 fb->height = height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300926 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200927
Daniel Stone1de42522016-11-17 18:17:16 +0000928 handles[0] = fb->handle;
929 pitches[0] = fb->stride;
930 offsets[0] = 0;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300931
Daniel Stone1de42522016-11-17 18:17:16 +0000932 ret = drmModeAddFB2(b->drm.fd, width, height, fb->format->format,
933 handles, pitches, offsets, &fb->fb_id, 0);
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300934 if (ret) {
Daniel Stone0b70fa42017-04-04 17:54:23 +0100935 ret = drmModeAddFB(b->drm.fd, width, height,
936 fb->format->depth, fb->format->bpp,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300937 fb->stride, fb->handle, &fb->fb_id);
938 }
939
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200940 if (ret)
941 goto err_bo;
942
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700943 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200944 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400945 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200946 if (ret)
947 goto err_add_fb;
948
Chris Michael4a7ce1f2015-11-10 10:40:37 -0500949 fb->map = mmap(NULL, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300950 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200951 if (fb->map == MAP_FAILED)
952 goto err_add_fb;
953
954 return fb;
955
956err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300957 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200958err_bo:
959 memset(&destroy_arg, 0, sizeof(destroy_arg));
960 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300961 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200962err_fb:
963 free(fb);
964 return NULL;
965}
966
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200967static struct drm_fb *
Daniel Stone6e7a9612017-04-04 17:54:26 +0100968drm_fb_ref(struct drm_fb *fb)
969{
970 fb->refcnt++;
971 return fb;
972}
973
974static struct drm_fb *
Daniel Stonefc175a72017-04-04 17:54:22 +0100975drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
Daniel Stonedb10df12016-12-08 13:15:58 +0000976 bool is_opaque, enum drm_fb_type type)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300977{
978 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Derek Foreman482ffdf2016-07-08 12:50:57 -0500979 uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300980 int ret;
981
Daniel Stonefc175a72017-04-04 17:54:22 +0100982 if (fb) {
983 assert(fb->type == type);
Daniel Stone6e7a9612017-04-04 17:54:26 +0100984 return drm_fb_ref(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +0100985 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300986
Bryce Harringtonde16d892014-11-20 22:21:57 -0800987 fb = zalloc(sizeof *fb);
988 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200989 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300990
Daniel Stonefc175a72017-04-04 17:54:22 +0100991 fb->type = type;
Daniel Stone6e7a9612017-04-04 17:54:26 +0100992 fb->refcnt = 1;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300993 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300994
Daniel Stonec8c917c2016-11-14 17:45:58 +0000995 fb->width = gbm_bo_get_width(bo);
996 fb->height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200997 fb->stride = gbm_bo_get_stride(bo);
998 fb->handle = gbm_bo_get_handle(bo).u32;
Daniel Stonedb10df12016-12-08 13:15:58 +0000999 fb->format = pixel_format_get_info(gbm_bo_get_format(bo));
Daniel Stonec8c917c2016-11-14 17:45:58 +00001000 fb->size = fb->stride * fb->height;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001001 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001002
Daniel Stone0b70fa42017-04-04 17:54:23 +01001003 if (!fb->format) {
1004 weston_log("couldn't look up format 0x%lx\n",
Daniel Stonedb10df12016-12-08 13:15:58 +00001005 (unsigned long) gbm_bo_get_format(bo));
Daniel Stone0b70fa42017-04-04 17:54:23 +01001006 goto err_free;
1007 }
1008
Daniel Stonedb10df12016-12-08 13:15:58 +00001009 /* We can scanout an ARGB buffer if the surface's opaque region covers
1010 * the whole output, but we have to use XRGB as the KMS format code. */
1011 if (is_opaque)
1012 fb->format = pixel_format_get_opaque_substitute(fb->format);
1013
Daniel Stonec8c917c2016-11-14 17:45:58 +00001014 if (backend->min_width > fb->width ||
1015 fb->width > backend->max_width ||
1016 backend->min_height > fb->height ||
1017 fb->height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001018 weston_log("bo geometry out of bounds\n");
1019 goto err_free;
1020 }
1021
Daniel Stone1de42522016-11-17 18:17:16 +00001022 handles[0] = fb->handle;
1023 pitches[0] = fb->stride;
1024 offsets[0] = 0;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001025
Daniel Stone1de42522016-11-17 18:17:16 +00001026 ret = drmModeAddFB2(backend->drm.fd, fb->width, fb->height,
1027 fb->format->format, handles, pitches, offsets,
1028 &fb->fb_id, 0);
Daniel Stone0b70fa42017-04-04 17:54:23 +01001029 if (ret && fb->format->depth && fb->format->bpp)
Daniel Stonec8c917c2016-11-14 17:45:58 +00001030 ret = drmModeAddFB(backend->drm.fd, fb->width, fb->height,
Daniel Stone0b70fa42017-04-04 17:54:23 +01001031 fb->format->depth, fb->format->bpp,
1032 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001033
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001034 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001035 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001036 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001037 }
1038
Tomohito Esaki576f42e2017-04-04 17:54:24 +01001039 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001040
1041 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001042
1043err_free:
1044 free(fb);
1045 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001046}
1047
1048static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001049drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001050{
Pekka Paalanende685b82012-12-04 15:58:12 +02001051 assert(fb->buffer_ref.buffer == NULL);
Daniel Stonefc175a72017-04-04 17:54:22 +01001052 assert(fb->type == BUFFER_CLIENT);
Pekka Paalanende685b82012-12-04 15:58:12 +02001053 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001054}
1055
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001056static void
Daniel Stone05a5ac22017-04-04 17:54:25 +01001057drm_fb_unref(struct drm_fb *fb)
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001058{
1059 if (!fb)
1060 return;
1061
Daniel Stone6e7a9612017-04-04 17:54:26 +01001062 assert(fb->refcnt > 0);
1063 if (--fb->refcnt > 0)
1064 return;
1065
Daniel Stonefc175a72017-04-04 17:54:22 +01001066 switch (fb->type) {
1067 case BUFFER_PIXMAN_DUMB:
Daniel Stone6e7a9612017-04-04 17:54:26 +01001068 drm_fb_destroy_dumb(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +01001069 break;
Daniel Stonee4256832017-04-04 17:54:27 +01001070 case BUFFER_CURSOR:
Daniel Stonefc175a72017-04-04 17:54:22 +01001071 case BUFFER_CLIENT:
1072 gbm_bo_destroy(fb->bo);
1073 break;
1074 case BUFFER_GBM_SURFACE:
Daniel Stone05a5ac22017-04-04 17:54:25 +01001075 gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
Daniel Stonefc175a72017-04-04 17:54:22 +01001076 break;
1077 default:
1078 assert(NULL);
1079 break;
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001080 }
1081}
1082
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001083/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001084 * Allocate a new, empty, plane state.
1085 */
1086static struct drm_plane_state *
1087drm_plane_state_alloc(struct drm_output_state *state_output,
1088 struct drm_plane *plane)
1089{
1090 struct drm_plane_state *state = zalloc(sizeof(*state));
1091
1092 assert(state);
1093 state->output_state = state_output;
1094 state->plane = plane;
1095
1096 /* Here we only add the plane state to the desired link, and not
1097 * set the member. Having an output pointer set means that the
1098 * plane will be displayed on the output; this won't be the case
1099 * when we go to disable a plane. In this case, it must be part of
1100 * the commit (and thus the output state), but the member must be
1101 * NULL, as it will not be on any output when the state takes
1102 * effect.
1103 */
1104 if (state_output)
1105 wl_list_insert(&state_output->plane_list, &state->link);
1106 else
1107 wl_list_init(&state->link);
1108
1109 return state;
1110}
1111
1112/**
1113 * Free an existing plane state. As a special case, the state will not
1114 * normally be freed if it is the current state; see drm_plane_set_state.
1115 */
1116static void
1117drm_plane_state_free(struct drm_plane_state *state, bool force)
1118{
1119 if (!state)
1120 return;
1121
1122 wl_list_remove(&state->link);
1123 wl_list_init(&state->link);
1124 state->output_state = NULL;
1125
1126 if (force || state != state->plane->state_cur) {
1127 drm_fb_unref(state->fb);
1128 free(state);
1129 }
1130}
1131
1132/**
1133 * Duplicate an existing plane state into a new plane state, storing it within
1134 * the given output state. If the output state already contains a plane state
1135 * for the drm_plane referenced by 'src', that plane state is freed first.
1136 */
1137static struct drm_plane_state *
1138drm_plane_state_duplicate(struct drm_output_state *state_output,
1139 struct drm_plane_state *src)
1140{
1141 struct drm_plane_state *dst = malloc(sizeof(*dst));
1142 struct drm_plane_state *old, *tmp;
1143
1144 assert(src);
1145 assert(dst);
1146 *dst = *src;
1147 wl_list_init(&dst->link);
1148
1149 wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
1150 /* Duplicating a plane state into the same output state, so
1151 * it can replace itself with an identical copy of itself,
1152 * makes no sense. */
1153 assert(old != src);
1154 if (old->plane == dst->plane)
1155 drm_plane_state_free(old, false);
1156 }
1157
1158 wl_list_insert(&state_output->plane_list, &dst->link);
1159 if (src->fb)
1160 dst->fb = drm_fb_ref(src->fb);
1161 dst->output_state = state_output;
1162 dst->complete = false;
1163
1164 return dst;
1165}
1166
1167/**
1168 * Remove a plane state from an output state; if the plane was previously
1169 * enabled, then replace it with a disabling state. This ensures that the
1170 * output state was untouched from it was before the plane state was
1171 * modified by the caller of this function.
1172 *
1173 * This is required as drm_output_state_get_plane may either allocate a
1174 * new plane state, in which case this function will just perform a matching
1175 * drm_plane_state_free, or it may instead repurpose an existing disabling
1176 * state (if the plane was previously active), in which case this function
1177 * will reset it.
1178 */
1179static void
1180drm_plane_state_put_back(struct drm_plane_state *state)
1181{
1182 struct drm_output_state *state_output;
1183 struct drm_plane *plane;
1184
1185 if (!state)
1186 return;
1187
1188 state_output = state->output_state;
1189 plane = state->plane;
1190 drm_plane_state_free(state, false);
1191
1192 /* Plane was previously disabled; no need to keep this temporary
1193 * state around. */
1194 if (!plane->state_cur->fb)
1195 return;
1196
1197 (void) drm_plane_state_alloc(state_output, plane);
1198}
1199
Daniel Stonece137472016-11-16 19:35:03 +00001200static bool
1201drm_view_transform_supported(struct weston_view *ev, struct weston_output *output)
1202{
1203 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
1204
1205 /* This will incorrectly disallow cases where the combination of
1206 * buffer and view transformations match the output transform.
1207 * Fixing this requires a full analysis of the transformation
1208 * chain. */
1209 if (ev->transform.enabled &&
1210 ev->transform.matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE)
1211 return false;
1212
1213 if (viewport->buffer.transform != output->transform)
1214 return false;
1215
1216 return true;
1217}
1218
Daniel Stonebc15f682016-11-14 16:57:01 +00001219/**
Daniel Stoned6e2a762016-11-16 19:33:20 +00001220 * Given a weston_view, fill the drm_plane_state's co-ordinates to display on
1221 * a given plane.
1222 */
Daniel Stonece137472016-11-16 19:35:03 +00001223static bool
Daniel Stoned6e2a762016-11-16 19:33:20 +00001224drm_plane_state_coords_for_view(struct drm_plane_state *state,
1225 struct weston_view *ev)
1226{
1227 struct drm_output *output = state->output;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001228 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001229 pixman_region32_t dest_rect, src_rect;
1230 pixman_box32_t *box, tbox;
Daniel Stonedf2726a2017-02-07 18:48:19 +00001231 float sxf1, syf1, sxf2, syf2;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001232
Daniel Stonece137472016-11-16 19:35:03 +00001233 if (!drm_view_transform_supported(ev, &output->base))
1234 return false;
1235
Daniel Stoned6e2a762016-11-16 19:33:20 +00001236 /* Update the base weston_plane co-ordinates. */
1237 box = pixman_region32_extents(&ev->transform.boundingbox);
1238 state->plane->base.x = box->x1;
1239 state->plane->base.y = box->y1;
1240
1241 /* First calculate the destination co-ordinates by taking the
1242 * area of the view which is visible on this output, performing any
1243 * transforms to account for output rotation and scale as necessary. */
1244 pixman_region32_init(&dest_rect);
1245 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
1246 &output->base.region);
1247 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
1248 box = pixman_region32_extents(&dest_rect);
1249 tbox = weston_transformed_rect(output->base.width,
1250 output->base.height,
1251 output->base.transform,
1252 output->base.current_scale,
1253 *box);
1254 state->dest_x = tbox.x1;
1255 state->dest_y = tbox.y1;
1256 state->dest_w = tbox.x2 - tbox.x1;
1257 state->dest_h = tbox.y2 - tbox.y1;
1258 pixman_region32_fini(&dest_rect);
1259
1260 /* Now calculate the source rectangle, by finding the extents of the
1261 * view, and working backwards to source co-ordinates. */
1262 pixman_region32_init(&src_rect);
1263 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
1264 &output->base.region);
1265 box = pixman_region32_extents(&src_rect);
Daniel Stonedf2726a2017-02-07 18:48:19 +00001266 weston_view_from_global_float(ev, box->x1, box->y1, &sxf1, &syf1);
1267 weston_surface_to_buffer_float(ev->surface, sxf1, syf1, &sxf1, &syf1);
1268 weston_view_from_global_float(ev, box->x2, box->y2, &sxf2, &syf2);
1269 weston_surface_to_buffer_float(ev->surface, sxf2, syf2, &sxf2, &syf2);
1270 pixman_region32_fini(&src_rect);
Daniel Stoned6e2a762016-11-16 19:33:20 +00001271
Daniel Stonedf2726a2017-02-07 18:48:19 +00001272 /* Buffer transforms may mean that x2 is to the left of x1, and/or that
1273 * y2 is above y1. */
1274 if (sxf2 < sxf1) {
1275 double tmp = sxf1;
1276 sxf1 = sxf2;
1277 sxf2 = tmp;
1278 }
1279 if (syf2 < syf1) {
1280 double tmp = syf1;
1281 syf1 = syf2;
1282 syf2 = tmp;
1283 }
1284
1285 /* Shift from S23.8 wl_fixed to U16.16 KMS fixed-point encoding. */
1286 state->src_x = wl_fixed_from_double(sxf1) << 8;
1287 state->src_y = wl_fixed_from_double(syf1) << 8;
1288 state->src_w = wl_fixed_from_double(sxf2 - sxf1) << 8;
1289 state->src_h = wl_fixed_from_double(syf2 - syf1) << 8;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001290
1291 /* Clamp our source co-ordinates to surface bounds; it's possible
1292 * for intermediate translations to give us slightly incorrect
1293 * co-ordinates if we have, for example, multiple zooming
1294 * transformations. View bounding boxes are also explicitly rounded
1295 * greedily. */
Daniel Stonedf2726a2017-02-07 18:48:19 +00001296 if (state->src_x < 0)
1297 state->src_x = 0;
1298 if (state->src_y < 0)
1299 state->src_y = 0;
1300 if (state->src_w > (uint32_t) ((buffer->width << 16) - state->src_x))
1301 state->src_w = (buffer->width << 16) - state->src_x;
1302 if (state->src_h > (uint32_t) ((buffer->height << 16) - state->src_y))
1303 state->src_h = (buffer->height << 16) - state->src_y;
Daniel Stonece137472016-11-16 19:35:03 +00001304
1305 return true;
Daniel Stoned6e2a762016-11-16 19:33:20 +00001306}
1307
Daniel Stonef11ec022016-11-17 17:32:42 +00001308static bool
1309drm_view_is_opaque(struct weston_view *ev)
1310{
1311 pixman_region32_t r;
1312 bool ret = false;
1313
1314 pixman_region32_init_rect(&r, 0, 0,
1315 ev->surface->width,
1316 ev->surface->height);
1317 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
1318
1319 if (!pixman_region32_not_empty(&r))
1320 ret = true;
1321
1322 pixman_region32_fini(&r);
1323
1324 return ret;
1325}
1326
1327static struct drm_fb *
1328drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
1329{
1330 struct drm_output *output = state->output;
1331 struct drm_backend *b = to_drm_backend(output->base.compositor);
1332 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
1333 struct linux_dmabuf_buffer *dmabuf;
1334 struct drm_fb *fb;
1335 struct gbm_bo *bo;
1336
1337 /* Don't import buffers which span multiple outputs. */
1338 if (ev->output_mask != (1u << output->base.id))
1339 return NULL;
1340
1341 if (ev->alpha != 1.0f)
1342 return NULL;
1343
1344 if (!drm_view_transform_supported(ev, &output->base))
1345 return NULL;
1346
1347 if (!buffer)
1348 return NULL;
1349
1350 if (wl_shm_buffer_get(buffer->resource))
1351 return NULL;
1352
1353 if (!b->gbm)
1354 return NULL;
1355
1356 dmabuf = linux_dmabuf_buffer_get(buffer->resource);
1357 if (dmabuf) {
1358#ifdef HAVE_GBM_FD_IMPORT
1359 /* XXX: TODO:
1360 *
1361 * Use AddFB2 directly, do not go via GBM.
1362 * Add support for multiplanar formats.
1363 * Both require refactoring in the DRM-backend to
1364 * support a mix of gbm_bos and drmfbs.
1365 */
1366 struct gbm_import_fd_data gbm_dmabuf = {
1367 .fd = dmabuf->attributes.fd[0],
1368 .width = dmabuf->attributes.width,
1369 .height = dmabuf->attributes.height,
1370 .stride = dmabuf->attributes.stride[0],
1371 .format = dmabuf->attributes.format
1372 };
1373
1374 /* XXX: TODO:
1375 *
1376 * Currently the buffer is rejected if any dmabuf attribute
1377 * flag is set. This keeps us from passing an inverted /
1378 * interlaced / bottom-first buffer (or any other type that may
1379 * be added in the future) through to an overlay. Ultimately,
1380 * these types of buffers should be handled through buffer
1381 * transforms and not as spot-checks requiring specific
1382 * knowledge. */
1383 if (dmabuf->attributes.n_planes != 1 ||
1384 dmabuf->attributes.offset[0] != 0 ||
1385 dmabuf->attributes.flags)
1386 return NULL;
1387
1388 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
1389 GBM_BO_USE_SCANOUT);
1390#else
1391 return NULL;
1392#endif
1393 } else {
1394 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
1395 buffer->resource, GBM_BO_USE_SCANOUT);
1396 }
1397
1398 if (!bo)
1399 return NULL;
1400
1401 fb = drm_fb_get_from_bo(bo, b, drm_view_is_opaque(ev), BUFFER_CLIENT);
1402 if (!fb) {
1403 gbm_bo_destroy(bo);
1404 return NULL;
1405 }
1406
1407 drm_fb_set_buffer(fb, buffer);
1408 return fb;
1409}
1410
Daniel Stoned6e2a762016-11-16 19:33:20 +00001411/**
Daniel Stone2ba17f42015-05-19 20:02:41 +01001412 * Return a plane state from a drm_output_state.
1413 */
1414static struct drm_plane_state *
1415drm_output_state_get_existing_plane(struct drm_output_state *state_output,
1416 struct drm_plane *plane)
1417{
1418 struct drm_plane_state *ps;
1419
1420 wl_list_for_each(ps, &state_output->plane_list, link) {
1421 if (ps->plane == plane)
1422 return ps;
1423 }
1424
1425 return NULL;
1426}
1427
1428/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001429 * Return a plane state from a drm_output_state, either existing or
1430 * freshly allocated.
1431 */
1432static struct drm_plane_state *
1433drm_output_state_get_plane(struct drm_output_state *state_output,
1434 struct drm_plane *plane)
1435{
1436 struct drm_plane_state *ps;
1437
Daniel Stone2ba17f42015-05-19 20:02:41 +01001438 ps = drm_output_state_get_existing_plane(state_output, plane);
1439 if (ps)
1440 return ps;
Daniel Stonebc15f682016-11-14 16:57:01 +00001441
1442 return drm_plane_state_alloc(state_output, plane);
1443}
1444
1445/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001446 * Allocate a new, empty drm_output_state. This should not generally be used
1447 * in the repaint cycle; see drm_output_state_duplicate.
1448 */
1449static struct drm_output_state *
1450drm_output_state_alloc(struct drm_output *output,
1451 struct drm_pending_state *pending_state)
Daniel Stone90648872016-10-21 18:08:37 +01001452{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001453 struct drm_output_state *state = zalloc(sizeof(*state));
1454
1455 assert(state);
1456 state->output = output;
Daniel Stonea08512f2016-11-08 17:46:10 +00001457 state->dpms = WESTON_DPMS_OFF;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001458 state->pending_state = pending_state;
1459 if (pending_state)
1460 wl_list_insert(&pending_state->output_list, &state->link);
1461 else
1462 wl_list_init(&state->link);
1463
Daniel Stonebc15f682016-11-14 16:57:01 +00001464 wl_list_init(&state->plane_list);
1465
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001466 return state;
1467}
1468
1469/**
1470 * Duplicate an existing drm_output_state into a new one. This is generally
1471 * used during the repaint cycle, to capture the existing state of an output
1472 * and modify it to create a new state to be used.
1473 *
1474 * The mode determines whether the output will be reset to an a blank state,
1475 * or an exact mirror of the current state.
1476 */
1477static struct drm_output_state *
1478drm_output_state_duplicate(struct drm_output_state *src,
1479 struct drm_pending_state *pending_state,
1480 enum drm_output_state_duplicate_mode plane_mode)
1481{
1482 struct drm_output_state *dst = malloc(sizeof(*dst));
Daniel Stonebc15f682016-11-14 16:57:01 +00001483 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001484
1485 assert(dst);
1486
1487 /* Copy the whole structure, then individually modify the
1488 * pending_state, as well as the list link into our pending
1489 * state. */
1490 *dst = *src;
1491
1492 dst->pending_state = pending_state;
1493 if (pending_state)
1494 wl_list_insert(&pending_state->output_list, &dst->link);
1495 else
1496 wl_list_init(&dst->link);
1497
Daniel Stonebc15f682016-11-14 16:57:01 +00001498 wl_list_init(&dst->plane_list);
1499
1500 wl_list_for_each(ps, &src->plane_list, link) {
1501 /* Don't carry planes which are now disabled; these should be
1502 * free for other outputs to reuse. */
1503 if (!ps->output)
1504 continue;
1505
1506 if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
1507 (void) drm_plane_state_alloc(dst, ps->plane);
1508 else
1509 (void) drm_plane_state_duplicate(dst, ps);
1510 }
1511
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001512 return dst;
1513}
1514
1515/**
1516 * Free an unused drm_output_state.
1517 */
1518static void
1519drm_output_state_free(struct drm_output_state *state)
1520{
Daniel Stonebc15f682016-11-14 16:57:01 +00001521 struct drm_plane_state *ps, *next;
1522
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001523 if (!state)
1524 return;
1525
Daniel Stonebc15f682016-11-14 16:57:01 +00001526 wl_list_for_each_safe(ps, next, &state->plane_list, link)
1527 drm_plane_state_free(ps, false);
1528
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001529 wl_list_remove(&state->link);
Daniel Stonebc15f682016-11-14 16:57:01 +00001530
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001531 free(state);
Daniel Stone90648872016-10-21 18:08:37 +01001532}
1533
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001534/**
Daniel Stonea08512f2016-11-08 17:46:10 +00001535 * Get output state to disable output
1536 *
1537 * Returns a pointer to an output_state object which can be used to disable
1538 * an output (e.g. DPMS off).
1539 *
1540 * @param pending_state The pending state object owning this update
1541 * @param output The output to disable
1542 * @returns A drm_output_state to disable the output
1543 */
1544static struct drm_output_state *
1545drm_output_get_disable_state(struct drm_pending_state *pending_state,
1546 struct drm_output *output)
1547{
1548 struct drm_output_state *output_state;
1549
1550 output_state = drm_output_state_duplicate(output->state_cur,
1551 pending_state,
1552 DRM_OUTPUT_STATE_CLEAR_PLANES);
1553 output_state->dpms = WESTON_DPMS_OFF;
1554
1555 return output_state;
1556}
1557
1558/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001559 * Allocate a new drm_pending_state
1560 *
1561 * Allocate a new, empty, 'pending state' structure to be used across a
1562 * repaint cycle or similar.
1563 *
1564 * @param backend DRM backend
1565 * @returns Newly-allocated pending state structure
1566 */
1567static struct drm_pending_state *
1568drm_pending_state_alloc(struct drm_backend *backend)
1569{
1570 struct drm_pending_state *ret;
1571
1572 ret = calloc(1, sizeof(*ret));
1573 if (!ret)
1574 return NULL;
1575
1576 ret->backend = backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001577 wl_list_init(&ret->output_list);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001578
1579 return ret;
1580}
1581
1582/**
1583 * Free a drm_pending_state structure
1584 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001585 * Frees a pending_state structure, as well as any output_states connected
1586 * to this pending state.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001587 *
1588 * @param pending_state Pending state structure to free
1589 */
1590static void
1591drm_pending_state_free(struct drm_pending_state *pending_state)
1592{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001593 struct drm_output_state *output_state, *tmp;
1594
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001595 if (!pending_state)
1596 return;
1597
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001598 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1599 link) {
1600 drm_output_state_free(output_state);
1601 }
1602
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001603 free(pending_state);
1604}
1605
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001606/**
1607 * Find an output state in a pending state
1608 *
1609 * Given a pending_state structure, find the output_state for a particular
1610 * output.
1611 *
1612 * @param pending_state Pending state structure to search
1613 * @param output Output to find state for
1614 * @returns Output state if present, or NULL if not
1615 */
1616static struct drm_output_state *
1617drm_pending_state_get_output(struct drm_pending_state *pending_state,
1618 struct drm_output *output)
1619{
1620 struct drm_output_state *output_state;
1621
1622 wl_list_for_each(output_state, &pending_state->output_list, link) {
1623 if (output_state->output == output)
1624 return output_state;
1625 }
1626
1627 return NULL;
1628}
1629
Daniel Stonea08512f2016-11-08 17:46:10 +00001630static int drm_pending_state_apply_sync(struct drm_pending_state *state);
1631
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001632/**
1633 * Mark a drm_output_state (the output's last state) as complete. This handles
1634 * any post-completion actions such as updating the repaint timer, disabling the
1635 * output, and finally freeing the state.
1636 */
1637static void
1638drm_output_update_complete(struct drm_output *output, uint32_t flags,
1639 unsigned int sec, unsigned int usec)
1640{
Daniel Stonea08512f2016-11-08 17:46:10 +00001641 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001642 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001643 struct timespec ts;
1644
1645 /* Stop the pageflip timer instead of rearming it here */
1646 if (output->pageflip_timer)
1647 wl_event_source_timer_update(output->pageflip_timer, 0);
1648
Daniel Stonebc15f682016-11-14 16:57:01 +00001649 wl_list_for_each(ps, &output->state_cur->plane_list, link)
1650 ps->complete = true;
1651
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001652 drm_output_state_free(output->state_last);
1653 output->state_last = NULL;
1654
1655 if (output->destroy_pending) {
Daniel Stonea08512f2016-11-08 17:46:10 +00001656 output->destroy_pending = 0;
1657 output->disable_pending = 0;
1658 output->dpms_off_pending = 0;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001659 drm_output_destroy(&output->base);
1660 return;
1661 } else if (output->disable_pending) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001662 output->disable_pending = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00001663 output->dpms_off_pending = 0;
1664 weston_output_disable(&output->base);
1665 return;
1666 } else if (output->dpms_off_pending) {
1667 struct drm_pending_state *pending = drm_pending_state_alloc(b);
1668 output->dpms_off_pending = 0;
1669 drm_output_get_disable_state(pending, output);
1670 drm_pending_state_apply_sync(pending);
1671 return;
1672 } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
1673 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
1674 /* DPMS can happen to us either in the middle of a repaint
1675 * cycle (when we have painted fresh content, only to throw it
1676 * away for DPMS off), or at any other random point. If the
1677 * latter is true, then we cannot go through finish_frame,
1678 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001679 return;
1680 }
1681
1682 ts.tv_sec = sec;
1683 ts.tv_nsec = usec * 1000;
1684 weston_output_finish_frame(&output->base, &ts, flags);
1685
1686 /* We can't call this from frame_notify, because the output's
1687 * repaint needed flag is cleared just after that */
1688 if (output->recorder)
1689 weston_output_schedule_repaint(&output->base);
1690}
1691
1692/**
1693 * Mark an output state as current on the output, i.e. it has been
1694 * submitted to the kernel. The mode argument determines whether this
1695 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
1696 * or asynchronously (in which case we wait for events to complete).
1697 */
1698static void
1699drm_output_assign_state(struct drm_output_state *state,
1700 enum drm_state_apply_mode mode)
1701{
1702 struct drm_output *output = state->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00001703 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001704 struct drm_plane_state *plane_state;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001705
1706 assert(!output->state_last);
1707
1708 if (mode == DRM_STATE_APPLY_ASYNC)
1709 output->state_last = output->state_cur;
1710 else
1711 drm_output_state_free(output->state_cur);
1712
1713 wl_list_remove(&state->link);
1714 wl_list_init(&state->link);
1715 state->pending_state = NULL;
1716
1717 output->state_cur = state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001718
Daniel Stone598ee9d2016-11-16 11:55:20 +00001719 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC)
1720 output->atomic_complete_pending = 1;
1721
Daniel Stonebc15f682016-11-14 16:57:01 +00001722 /* Replace state_cur on each affected plane with the new state, being
1723 * careful to dispose of orphaned (but only orphaned) previous state.
1724 * If the previous state is not orphaned (still has an output_state
1725 * attached), it will be disposed of by freeing the output_state. */
1726 wl_list_for_each(plane_state, &state->plane_list, link) {
1727 struct drm_plane *plane = plane_state->plane;
1728
1729 if (plane->state_cur && !plane->state_cur->output_state)
1730 drm_plane_state_free(plane->state_cur, true);
1731 plane->state_cur = plane_state;
1732
1733 if (mode != DRM_STATE_APPLY_ASYNC) {
1734 plane_state->complete = true;
1735 continue;
1736 }
1737
Daniel Stone598ee9d2016-11-16 11:55:20 +00001738 if (b->atomic_modeset)
1739 continue;
1740
Daniel Stonebc15f682016-11-14 16:57:01 +00001741 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
1742 output->vblank_pending++;
Daniel Stonee2e80132018-01-16 15:37:33 +00001743 else if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
1744 output->page_flip_pending = 1;
Daniel Stonebc15f682016-11-14 16:57:01 +00001745 }
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001746}
1747
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001748static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001749drm_output_prepare_scanout_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001750 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001751{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001752 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02001753 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00001754 struct drm_plane *scanout_plane = output->scanout_plane;
1755 struct drm_plane_state *state;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001756 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001757 struct gbm_bo *bo;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001758 pixman_box32_t *extents;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001759
Daniel Stone90648872016-10-21 18:08:37 +01001760 /* Don't import buffers which span multiple outputs. */
1761 if (ev->output_mask != (1u << output->base.id))
1762 return NULL;
1763
Daniel Stone296d7a92016-10-21 18:05:37 +01001764 /* We use GBM to import buffers. */
1765 if (b->gbm == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001766 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001767
Daniel Stone296d7a92016-10-21 18:05:37 +01001768 if (buffer == NULL)
1769 return NULL;
Daniel Stone90648872016-10-21 18:08:37 +01001770 if (wl_shm_buffer_get(buffer->resource))
1771 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001772
Daniel Stone7cdf2312016-11-16 19:40:29 +00001773 /* Check the view spans exactly the output size, calculated in the
1774 * logical co-ordinate space. */
1775 extents = pixman_region32_extents(&ev->transform.boundingbox);
1776 if (extents->x1 != output->base.x ||
1777 extents->y1 != output->base.y ||
1778 extents->x2 != output->base.x + output->base.width ||
1779 extents->y2 != output->base.y + output->base.height)
Daniel Stone90648872016-10-21 18:08:37 +01001780 return NULL;
1781
1782 if (ev->alpha != 1.0f)
1783 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001784
Daniel Stonee2e80132018-01-16 15:37:33 +00001785 state = drm_output_state_get_plane(output_state, scanout_plane);
1786 if (state->fb) {
1787 /* If there is already a framebuffer on the scanout plane,
1788 * a client view has already been placed on the scanout
1789 * view. In that case, do not free or put back the state,
1790 * but just leave it in place and quietly exit. */
1791 return NULL;
1792 }
1793
Daniel Stone7cdf2312016-11-16 19:40:29 +00001794 state->output = output;
1795 if (!drm_plane_state_coords_for_view(state, ev))
1796 goto err;
1797
1798 /* The legacy API does not let us perform cropping or scaling. */
1799 if (state->src_x != 0 || state->src_y != 0 ||
1800 state->src_w != state->dest_w << 16 ||
1801 state->src_h != state->dest_h << 16 ||
1802 state->dest_x != 0 || state->dest_y != 0 ||
1803 state->dest_w != (unsigned) output->base.current_mode->width ||
1804 state->dest_h != (unsigned) output->base.current_mode->height)
1805 goto err;
1806
Giulio Camuffo954f1832014-10-11 18:27:30 +03001807 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -07001808 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001809
Rob Bradford9b101872012-09-14 23:25:41 +01001810 /* Unable to use the buffer for scanout */
1811 if (!bo)
Daniel Stone7cdf2312016-11-16 19:40:29 +00001812 goto err;
Rob Bradford9b101872012-09-14 23:25:41 +01001813
Daniel Stonedb10df12016-12-08 13:15:58 +00001814 state->fb = drm_fb_get_from_bo(bo, b, drm_view_is_opaque(ev),
1815 BUFFER_CLIENT);
1816 if (!state->fb) {
Daniel Stone7cdf2312016-11-16 19:40:29 +00001817 /* We need to explicitly destroy the BO. */
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +03001818 gbm_bo_destroy(bo);
Daniel Stone7cdf2312016-11-16 19:40:29 +00001819 goto err;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +03001820 }
1821
Daniel Stonedb10df12016-12-08 13:15:58 +00001822 /* Can't change formats with just a pageflip */
1823 if (state->fb->format->format != output->gbm_format) {
1824 /* No need to destroy the GBM BO here, as it's now owned
1825 * by the FB. */
Daniel Stone7cdf2312016-11-16 19:40:29 +00001826 goto err;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001827 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001828
Daniel Stonee2e80132018-01-16 15:37:33 +00001829 drm_fb_set_buffer(state->fb, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001830
Daniel Stonee2e80132018-01-16 15:37:33 +00001831 return &scanout_plane->base;
Daniel Stone7cdf2312016-11-16 19:40:29 +00001832
1833err:
1834 drm_plane_state_put_back(state);
1835 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001836}
1837
Daniel Stone95d48a22017-04-04 17:54:30 +01001838static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001839drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001840{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001841 struct drm_output *output = state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02001842 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001843 struct gbm_bo *bo;
Daniel Stone95d48a22017-04-04 17:54:30 +01001844 struct drm_fb *ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001845
Giulio Camuffo954f1832014-10-11 18:27:30 +03001846 output->base.compositor->renderer->repaint_output(&output->base,
1847 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001848
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001849 bo = gbm_surface_lock_front_buffer(output->gbm_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001850 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +02001851 weston_log("failed to lock front buffer: %m\n");
Daniel Stone95d48a22017-04-04 17:54:30 +01001852 return NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001853 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001854
Daniel Stonedb10df12016-12-08 13:15:58 +00001855 /* The renderer always produces an opaque image. */
1856 ret = drm_fb_get_from_bo(bo, b, true, BUFFER_GBM_SURFACE);
Daniel Stone95d48a22017-04-04 17:54:30 +01001857 if (!ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001858 weston_log("failed to get drm_fb for bo\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001859 gbm_surface_release_buffer(output->gbm_surface, bo);
Daniel Stone95d48a22017-04-04 17:54:30 +01001860 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001861 }
Daniel Stone95d48a22017-04-04 17:54:30 +01001862 ret->gbm_surface = output->gbm_surface;
1863
1864 return ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001865}
1866
Daniel Stone95d48a22017-04-04 17:54:30 +01001867static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001868drm_output_render_pixman(struct drm_output_state *state,
1869 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001870{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001871 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001872 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001873
1874 output->current_image ^= 1;
1875
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001876 pixman_renderer_output_set_buffer(&output->base,
1877 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +02001878 pixman_renderer_output_set_hw_extra_damage(&output->base,
1879 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001880
Pekka Paalanenacf50c32018-04-23 11:44:56 +02001881 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001882
Pekka Paalanenacf50c32018-04-23 11:44:56 +02001883 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +01001884
1885 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001886}
1887
1888static void
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001889drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001890{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001891 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001892 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +00001893 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +00001894 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02001895 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +01001896 struct drm_fb *fb;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001897
Daniel Stone4e84f7d2017-04-04 17:54:29 +01001898 /* If we already have a client buffer promoted to scanout, then we don't
1899 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +00001900 scanout_state = drm_output_state_get_plane(state,
1901 output->scanout_plane);
1902 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +01001903 return;
1904
Daniel Stonee95169b2016-11-14 17:46:59 +00001905 if (!pixman_region32_not_empty(damage) &&
1906 scanout_plane->state_cur->fb &&
1907 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
1908 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
1909 scanout_plane->state_cur->fb->width ==
1910 output->base.current_mode->width &&
1911 scanout_plane->state_cur->fb->height ==
1912 output->base.current_mode->height) {
1913 fb = drm_fb_ref(scanout_plane->state_cur->fb);
1914 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001915 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00001916 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001917 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00001918 }
Daniel Stone95d48a22017-04-04 17:54:30 +01001919
Daniel Stonee2e80132018-01-16 15:37:33 +00001920 if (!fb) {
1921 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +01001922 return;
Daniel Stonee2e80132018-01-16 15:37:33 +00001923 }
1924
1925 scanout_state->fb = fb;
1926 scanout_state->output = output;
1927
1928 scanout_state->src_x = 0;
1929 scanout_state->src_y = 0;
1930 scanout_state->src_w = output->base.current_mode->width << 16;
1931 scanout_state->src_h = output->base.current_mode->height << 16;
1932
1933 scanout_state->dest_x = 0;
1934 scanout_state->dest_y = 0;
1935 scanout_state->dest_w = scanout_state->src_w >> 16;
1936 scanout_state->dest_h = scanout_state->src_h >> 16;
1937
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001938
Giulio Camuffo954f1832014-10-11 18:27:30 +03001939 pixman_region32_subtract(&c->primary_plane.damage,
1940 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001941}
1942
1943static void
Richard Hughese7299962013-05-01 21:52:12 +01001944drm_output_set_gamma(struct weston_output *output_base,
1945 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
1946{
1947 int rc;
Armin Krezović545dba62016-08-05 15:54:18 +02001948 struct drm_output *output = to_drm_output(output_base);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001949 struct drm_backend *backend =
Armin Krezović545dba62016-08-05 15:54:18 +02001950 to_drm_backend(output->base.compositor);
Richard Hughese7299962013-05-01 21:52:12 +01001951
1952 /* check */
1953 if (output_base->gamma_size != size)
1954 return;
Richard Hughese7299962013-05-01 21:52:12 +01001955
Giulio Camuffo954f1832014-10-11 18:27:30 +03001956 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +01001957 output->crtc_id,
1958 size, r, g, b);
1959 if (rc)
1960 weston_log("set gamma failed: %m\n");
1961}
1962
Bryce Harringtonada4f072015-06-30 13:25:46 -07001963/* Determine the type of vblank synchronization to use for the output.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001964 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07001965 * The pipe parameter indicates which CRTC is in use. Knowing this, we
1966 * can determine which vblank sequence type to use for it. Traditional
1967 * cards had only two CRTCs, with CRTC 0 using no special flags, and
1968 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
1969 * parameter indicates this.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001970 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07001971 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
1972 * 0-31. If this is non-zero it indicates we're dealing with a
1973 * multi-gpu situation and we need to calculate the vblank sync
1974 * using DRM_BLANK_HIGH_CRTC_MASK.
1975 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +03001976static unsigned int
1977drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02001978{
1979 if (output->pipe > 1)
1980 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
1981 DRM_VBLANK_HIGH_CRTC_MASK;
1982 else if (output->pipe > 0)
1983 return DRM_VBLANK_SECONDARY;
1984 else
1985 return 0;
1986}
1987
David Herrmann1edf44c2013-10-22 17:11:26 +02001988static int
Daniel Stone598ee9d2016-11-16 11:55:20 +00001989drm_output_apply_state_legacy(struct drm_output_state *state)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001990{
Daniel Stonea08512f2016-11-08 17:46:10 +00001991 struct drm_output *output = state->output;
1992 struct drm_backend *backend = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00001993 struct drm_plane *scanout_plane = output->scanout_plane;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001994 struct drm_property_info *dpms_prop;
Daniel Stonee2e80132018-01-16 15:37:33 +00001995 struct drm_plane_state *scanout_state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001996 struct drm_plane_state *ps;
Daniel Stone085d2b92015-05-21 00:00:57 +01001997 struct drm_plane *p;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001998 struct drm_mode *mode;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001999 struct drm_head *head;
2000 uint32_t connectors[MAX_CLONED_CONNECTORS];
2001 int n_conn = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00002002 struct timespec now;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002003 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002004
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002005 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2006 assert(n_conn < MAX_CLONED_CONNECTORS);
2007 connectors[n_conn++] = head->connector_id;
2008 }
2009
Derek Foreman2cd87fe2017-04-13 13:48:48 -05002010 /* If disable_planes is set then assign_planes() wasn't
2011 * called for this render, so we could still have a stale
2012 * cursor plane set up.
2013 */
2014 if (output->base.disable_planes) {
2015 output->cursor_view = NULL;
Greg V1f781762018-02-19 17:59:42 +03002016 if (output->cursor_plane) {
2017 output->cursor_plane->base.x = INT32_MIN;
2018 output->cursor_plane->base.y = INT32_MIN;
2019 }
Derek Foreman2cd87fe2017-04-13 13:48:48 -05002020 }
2021
Daniel Stonea08512f2016-11-08 17:46:10 +00002022 if (state->dpms != WESTON_DPMS_ON) {
2023 wl_list_for_each(ps, &state->plane_list, link) {
2024 p = ps->plane;
2025 assert(ps->fb == NULL);
2026 assert(ps->output == NULL);
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002027
Daniel Stonea08512f2016-11-08 17:46:10 +00002028 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2029 continue;
2030
2031 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
2032 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2033 if (ret)
2034 weston_log("drmModeSetPlane failed disable: %m\n");
2035 }
2036
2037 if (output->cursor_plane) {
2038 ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
2039 0, 0, 0);
2040 if (ret)
2041 weston_log("drmModeSetCursor failed disable: %m\n");
2042 }
2043
2044 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002045 NULL, 0, NULL);
Daniel Stonea08512f2016-11-08 17:46:10 +00002046 if (ret)
2047 weston_log("drmModeSetCrtc failed disabling: %m\n");
2048
2049 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
2050 weston_compositor_read_presentation_clock(output->base.compositor, &now);
2051 drm_output_update_complete(output,
2052 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
2053 now.tv_sec, now.tv_nsec / 1000);
2054
2055 return 0;
2056 }
2057
2058 scanout_state =
2059 drm_output_state_get_existing_plane(state, scanout_plane);
Daniel Stone087ddf02017-02-14 17:51:30 +00002060
Daniel Stonee2e80132018-01-16 15:37:33 +00002061 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
2062 * legacy PageFlip API doesn't allow us to do clipping either. */
2063 assert(scanout_state->src_x == 0);
2064 assert(scanout_state->src_y == 0);
2065 assert(scanout_state->src_w ==
2066 (unsigned) (output->base.current_mode->width << 16));
2067 assert(scanout_state->src_h ==
2068 (unsigned) (output->base.current_mode->height << 16));
2069 assert(scanout_state->dest_x == 0);
2070 assert(scanout_state->dest_y == 0);
2071 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
2072 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
2073
Daniel Stonecb04cc42016-11-16 11:51:27 +00002074 mode = to_drm_mode(output->base.current_mode);
Daniel Stone6020f472018-02-05 15:46:20 +00002075 if (backend->state_invalid || !scanout_plane->state_cur->fb ||
Daniel Stonee2e80132018-01-16 15:37:33 +00002076 scanout_plane->state_cur->fb->stride != scanout_state->fb->stride) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002077 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00002078 scanout_state->fb->fb_id,
2079 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002080 connectors, n_conn,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002081 &mode->mode_info);
2082 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002083 weston_log("set mode failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002084 goto err;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002085 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02002086 }
2087
Giulio Camuffo954f1832014-10-11 18:27:30 +03002088 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00002089 scanout_state->fb->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05002090 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002091 weston_log("queueing pageflip failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002092 goto err;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05002093 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01002094
Daniel Stone205c0a02017-04-04 17:54:33 +01002095 assert(!output->page_flip_pending);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002096
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002097 if (output->pageflip_timer)
2098 wl_event_source_timer_update(output->pageflip_timer,
2099 backend->pageflip_timeout);
2100
Daniel Stone2ba17f42015-05-19 20:02:41 +01002101 drm_output_set_cursor(state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04002102
Jesse Barnes58ef3792012-02-23 09:45:49 -05002103 /*
2104 * Now, update all the sprite surfaces
2105 */
Daniel Stonebc15f682016-11-14 16:57:01 +00002106 wl_list_for_each(ps, &state->plane_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002107 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002108 drmVBlank vbl = {
2109 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
2110 .request.sequence = 1,
2111 };
2112
Daniel Stonebc15f682016-11-14 16:57:01 +00002113 p = ps->plane;
Daniel Stone085d2b92015-05-21 00:00:57 +01002114 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002115 continue;
2116
Daniel Stonebc15f682016-11-14 16:57:01 +00002117 assert(p->state_cur->complete);
2118 assert(!!p->state_cur->output == !!p->state_cur->fb);
2119 assert(!p->state_cur->output || p->state_cur->output == output);
2120 assert(!ps->complete);
2121 assert(!ps->output || ps->output == output);
2122 assert(!!ps->output == !!ps->fb);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002123
Daniel Stonebc15f682016-11-14 16:57:01 +00002124 if (ps->fb && !backend->sprites_hidden)
2125 fb_id = ps->fb->fb_id;
Daniel Stone085d2b92015-05-21 00:00:57 +01002126
2127 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002128 output->crtc_id, fb_id, flags,
Daniel Stonebc15f682016-11-14 16:57:01 +00002129 ps->dest_x, ps->dest_y,
2130 ps->dest_w, ps->dest_h,
2131 ps->src_x, ps->src_y,
2132 ps->src_w, ps->src_h);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002133 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +02002134 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002135 ret, strerror(errno));
2136
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02002137 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -05002138
Jesse Barnes58ef3792012-02-23 09:45:49 -05002139 /*
2140 * Queue a vblank signal so we know when the surface
2141 * becomes active on the display or has been replaced.
2142 */
Daniel Stonebc15f682016-11-14 16:57:01 +00002143 vbl.request.signal = (unsigned long) ps;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002144 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002145 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02002146 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002147 ret, strerror(errno));
2148 }
2149 }
2150
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03002151 if (state->dpms != output->state_cur->dpms) {
2152 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2153 dpms_prop = &head->props_conn[WDRM_CONNECTOR_DPMS];
2154 if (dpms_prop->prop_id == 0)
2155 continue;
2156
2157 ret = drmModeConnectorSetProperty(backend->drm.fd,
2158 head->connector_id,
2159 dpms_prop->prop_id,
2160 state->dpms);
2161 if (ret) {
2162 weston_log("DRM: DPMS: failed property set for %s\n",
2163 head->base.name);
2164 }
Daniel Stonea08512f2016-11-08 17:46:10 +00002165 }
2166 }
2167
2168 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
2169
David Herrmann1edf44c2013-10-22 17:11:26 +02002170 return 0;
2171
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002172err:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -08002173 output->cursor_view = NULL;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002174 drm_output_state_free(state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002175 return -1;
2176}
David Herrmann1edf44c2013-10-22 17:11:26 +02002177
Daniel Stone598ee9d2016-11-16 11:55:20 +00002178#ifdef HAVE_DRM_ATOMIC
2179static int
2180crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
2181 enum wdrm_crtc_property prop, uint64_t val)
2182{
2183 struct drm_property_info *info = &output->props_crtc[prop];
2184 int ret;
2185
2186 if (info->prop_id == 0)
2187 return -1;
2188
2189 ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
2190 val);
2191 return (ret <= 0) ? -1 : 0;
2192}
2193
2194static int
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002195connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002196 enum wdrm_connector_property prop, uint64_t val)
2197{
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002198 struct drm_property_info *info = &head->props_conn[prop];
Daniel Stone598ee9d2016-11-16 11:55:20 +00002199 int ret;
2200
2201 if (info->prop_id == 0)
2202 return -1;
2203
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002204 ret = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002205 info->prop_id, val);
2206 return (ret <= 0) ? -1 : 0;
2207}
2208
2209static int
2210plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
2211 enum wdrm_plane_property prop, uint64_t val)
2212{
2213 struct drm_property_info *info = &plane->props[prop];
2214 int ret;
2215
2216 if (info->prop_id == 0)
2217 return -1;
2218
2219 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
2220 val);
2221 return (ret <= 0) ? -1 : 0;
2222}
2223
2224static int
2225drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
2226{
2227 int ret;
2228
2229 if (mode->blob_id)
2230 return 0;
2231
2232 ret = drmModeCreatePropertyBlob(backend->drm.fd,
2233 &mode->mode_info,
2234 sizeof(mode->mode_info),
2235 &mode->blob_id);
2236 if (ret != 0)
2237 weston_log("failed to create mode property blob: %m\n");
2238
2239 return ret;
2240}
2241
2242static int
2243drm_output_apply_state_atomic(struct drm_output_state *state,
2244 drmModeAtomicReq *req,
2245 uint32_t *flags)
2246{
2247 struct drm_output *output = state->output;
2248 struct drm_backend *backend = to_drm_backend(output->base.compositor);
2249 struct drm_plane_state *plane_state;
2250 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002251 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002252 int ret = 0;
2253
2254 if (state->dpms != output->state_cur->dpms)
2255 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2256
2257 if (state->dpms == WESTON_DPMS_ON) {
2258 ret = drm_mode_ensure_blob(backend, current_mode);
2259 if (ret != 0)
2260 return ret;
2261
2262 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
2263 current_mode->blob_id);
2264 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002265
2266 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2267 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
2268 output->crtc_id);
2269 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00002270 } else {
2271 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
2272 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002273
2274 wl_list_for_each(head, &output->base.head_list, base.output_link)
2275 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002276 }
2277
2278 if (ret != 0) {
2279 weston_log("couldn't set atomic CRTC/connector state\n");
2280 return ret;
2281 }
2282
2283 wl_list_for_each(plane_state, &state->plane_list, link) {
2284 struct drm_plane *plane = plane_state->plane;
2285
2286 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
2287 plane_state->fb ? plane_state->fb->fb_id : 0);
2288 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
2289 plane_state->fb ? output->crtc_id : 0);
2290 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
2291 plane_state->src_x);
2292 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
2293 plane_state->src_y);
2294 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
2295 plane_state->src_w);
2296 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
2297 plane_state->src_h);
2298 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
2299 plane_state->dest_x);
2300 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
2301 plane_state->dest_y);
2302 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
2303 plane_state->dest_w);
2304 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
2305 plane_state->dest_h);
2306
2307 if (ret != 0) {
2308 weston_log("couldn't set plane state\n");
2309 return ret;
2310 }
2311 }
2312
2313 return 0;
2314}
2315
2316/**
2317 * Helper function used only by drm_pending_state_apply, with the same
2318 * guarantees and constraints as that function.
2319 */
2320static int
2321drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
2322 enum drm_state_apply_mode mode)
2323{
2324 struct drm_backend *b = pending_state->backend;
2325 struct drm_output_state *output_state, *tmp;
2326 struct drm_plane *plane;
2327 drmModeAtomicReq *req = drmModeAtomicAlloc();
2328 uint32_t flags = 0;
2329 int ret = 0;
2330
2331 if (!req)
2332 return -1;
2333
2334 if (b->state_invalid) {
Pekka Paalaneneacec812017-09-12 13:43:51 +03002335 struct weston_head *head_base;
2336 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002337 uint32_t *unused;
2338 int err;
2339
2340 /* If we need to reset all our state (e.g. because we've
2341 * just started, or just been VT-switched in), explicitly
2342 * disable all the CRTCs and connectors we aren't using. */
Pekka Paalaneneacec812017-09-12 13:43:51 +03002343 wl_list_for_each(head_base,
2344 &b->compositor->head_list, compositor_link) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00002345 struct drm_property_info *info;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002346
Pekka Paalaneneacec812017-09-12 13:43:51 +03002347 if (weston_head_is_enabled(head_base))
Daniel Stone598ee9d2016-11-16 11:55:20 +00002348 continue;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002349
Pekka Paalaneneacec812017-09-12 13:43:51 +03002350 head = to_drm_head(head_base);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002351
Pekka Paalaneneacec812017-09-12 13:43:51 +03002352 info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
2353 err = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002354 info->prop_id, 0);
2355 if (err <= 0)
2356 ret = -1;
2357
Pekka Paalaneneacec812017-09-12 13:43:51 +03002358 info = &head->props_conn[WDRM_CONNECTOR_DPMS];
Daniel Stone598ee9d2016-11-16 11:55:20 +00002359 if (info->prop_id > 0)
Pekka Paalaneneacec812017-09-12 13:43:51 +03002360 err = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002361 info->prop_id,
2362 DRM_MODE_DPMS_OFF);
2363 if (err <= 0)
2364 ret = -1;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002365 }
2366
2367 wl_array_for_each(unused, &b->unused_crtcs) {
2368 struct drm_property_info infos[WDRM_CRTC__COUNT];
2369 struct drm_property_info *info;
2370 drmModeObjectProperties *props;
2371 uint64_t active;
2372
2373 memset(infos, 0, sizeof(infos));
2374
2375 /* We can't emit a disable on a CRTC that's already
2376 * off, as the kernel will refuse to generate an event
2377 * for an off->off state and fail the commit.
2378 */
2379 props = drmModeObjectGetProperties(b->drm.fd,
2380 *unused,
2381 DRM_MODE_OBJECT_CRTC);
2382 if (!props) {
2383 ret = -1;
2384 continue;
2385 }
2386
2387 drm_property_info_populate(b, crtc_props, infos,
2388 WDRM_CRTC__COUNT,
2389 props);
2390
2391 info = &infos[WDRM_CRTC_ACTIVE];
2392 active = drm_property_get_value(info, props, 0);
2393 drmModeFreeObjectProperties(props);
2394 if (active == 0) {
2395 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2396 continue;
2397 }
2398
2399 err = drmModeAtomicAddProperty(req, *unused,
2400 info->prop_id, 0);
2401 if (err <= 0)
2402 ret = -1;
2403
2404 info = &infos[WDRM_CRTC_MODE_ID];
2405 err = drmModeAtomicAddProperty(req, *unused,
2406 info->prop_id, 0);
2407 if (err <= 0)
2408 ret = -1;
2409
2410 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2411 }
2412
2413 /* Disable all the planes; planes which are being used will
2414 * override this state in the output-state application. */
2415 wl_list_for_each(plane, &b->plane_list, link) {
2416 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
2417 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
2418 }
2419
2420 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2421 }
2422
2423 wl_list_for_each(output_state, &pending_state->output_list, link) {
2424 if (mode == DRM_STATE_APPLY_SYNC)
2425 assert(output_state->dpms == WESTON_DPMS_OFF);
2426 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
2427 }
2428
2429 if (ret != 0) {
2430 weston_log("atomic: couldn't compile atomic state\n");
2431 goto out;
2432 }
2433
2434 switch (mode) {
2435 case DRM_STATE_APPLY_SYNC:
2436 break;
2437 case DRM_STATE_APPLY_ASYNC:
2438 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
2439 break;
2440 }
2441
2442 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
2443 if (ret != 0) {
2444 weston_log("atomic: couldn't commit new state: %m\n");
2445 goto out;
2446 }
2447
2448 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2449 link)
2450 drm_output_assign_state(output_state, mode);
2451
2452 b->state_invalid = false;
2453
2454 assert(wl_list_empty(&pending_state->output_list));
2455
2456out:
2457 drmModeAtomicFree(req);
2458 drm_pending_state_free(pending_state);
2459 return ret;
2460}
2461#endif
2462
Daniel Stonea08512f2016-11-08 17:46:10 +00002463/**
2464 * Applies all of a pending_state asynchronously: the primary entry point for
2465 * applying KMS state to a device. Updates the state for all outputs in the
2466 * pending_state, as well as disabling any unclaimed outputs.
2467 *
2468 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2469 */
2470static int
2471drm_pending_state_apply(struct drm_pending_state *pending_state)
2472{
2473 struct drm_backend *b = pending_state->backend;
2474 struct drm_output_state *output_state, *tmp;
2475 uint32_t *unused;
2476
Daniel Stone598ee9d2016-11-16 11:55:20 +00002477#ifdef HAVE_DRM_ATOMIC
2478 if (b->atomic_modeset)
2479 return drm_pending_state_apply_atomic(pending_state,
2480 DRM_STATE_APPLY_ASYNC);
2481#endif
2482
Daniel Stonea08512f2016-11-08 17:46:10 +00002483 if (b->state_invalid) {
2484 /* If we need to reset all our state (e.g. because we've
2485 * just started, or just been VT-switched in), explicitly
2486 * disable all the CRTCs we aren't using. This also disables
2487 * all connectors on these CRTCs, so we don't need to do that
2488 * separately with the pre-atomic API. */
2489 wl_array_for_each(unused, &b->unused_crtcs)
2490 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2491 NULL);
2492 }
2493
2494 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2495 link) {
2496 struct drm_output *output = output_state->output;
2497 int ret;
2498
Daniel Stone598ee9d2016-11-16 11:55:20 +00002499 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002500 if (ret != 0) {
2501 weston_log("Couldn't apply state for output %s\n",
2502 output->base.name);
2503 }
2504 }
2505
2506 b->state_invalid = false;
2507
2508 assert(wl_list_empty(&pending_state->output_list));
2509
2510 drm_pending_state_free(pending_state);
2511
2512 return 0;
2513}
2514
2515/**
2516 * The synchronous version of drm_pending_state_apply. May only be used to
2517 * disable outputs. Does so synchronously: the request is guaranteed to have
2518 * completed on return, and the output will not be touched afterwards.
2519 *
2520 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2521 */
2522static int
2523drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
2524{
2525 struct drm_backend *b = pending_state->backend;
2526 struct drm_output_state *output_state, *tmp;
2527 uint32_t *unused;
2528
Daniel Stone598ee9d2016-11-16 11:55:20 +00002529#ifdef HAVE_DRM_ATOMIC
2530 if (b->atomic_modeset)
2531 return drm_pending_state_apply_atomic(pending_state,
2532 DRM_STATE_APPLY_SYNC);
2533#endif
2534
Daniel Stonea08512f2016-11-08 17:46:10 +00002535 if (b->state_invalid) {
2536 /* If we need to reset all our state (e.g. because we've
2537 * just started, or just been VT-switched in), explicitly
2538 * disable all the CRTCs we aren't using. This also disables
2539 * all connectors on these CRTCs, so we don't need to do that
2540 * separately with the pre-atomic API. */
2541 wl_array_for_each(unused, &b->unused_crtcs)
2542 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2543 NULL);
2544 }
2545
2546 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2547 link) {
2548 int ret;
2549
2550 assert(output_state->dpms == WESTON_DPMS_OFF);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002551 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002552 if (ret != 0) {
2553 weston_log("Couldn't apply state for output %s\n",
2554 output_state->output->base.name);
2555 }
2556 }
2557
2558 b->state_invalid = false;
2559
2560 assert(wl_list_empty(&pending_state->output_list));
2561
2562 drm_pending_state_free(pending_state);
2563
2564 return 0;
2565}
2566
2567static int
2568drm_output_repaint(struct weston_output *output_base,
2569 pixman_region32_t *damage,
2570 void *repaint_data)
2571{
2572 struct drm_pending_state *pending_state = repaint_data;
2573 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00002574 struct drm_output_state *state = NULL;
2575 struct drm_plane_state *scanout_state;
2576
2577 if (output->disable_pending || output->destroy_pending)
2578 goto err;
2579
2580 assert(!output->state_last);
2581
2582 /* If planes have been disabled in the core, we might not have
2583 * hit assign_planes at all, so might not have valid output state
2584 * here. */
2585 state = drm_pending_state_get_output(pending_state, output);
2586 if (!state)
2587 state = drm_output_state_duplicate(output->state_cur,
2588 pending_state,
2589 DRM_OUTPUT_STATE_CLEAR_PLANES);
2590 state->dpms = WESTON_DPMS_ON;
2591
2592 drm_output_render(state, damage);
2593 scanout_state = drm_output_state_get_plane(state,
2594 output->scanout_plane);
2595 if (!scanout_state || !scanout_state->fb)
2596 goto err;
2597
Daniel Stonea08512f2016-11-08 17:46:10 +00002598 return 0;
2599
2600err:
2601 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +02002602 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002603}
2604
2605static void
Jonas Ådahle5a12252013-04-05 23:07:11 +02002606drm_output_start_repaint_loop(struct weston_output *output_base)
2607{
Armin Krezović545dba62016-08-05 15:54:18 +02002608 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +00002609 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +00002610 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02002611 struct drm_backend *backend =
2612 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002613 struct timespec ts, tnow;
2614 struct timespec vbl2now;
2615 int64_t refresh_nsec;
2616 int ret;
2617 drmVBlank vbl = {
2618 .request.type = DRM_VBLANK_RELATIVE,
2619 .request.sequence = 0,
2620 .request.signal = 0,
2621 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002622
Armin Krezović08368132016-09-30 14:11:05 +02002623 if (output->disable_pending || output->destroy_pending)
Xiong Zhangabd5d472013-10-11 14:43:07 +08002624 return;
2625
Daniel Stonee2e80132018-01-16 15:37:33 +00002626 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002627 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +02002628 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002629 }
2630
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002631 /* Need to smash all state in from scratch; current timings might not
2632 * be what we want, page flip might not work, etc.
2633 */
Daniel Stone6020f472018-02-05 15:46:20 +00002634 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002635 goto finish_frame;
2636
Daniel Stonee2e80132018-01-16 15:37:33 +00002637 assert(scanout_plane->state_cur->output == output);
2638
Mario Kleinerf507ec32015-06-21 21:25:14 +02002639 /* Try to get current msc and timestamp via instant query */
2640 vbl.request.type |= drm_waitvblank_pipe(output);
2641 ret = drmWaitVBlank(backend->drm.fd, &vbl);
2642
2643 /* Error ret or zero timestamp means failure to get valid timestamp */
2644 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
2645 ts.tv_sec = vbl.reply.tval_sec;
2646 ts.tv_nsec = vbl.reply.tval_usec * 1000;
2647
2648 /* Valid timestamp for most recent vblank - not stale?
2649 * Stale ts could happen on Linux 3.17+, so make sure it
2650 * is not older than 1 refresh duration since now.
2651 */
2652 weston_compositor_read_presentation_clock(backend->compositor,
2653 &tnow);
2654 timespec_sub(&vbl2now, &tnow, &ts);
2655 refresh_nsec =
2656 millihz_to_nsec(output->base.current_mode->refresh);
2657 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
2658 drm_output_update_msc(output, vbl.reply.sequence);
2659 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002660 WP_PRESENTATION_FEEDBACK_INVALID);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002661 return;
2662 }
2663 }
2664
2665 /* Immediate query didn't provide valid timestamp.
2666 * Use pageflip fallback.
2667 */
Jonas Ådahle5a12252013-04-05 23:07:11 +02002668
Daniel Stone205c0a02017-04-04 17:54:33 +01002669 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002670 assert(!output->state_last);
2671
2672 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +00002673 drm_output_state_duplicate(output->state_cur, pending_state,
2674 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +01002675
Daniel Stone8747f952016-11-29 20:17:32 +00002676 ret = drm_pending_state_apply(pending_state);
2677 if (ret != 0) {
2678 weston_log("applying repaint-start state failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +02002679 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +02002680 }
David Herrmann3c688c52013-10-22 17:11:25 +02002681
2682 return;
2683
2684finish_frame:
2685 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +00002686 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002687 WP_PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002688}
2689
2690static void
Pekka Paalanen641307c2014-09-23 22:08:47 -04002691drm_output_update_msc(struct drm_output *output, unsigned int seq)
2692{
2693 uint64_t msc_hi = output->base.msc >> 32;
2694
2695 if (seq < (output->base.msc & 0xffffffff))
2696 msc_hi++;
2697
2698 output->base.msc = (msc_hi << 32) + seq;
2699}
2700
2701static void
Jesse Barnes58ef3792012-02-23 09:45:49 -05002702vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
2703 void *data)
2704{
Daniel Stonebc15f682016-11-14 16:57:01 +00002705 struct drm_plane_state *ps = (struct drm_plane_state *) data;
2706 struct drm_output_state *os = ps->output_state;
2707 struct drm_output *output = os->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002708 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002709 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2710 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002711
Daniel Stone598ee9d2016-11-16 11:55:20 +00002712 assert(!b->atomic_modeset);
2713
Pekka Paalanen641307c2014-09-23 22:08:47 -04002714 drm_output_update_msc(output, frame);
Daniel Stone65d87d02017-04-04 17:54:32 +01002715 output->vblank_pending--;
2716 assert(output->vblank_pending >= 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002717
Daniel Stonebc15f682016-11-14 16:57:01 +00002718 assert(ps->fb);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002719
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002720 if (output->page_flip_pending || output->vblank_pending)
2721 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002722
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002723 drm_output_update_complete(output, flags, sec, usec);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002724}
2725
2726static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002727page_flip_handler(int fd, unsigned int frame,
2728 unsigned int sec, unsigned int usec, void *data)
2729{
Armin Krezović545dba62016-08-05 15:54:18 +02002730 struct drm_output *output = data;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002731 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002732 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2733 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2734 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002735
Pekka Paalanen641307c2014-09-23 22:08:47 -04002736 drm_output_update_msc(output, frame);
2737
Daniel Stone598ee9d2016-11-16 11:55:20 +00002738 assert(!b->atomic_modeset);
Daniel Stone205c0a02017-04-04 17:54:33 +01002739 assert(output->page_flip_pending);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002740 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002741
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002742 if (output->vblank_pending)
2743 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002744
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002745 drm_output_update_complete(output, flags, sec, usec);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02002746}
2747
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002748/**
2749 * Begin a new repaint cycle
2750 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002751 * Called by the core compositor at the beginning of a repaint cycle. Creates
2752 * a new pending_state structure to own any output state created by individual
2753 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002754 */
2755static void *
2756drm_repaint_begin(struct weston_compositor *compositor)
2757{
2758 struct drm_backend *b = to_drm_backend(compositor);
2759 struct drm_pending_state *ret;
2760
2761 ret = drm_pending_state_alloc(b);
2762 b->repaint_data = ret;
2763
2764 return ret;
2765}
2766
2767/**
2768 * Flush a repaint set
2769 *
2770 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002771 * and should be flushed. Frees the pending state, transitioning ownership
2772 * of the output state from the pending state, to the update itself. When
2773 * the update completes (see drm_output_update_complete), the output
2774 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002775 */
2776static void
2777drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
2778{
2779 struct drm_backend *b = to_drm_backend(compositor);
2780 struct drm_pending_state *pending_state = repaint_data;
Daniel Stone6020f472018-02-05 15:46:20 +00002781
Daniel Stonea08512f2016-11-08 17:46:10 +00002782 drm_pending_state_apply(pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002783 b->repaint_data = NULL;
2784}
2785
2786/**
2787 * Cancel a repaint set
2788 *
2789 * Called by the core compositor when a repaint has finished, so the data
2790 * held across the repaint cycle should be discarded.
2791 */
2792static void
2793drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
2794{
2795 struct drm_backend *b = to_drm_backend(compositor);
2796 struct drm_pending_state *pending_state = repaint_data;
2797
2798 drm_pending_state_free(pending_state);
2799 b->repaint_data = NULL;
2800}
2801
Daniel Stone598ee9d2016-11-16 11:55:20 +00002802#ifdef HAVE_DRM_ATOMIC
2803static void
2804atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
2805 unsigned int usec, unsigned int crtc_id, void *data)
2806{
2807 struct drm_backend *b = data;
2808 struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
2809 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2810 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2811 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
2812
2813 /* During the initial modeset, we can disable CRTCs which we don't
2814 * actually handle during normal operation; this will give us events
2815 * for unknown outputs. Ignore them. */
2816 if (!output || !output->base.enabled)
2817 return;
2818
2819 drm_output_update_msc(output, frame);
2820
2821 assert(b->atomic_modeset);
2822 assert(output->atomic_complete_pending);
2823 output->atomic_complete_pending = 0;
2824
2825 drm_output_update_complete(output, flags, sec, usec);
2826}
2827#endif
2828
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002829static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002830drm_output_prepare_overlay_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002831 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002832{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002833 struct drm_output *output = output_state->output;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002834 struct weston_compositor *ec = output->base.compositor;
Daniel Stoned6e2a762016-11-16 19:33:20 +00002835 struct drm_backend *b = to_drm_backend(ec);
Daniel Stone08d4edf2017-04-04 17:54:34 +01002836 struct drm_plane *p;
Daniel Stonebc15f682016-11-14 16:57:01 +00002837 struct drm_plane_state *state = NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00002838 struct drm_fb *fb;
Daniel Stonedb10df12016-12-08 13:15:58 +00002839 unsigned int i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002840
Giulio Camuffo954f1832014-10-11 18:27:30 +03002841 if (b->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002842 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -05002843
Daniel Stonef11ec022016-11-17 17:32:42 +00002844 fb = drm_fb_get_from_view(output_state, ev);
2845 if (!fb)
Daniel Stone296d7a92016-10-21 18:05:37 +01002846 return NULL;
2847
Daniel Stone085d2b92015-05-21 00:00:57 +01002848 wl_list_for_each(p, &b->plane_list, link) {
2849 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2850 continue;
2851
Daniel Stone5ff289a2017-10-07 12:59:02 +01002852 if (!drm_plane_is_available(p, output))
Daniel Stonebc15f682016-11-14 16:57:01 +00002853 continue;
2854
Daniel Stonef11ec022016-11-17 17:32:42 +00002855 /* Check whether the format is supported */
2856 for (i = 0; i < p->count_formats; i++) {
2857 if (p->formats[i] == fb->format->format)
2858 break;
2859 }
2860 if (i == p->count_formats)
2861 continue;
2862
Daniel Stonebc15f682016-11-14 16:57:01 +00002863 state = drm_output_state_get_plane(output_state, p);
2864 if (state->fb) {
2865 state = NULL;
2866 continue;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002867 }
Daniel Stonebc15f682016-11-14 16:57:01 +00002868
2869 break;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002870 }
2871
2872 /* No sprites available */
Daniel Stonef11ec022016-11-17 17:32:42 +00002873 if (!state) {
2874 drm_fb_unref(fb);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002875 return NULL;
Daniel Stonef11ec022016-11-17 17:32:42 +00002876 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002877
Daniel Stonef11ec022016-11-17 17:32:42 +00002878 state->fb = fb;
Daniel Stonece137472016-11-16 19:35:03 +00002879 state->output = output;
Daniel Stonef11ec022016-11-17 17:32:42 +00002880
Daniel Stonece137472016-11-16 19:35:03 +00002881 if (!drm_plane_state_coords_for_view(state, ev))
2882 goto err;
2883
2884 if (state->src_w != state->dest_w << 16 ||
2885 state->src_h != state->dest_h << 16)
2886 goto err;
2887
Daniel Stone08d4edf2017-04-04 17:54:34 +01002888 return &p->base;
Daniel Stonebc15f682016-11-14 16:57:01 +00002889
2890err:
Daniel Stonedb10df12016-12-08 13:15:58 +00002891 drm_plane_state_put_back(state);
Daniel Stonebc15f682016-11-14 16:57:01 +00002892 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002893}
2894
Pekka Paalanend0ead482014-06-16 12:05:40 +03002895/**
2896 * Update the image for the current cursor surface
2897 *
Daniel Stone9b560382016-11-16 19:46:35 +00002898 * @param plane_state DRM cursor plane state
2899 * @param ev Source view for cursor
Pekka Paalanend0ead482014-06-16 12:05:40 +03002900 */
2901static void
Daniel Stone9b560382016-11-16 19:46:35 +00002902cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
Pekka Paalanend0ead482014-06-16 12:05:40 +03002903{
Daniel Stone9b560382016-11-16 19:46:35 +00002904 struct drm_backend *b = plane_state->plane->backend;
2905 struct gbm_bo *bo = plane_state->fb->bo;
Pekka Paalanend0ead482014-06-16 12:05:40 +03002906 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
2907 uint32_t buf[b->cursor_width * b->cursor_height];
2908 int32_t stride;
2909 uint8_t *s;
2910 int i;
2911
2912 assert(buffer && buffer->shm_buffer);
2913 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
Daniel Stone9b560382016-11-16 19:46:35 +00002914 assert(buffer->width <= b->cursor_width);
2915 assert(buffer->height <= b->cursor_height);
Pekka Paalanend0ead482014-06-16 12:05:40 +03002916
2917 memset(buf, 0, sizeof buf);
2918 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
2919 s = wl_shm_buffer_get_data(buffer->shm_buffer);
2920
2921 wl_shm_buffer_begin_access(buffer->shm_buffer);
Daniel Stone9b560382016-11-16 19:46:35 +00002922 for (i = 0; i < buffer->height; i++)
Pekka Paalanend0ead482014-06-16 12:05:40 +03002923 memcpy(buf + i * b->cursor_width,
2924 s + i * stride,
Daniel Stone9b560382016-11-16 19:46:35 +00002925 buffer->width * 4);
Pekka Paalanend0ead482014-06-16 12:05:40 +03002926 wl_shm_buffer_end_access(buffer->shm_buffer);
2927
2928 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
2929 weston_log("failed update cursor: %m\n");
2930}
2931
Daniel Stone2ba17f42015-05-19 20:02:41 +01002932static struct weston_plane *
2933drm_output_prepare_cursor_view(struct drm_output_state *output_state,
2934 struct weston_view *ev)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04002935{
Daniel Stone2ba17f42015-05-19 20:02:41 +01002936 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02002937 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stone2ba17f42015-05-19 20:02:41 +01002938 struct drm_plane *plane = output->cursor_plane;
2939 struct drm_plane_state *plane_state;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002940 struct wl_shm_buffer *shmbuf;
2941 bool needs_update = false;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05002942
Daniel Stone2ba17f42015-05-19 20:02:41 +01002943 if (!plane)
2944 return NULL;
2945
2946 if (b->cursors_are_broken)
2947 return NULL;
2948
2949 if (!plane->state_cur->complete)
2950 return NULL;
2951
2952 if (plane->state_cur->output && plane->state_cur->output != output)
2953 return NULL;
2954
2955 /* Don't import buffers which span multiple outputs. */
2956 if (ev->output_mask != (1u << output->base.id))
2957 return NULL;
2958
2959 /* We use GBM to import SHM buffers. */
2960 if (b->gbm == NULL)
2961 return NULL;
2962
2963 if (ev->surface->buffer_ref.buffer == NULL)
2964 return NULL;
2965 shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
2966 if (!shmbuf)
2967 return NULL;
2968 if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)
2969 return NULL;
2970
Daniel Stone2ba17f42015-05-19 20:02:41 +01002971 plane_state =
2972 drm_output_state_get_plane(output_state, output->cursor_plane);
2973
2974 if (plane_state && plane_state->fb)
2975 return NULL;
2976
Daniel Stone9b560382016-11-16 19:46:35 +00002977 /* We can't scale with the legacy API, and we don't try to account for
2978 * simple cropping/translation in cursor_bo_update. */
2979 plane_state->output = output;
2980 if (!drm_plane_state_coords_for_view(plane_state, ev))
2981 goto err;
2982
2983 if (plane_state->src_x != 0 || plane_state->src_y != 0 ||
2984 plane_state->src_w > (unsigned) b->cursor_width << 16 ||
2985 plane_state->src_h > (unsigned) b->cursor_height << 16 ||
2986 plane_state->src_w != plane_state->dest_w << 16 ||
2987 plane_state->src_h != plane_state->dest_h << 16)
2988 goto err;
2989
Daniel Stone2ba17f42015-05-19 20:02:41 +01002990 /* Since we're setting plane state up front, we need to work out
2991 * whether or not we need to upload a new cursor. We can't use the
2992 * plane damage, since the planes haven't actually been calculated
2993 * yet: instead try to figure it out directly. KMS cursor planes are
2994 * pretty unique here, in that they lie partway between a Weston plane
2995 * (direct scanout) and a renderer. */
2996 if (ev != output->cursor_view ||
2997 pixman_region32_not_empty(&ev->surface->damage)) {
2998 output->current_cursor++;
2999 output->current_cursor =
3000 output->current_cursor %
3001 ARRAY_LENGTH(output->gbm_cursor_fb);
3002 needs_update = true;
3003 }
3004
3005 output->cursor_view = ev;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003006
3007 plane_state->fb =
3008 drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
Daniel Stone9b560382016-11-16 19:46:35 +00003009
3010 if (needs_update)
3011 cursor_bo_update(plane_state, ev);
3012
3013 /* The cursor API is somewhat special: in cursor_bo_update(), we upload
3014 * a buffer which is always cursor_width x cursor_height, even if the
3015 * surface we want to promote is actually smaller than this. Manually
3016 * mangle the plane state to deal with this. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01003017 plane_state->src_w = b->cursor_width << 16;
3018 plane_state->src_h = b->cursor_height << 16;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003019 plane_state->dest_w = b->cursor_width;
3020 plane_state->dest_h = b->cursor_height;
3021
Daniel Stone2ba17f42015-05-19 20:02:41 +01003022 return &plane->base;
Daniel Stone9b560382016-11-16 19:46:35 +00003023
3024err:
3025 drm_plane_state_put_back(plane_state);
3026 return NULL;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003027}
3028
3029static void
3030drm_output_set_cursor(struct drm_output_state *output_state)
3031{
3032 struct drm_output *output = output_state->output;
3033 struct drm_backend *b = to_drm_backend(output->base.compositor);
3034 struct drm_plane *plane = output->cursor_plane;
3035 struct drm_plane_state *state;
3036 EGLint handle;
3037 struct gbm_bo *bo;
3038
3039 if (!plane)
3040 return;
3041
3042 state = drm_output_state_get_existing_plane(output_state, plane);
3043 if (!state)
3044 return;
3045
3046 if (!state->fb) {
3047 pixman_region32_fini(&plane->base.damage);
3048 pixman_region32_init(&plane->base.damage);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003049 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04003050 return;
3051 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003052
Daniel Stone2ba17f42015-05-19 20:02:41 +01003053 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
3054 assert(!plane->state_cur->output || plane->state_cur->output == output);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003055
Daniel Stone2ba17f42015-05-19 20:02:41 +01003056 if (plane->state_cur->fb != state->fb) {
3057 bo = state->fb->bo;
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04003058 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03003059 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
Daniel Stone2ba17f42015-05-19 20:02:41 +01003060 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03003061 weston_log("failed to set cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01003062 goto err;
Rob Clarkab5b1e32012-08-09 13:24:45 -05003063 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003064 }
3065
Daniel Stone2ba17f42015-05-19 20:02:41 +01003066 pixman_region32_fini(&plane->base.damage);
3067 pixman_region32_init(&plane->base.damage);
Pekka Paalanen7eaed402015-11-27 14:20:58 +02003068
Daniel Stone2ba17f42015-05-19 20:02:41 +01003069 if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
3070 state->dest_x, state->dest_y)) {
Daniel Stonea7cba1d2017-04-04 17:54:21 +01003071 weston_log("failed to move cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01003072 goto err;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003073 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003074
3075 return;
3076
3077err:
3078 b->cursors_are_broken = 1;
3079 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003080}
3081
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303082/*
3083 * Get the aspect-ratio from drmModeModeInfo mode flags.
3084 *
3085 * @param drm_mode_flags- flags from drmModeModeInfo structure.
3086 * @returns aspect-ratio as encoded in enum 'weston_mode_aspect_ratio'.
3087 */
3088static enum weston_mode_aspect_ratio
3089drm_to_weston_mode_aspect_ratio(uint32_t drm_mode_flags)
3090{
3091 return (drm_mode_flags & DRM_MODE_FLAG_PIC_AR_MASK) >>
3092 DRM_MODE_FLAG_PIC_AR_BITS_POS;
3093}
3094
3095static const char *
3096aspect_ratio_to_string(enum weston_mode_aspect_ratio ratio)
3097{
3098 if (ratio < 0 || ratio >= ARRAY_LENGTH(aspect_ratio_as_string) ||
3099 !aspect_ratio_as_string[ratio])
3100 return " (unknown aspect ratio)";
3101
3102 return aspect_ratio_as_string[ratio];
3103}
3104
Jesse Barnes58ef3792012-02-23 09:45:49 -05003105static void
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003106drm_assign_planes(struct weston_output *output_base, void *repaint_data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05003107{
Armin Krezović545dba62016-08-05 15:54:18 +02003108 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003109 struct drm_pending_state *pending_state = repaint_data;
Armin Krezović545dba62016-08-05 15:54:18 +02003110 struct drm_output *output = to_drm_output(output_base);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003111 struct drm_output_state *state;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003112 struct drm_plane_state *plane_state;
Daniel Stonec3fcb5b2016-12-01 12:33:54 +00003113 struct weston_view *ev;
Daniel Stone115ed2c2016-11-08 21:19:22 +00003114 pixman_region32_t surface_overlap, renderer_region;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003115 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003116
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003117 assert(!output->state_last);
3118 state = drm_output_state_duplicate(output->state_cur,
3119 pending_state,
3120 DRM_OUTPUT_STATE_CLEAR_PLANES);
3121
Jesse Barnes58ef3792012-02-23 09:45:49 -05003122 /*
3123 * Find a surface for each sprite in the output using some heuristics:
3124 * 1) size
3125 * 2) frequency of update
3126 * 3) opacity (though some hw might support alpha blending)
3127 * 4) clipping (this can be fixed with color keys)
3128 *
3129 * The idea is to save on blitting since this should save power.
3130 * If we can get a large video surface on the sprite for example,
3131 * the main display surface may not need to update at all, and
3132 * the client buffer can be used directly for the sprite surface
3133 * as we do for flipping full screen surfaces.
3134 */
Daniel Stone115ed2c2016-11-08 21:19:22 +00003135 pixman_region32_init(&renderer_region);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003136 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003137
Daniel Stonec3fcb5b2016-12-01 12:33:54 +00003138 wl_list_for_each(ev, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02003139 struct weston_surface *es = ev->surface;
3140
3141 /* Test whether this buffer can ever go into a plane:
3142 * non-shm, or small enough to be a cursor.
3143 *
3144 * Also, keep a reference when using the pixman renderer.
3145 * That makes it possible to do a seamless switch to the GL
3146 * renderer and since the pixman renderer keeps a reference
3147 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02003148 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003149 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02003150 (es->buffer_ref.buffer &&
3151 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Derek Foreman87430472015-10-15 10:24:48 -05003152 (ev->surface->width <= b->cursor_width &&
3153 ev->surface->height <= b->cursor_height))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05003154 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02003155 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05003156 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02003157
Jesse Barnes58ef3792012-02-23 09:45:49 -05003158 pixman_region32_init(&surface_overlap);
Daniel Stone115ed2c2016-11-08 21:19:22 +00003159 pixman_region32_intersect(&surface_overlap, &renderer_region,
Jason Ekstranda7af7042013-10-12 22:38:11 -05003160 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003161
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003162 next_plane = NULL;
Daniel Stonef9bd5462018-05-15 17:09:53 +01003163 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003164 next_plane = primary;
3165 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003166 next_plane = drm_output_prepare_cursor_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05003167
Daniel Stonef9bd5462018-05-15 17:09:53 +01003168 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003169 next_plane = drm_output_prepare_scanout_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05003170
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003171 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003172 next_plane = drm_output_prepare_overlay_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05003173
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003174 if (next_plane == NULL)
3175 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003176
Jason Ekstranda7af7042013-10-12 22:38:11 -05003177 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003178
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003179 if (next_plane == primary)
Daniel Stone115ed2c2016-11-08 21:19:22 +00003180 pixman_region32_union(&renderer_region,
3181 &renderer_region,
Jason Ekstranda7af7042013-10-12 22:38:11 -05003182 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04003183
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003184 if (next_plane == primary ||
Daniel Stone2ba17f42015-05-19 20:02:41 +01003185 (output->cursor_plane &&
3186 next_plane == &output->cursor_plane->base)) {
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003187 /* cursor plane involves a copy */
3188 ev->psf_flags = 0;
3189 } else {
3190 /* All other planes are a direct scanout of a
3191 * single client buffer.
3192 */
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02003193 ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003194 }
3195
Jesse Barnes58ef3792012-02-23 09:45:49 -05003196 pixman_region32_fini(&surface_overlap);
3197 }
Daniel Stone115ed2c2016-11-08 21:19:22 +00003198 pixman_region32_fini(&renderer_region);
Daniel Stone2ba17f42015-05-19 20:02:41 +01003199
3200 /* We rely on output->cursor_view being both an accurate reflection of
3201 * the cursor plane's state, but also being maintained across repaints
3202 * to avoid unnecessary damage uploads, per the comment in
3203 * drm_output_prepare_cursor_view. In the event that we go from having
3204 * a cursor view to not having a cursor view, we need to clear it. */
3205 if (output->cursor_view) {
3206 plane_state =
3207 drm_output_state_get_existing_plane(state,
3208 output->cursor_plane);
3209 if (!plane_state || !plane_state->fb)
3210 output->cursor_view = NULL;
3211 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05003212}
3213
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003214/**
3215 * Find the closest-matching mode for a given target
3216 *
3217 * Given a target mode, find the most suitable mode amongst the output's
3218 * current mode list to use, preferring the current mode if possible, to
3219 * avoid an expensive mode switch.
3220 *
3221 * @param output DRM output
3222 * @param target_mode Mode to attempt to match
3223 * @returns Pointer to a mode from the output's mode list
3224 */
Alex Wub7b8bda2012-04-17 17:20:48 +08003225static struct drm_mode *
3226choose_mode (struct drm_output *output, struct weston_mode *target_mode)
3227{
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303228 struct drm_mode *tmp_mode = NULL, *mode_fall_back = NULL, *mode;
3229 enum weston_mode_aspect_ratio src_aspect = WESTON_MODE_PIC_AR_NONE;
3230 enum weston_mode_aspect_ratio target_aspect = WESTON_MODE_PIC_AR_NONE;
3231 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08003232
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303233 b = to_drm_backend(output->base.compositor);
3234 target_aspect = target_mode->aspect_ratio;
3235 src_aspect = output->base.current_mode->aspect_ratio;
Hardeningff39efa2013-09-18 23:56:35 +02003236 if (output->base.current_mode->width == target_mode->width &&
3237 output->base.current_mode->height == target_mode->height &&
3238 (output->base.current_mode->refresh == target_mode->refresh ||
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303239 target_mode->refresh == 0)) {
3240 if (!b->aspect_ratio_supported || src_aspect == target_aspect)
3241 return to_drm_mode(output->base.current_mode);
3242 }
Alex Wub7b8bda2012-04-17 17:20:48 +08003243
3244 wl_list_for_each(mode, &output->base.mode_list, base.link) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303245
3246 src_aspect = mode->base.aspect_ratio;
Alex Wub7b8bda2012-04-17 17:20:48 +08003247 if (mode->mode_info.hdisplay == target_mode->width &&
3248 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02003249 if (mode->base.refresh == target_mode->refresh ||
3250 target_mode->refresh == 0) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303251 if (!b->aspect_ratio_supported ||
3252 src_aspect == target_aspect)
3253 return mode;
3254 else if (!mode_fall_back)
3255 mode_fall_back = mode;
3256 } else if (!tmp_mode) {
Alex Wub7b8bda2012-04-17 17:20:48 +08003257 tmp_mode = mode;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303258 }
Alex Wub7b8bda2012-04-17 17:20:48 +08003259 }
3260 }
3261
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303262 if (mode_fall_back)
3263 return mode_fall_back;
3264
Alex Wub7b8bda2012-04-17 17:20:48 +08003265 return tmp_mode;
3266}
3267
3268static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003269drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003270static void
3271drm_output_fini_egl(struct drm_output *output);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003272static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003273drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003274static void
3275drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003276
3277static int
Alex Wub7b8bda2012-04-17 17:20:48 +08003278drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
3279{
Daniel Stone02d487a2017-10-07 14:01:45 +01003280 struct drm_output *output = to_drm_output(output_base);
3281 struct drm_backend *b = to_drm_backend(output_base->compositor);
3282 struct drm_mode *drm_mode = choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +08003283
3284 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +01003285 weston_log("%s: invalid resolution %dx%d\n",
3286 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08003287 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003288 }
3289
Hardeningff39efa2013-09-18 23:56:35 +02003290 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08003291 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003292
Hardeningff39efa2013-09-18 23:56:35 +02003293 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003294
Hardeningff39efa2013-09-18 23:56:35 +02003295 output->base.current_mode = &drm_mode->base;
3296 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08003297 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
3298
Daniel Stonef30a18c2017-04-04 17:54:31 +01003299 /* XXX: This drops our current buffer too early, before we've started
3300 * displaying it. Ideally this should be much more atomic and
3301 * integrated with a full repaint cycle, rather than doing a
3302 * sledgehammer modeswitch first, and only later showing new
3303 * content.
3304 */
Daniel Stone6020f472018-02-05 15:46:20 +00003305 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +08003306
Giulio Camuffo954f1832014-10-11 18:27:30 +03003307 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003308 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003309 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003310 weston_log("failed to init output pixman state with "
3311 "new mode\n");
3312 return -1;
3313 }
3314 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +00003315 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003316 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003317 weston_log("failed to init output egl state with "
3318 "new mode");
3319 return -1;
3320 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003321 }
3322
Alex Wub7b8bda2012-04-17 17:20:48 +08003323 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003324}
3325
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003326static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003327on_drm_input(int fd, uint32_t mask, void *data)
3328{
Daniel Stone598ee9d2016-11-16 11:55:20 +00003329#ifdef HAVE_DRM_ATOMIC
3330 struct drm_backend *b = data;
3331#endif
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003332 drmEventContext evctx;
3333
3334 memset(&evctx, 0, sizeof evctx);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003335#ifndef HAVE_DRM_ATOMIC
Emil Velikov863e66b2017-04-04 18:07:34 +01003336 evctx.version = 2;
Daniel Stone598ee9d2016-11-16 11:55:20 +00003337#else
3338 evctx.version = 3;
3339 if (b->atomic_modeset)
3340 evctx.page_flip_handler2 = atomic_flip_handler;
3341 else
3342#endif
3343 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003344 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003345 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003346
3347 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003348}
3349
3350static int
Daniel Stoneefa504f2016-12-19 16:48:20 +00003351init_kms_caps(struct drm_backend *b)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003352{
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003353 uint64_t cap;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003354 int ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003355 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003356
Daniel Stoneefa504f2016-12-19 16:48:20 +00003357 weston_log("using %s\n", b->drm.filename);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003358
Daniel Stoneefa504f2016-12-19 16:48:20 +00003359 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003360 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003361 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003362 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003363 clk_id = CLOCK_REALTIME;
3364
Giulio Camuffo954f1832014-10-11 18:27:30 +03003365 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003366 weston_log("Error: failed to set presentation clock %d.\n",
3367 clk_id);
3368 return -1;
3369 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02003370
Daniel Stoneefa504f2016-12-19 16:48:20 +00003371 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003372 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003373 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003374 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003375 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003376
Daniel Stoneefa504f2016-12-19 16:48:20 +00003377 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003378 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003379 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003380 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003381 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003382
Daniel Stonebe1090b2017-09-06 17:29:57 +01003383 if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
3384 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
3385 b->universal_planes = (ret == 0);
3386 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003387 weston_log("DRM: %s universal planes\n",
3388 b->universal_planes ? "supports" : "does not support");
3389
Pekka Paalanencd011a62016-11-15 22:07:49 +00003390#ifdef HAVE_DRM_ATOMIC
3391 if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00003392 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
3393 if (ret != 0)
3394 cap = 0;
Pekka Paalanencd011a62016-11-15 22:07:49 +00003395 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003396 b->atomic_modeset = ((ret == 0) && (cap == 1));
Pekka Paalanencd011a62016-11-15 22:07:49 +00003397 }
3398#endif
3399 weston_log("DRM: %s atomic modesetting\n",
3400 b->atomic_modeset ? "supports" : "does not support");
3401
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303402 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
3403 b->aspect_ratio_supported = (ret == 0);
3404 weston_log("DRM: %s picture aspect ratio\n",
3405 b->aspect_ratio_supported ? "supports" : "does not support");
3406
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003407 return 0;
3408}
3409
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003410static struct gbm_device *
3411create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003412{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003413 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01003414
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003415 gl_renderer = weston_load_module("gl-renderer.so",
3416 "gl_renderer_interface");
3417 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003418 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003419
3420 /* GBM will load a dri driver, but even though they need symbols from
3421 * libglapi, in some version of Mesa they are not linked to it. Since
3422 * only the gl-renderer module links to it, the call above won't make
3423 * these symbols globally available, and loading the DRI driver fails.
3424 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
3425 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
3426
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003427 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003428
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003429 return gbm;
3430}
3431
Bryce Harringtonc056a982015-05-19 15:25:18 -07003432/* When initializing EGL, if the preferred buffer format isn't available
Bryce Harringtonb9939982016-04-15 20:28:26 -07003433 * we may be able to substitute an ARGB format for an XRGB one.
Derek Foremanc4cfe852015-05-15 12:12:40 -05003434 *
3435 * This returns 0 if substitution isn't possible, but 0 might be a
3436 * legitimate format for other EGL platforms, so the caller is
3437 * responsible for checking for 0 before calling gl_renderer->create().
3438 *
3439 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
3440 * but it's entirely possible we'll see this again on other implementations.
3441 */
3442static int
3443fallback_format_for(uint32_t format)
3444{
3445 switch (format) {
3446 case GBM_FORMAT_XRGB8888:
3447 return GBM_FORMAT_ARGB8888;
3448 case GBM_FORMAT_XRGB2101010:
3449 return GBM_FORMAT_ARGB2101010;
3450 default:
3451 return 0;
3452 }
3453}
3454
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003455static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003456drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003457{
Derek Foreman6d556372015-11-04 14:47:33 -06003458 EGLint format[3] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01003459 b->gbm_format,
3460 fallback_format_for(b->gbm_format),
Derek Foreman6d556372015-11-04 14:47:33 -06003461 0,
Derek Foremanc4cfe852015-05-15 12:12:40 -05003462 };
Derek Foreman6d556372015-11-04 14:47:33 -06003463 int n_formats = 2;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01003464
Derek Foremanc4cfe852015-05-15 12:12:40 -05003465 if (format[1])
Derek Foreman6d556372015-11-04 14:47:33 -06003466 n_formats = 3;
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003467 if (gl_renderer->display_create(b->compositor,
3468 EGL_PLATFORM_GBM_KHR,
3469 (void *)b->gbm,
Miguel A. Vico41700e32016-05-18 17:47:59 +02003470 NULL,
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003471 gl_renderer->opaque_attribs,
3472 format,
3473 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003474 return -1;
3475 }
3476
3477 return 0;
3478}
3479
3480static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003481init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003482{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003483 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003484
Giulio Camuffo954f1832014-10-11 18:27:30 +03003485 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003486 return -1;
3487
Giulio Camuffo954f1832014-10-11 18:27:30 +03003488 if (drm_backend_create_gl_renderer(b) < 0) {
3489 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003490 return -1;
3491 }
3492
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003493 return 0;
3494}
3495
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003496static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003497init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003498{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003499 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003500}
3501
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003502/**
Pekka Paalanenec272712014-06-05 11:22:25 +03003503 * Create a drm_plane for a hardware plane
3504 *
3505 * Creates one drm_plane structure for a hardware plane, and initialises its
3506 * properties and formats.
3507 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003508 * In the absence of universal plane support, where KMS does not explicitly
3509 * expose the primary and cursor planes to userspace, this may also create
3510 * an 'internal' plane for internal management.
3511 *
Pekka Paalanenec272712014-06-05 11:22:25 +03003512 * This function does not add the plane to the list of usable planes in Weston
3513 * itself; the caller is responsible for this.
3514 *
3515 * Call drm_plane_destroy to clean up the plane.
3516 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003517 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +03003518 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +01003519 * @param kplane DRM plane to create, or NULL if creating internal plane
3520 * @param output Output to create internal plane for, or NULL
3521 * @param type Type to use when creating internal plane, or invalid
3522 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +03003523 */
3524static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003525drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
3526 struct drm_output *output, enum wdrm_plane_type type,
3527 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +03003528{
3529 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003530 drmModeObjectProperties *props;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003531 int num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003532
Daniel Stone2ba17f42015-05-19 20:02:41 +01003533 plane = zalloc(sizeof(*plane) +
3534 (sizeof(uint32_t) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +03003535 if (!plane) {
3536 weston_log("%s: out of memory\n", __func__);
3537 return NULL;
3538 }
3539
3540 plane->backend = b;
Daniel Stonebc15f682016-11-14 16:57:01 +00003541 plane->state_cur = drm_plane_state_alloc(NULL, plane);
3542 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +03003543
Daniel Stone2ba17f42015-05-19 20:02:41 +01003544 if (kplane) {
3545 plane->possible_crtcs = kplane->possible_crtcs;
3546 plane->plane_id = kplane->plane_id;
3547 plane->count_formats = kplane->count_formats;
3548 memcpy(plane->formats, kplane->formats,
3549 kplane->count_formats * sizeof(kplane->formats[0]));
3550
3551 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
3552 DRM_MODE_OBJECT_PLANE);
3553 if (!props) {
3554 weston_log("couldn't get plane properties\n");
3555 goto err;
3556 }
3557 drm_property_info_populate(b, plane_props, plane->props,
3558 WDRM_PLANE__COUNT, props);
3559 plane->type =
3560 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
3561 props,
3562 WDRM_PLANE_TYPE__COUNT);
3563 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003564 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003565 else {
3566 plane->possible_crtcs = (1 << output->pipe);
3567 plane->plane_id = 0;
3568 plane->count_formats = 1;
3569 plane->formats[0] = format;
3570 plane->type = type;
3571 }
3572
3573 if (plane->type == WDRM_PLANE_TYPE__COUNT)
3574 goto err_props;
3575
3576 /* With universal planes, everything is a DRM plane; without
3577 * universal planes, the only DRM planes are overlay planes.
3578 * Everything else is a fake plane. */
3579 if (b->universal_planes) {
3580 assert(kplane);
3581 } else {
3582 if (kplane)
3583 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
3584 else
3585 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
3586 output);
3587 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003588
Pekka Paalanenec272712014-06-05 11:22:25 +03003589 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01003590 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +03003591
3592 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003593
3594err_props:
3595 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
3596err:
3597 drm_plane_state_free(plane->state_cur, true);
3598 free(plane);
3599 return NULL;
3600}
3601
3602/**
3603 * Find, or create, a special-purpose plane
3604 *
3605 * Primary and cursor planes are a special case, in that before universal
3606 * planes, they are driven by non-plane API calls. Without universal plane
3607 * support, the only way to configure a primary plane is via drmModeSetCrtc,
3608 * and the only way to configure a cursor plane is drmModeSetCursor2.
3609 *
3610 * Although they may actually be regular planes in the hardware, without
3611 * universal plane support, these planes are not actually exposed to
3612 * userspace in the regular plane list.
3613 *
3614 * However, for ease of internal tracking, we want to manage all planes
3615 * through the same drm_plane structures. Therefore, when we are running
3616 * without universal plane support, we create fake drm_plane structures
3617 * to track these planes.
3618 *
3619 * @param b DRM backend
3620 * @param output Output to use for plane
3621 * @param type Type of plane
3622 */
3623static struct drm_plane *
3624drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
3625 enum wdrm_plane_type type)
3626{
3627 struct drm_plane *plane;
3628
3629 if (!b->universal_planes) {
3630 uint32_t format;
3631
3632 switch (type) {
3633 case WDRM_PLANE_TYPE_CURSOR:
3634 format = GBM_FORMAT_ARGB8888;
3635 break;
Daniel Stonee2e80132018-01-16 15:37:33 +00003636 case WDRM_PLANE_TYPE_PRIMARY:
3637 /* We don't know what formats the primary plane supports
3638 * before universal planes, so we just assume that the
3639 * GBM format works; however, this isn't set until after
3640 * the output is created. */
3641 format = 0;
3642 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003643 default:
3644 assert(!"invalid type in drm_output_find_special_plane");
3645 break;
3646 }
3647
3648 return drm_plane_create(b, NULL, output, type, format);
3649 }
3650
3651 wl_list_for_each(plane, &b->plane_list, link) {
3652 struct drm_output *tmp;
3653 bool found_elsewhere = false;
3654
3655 if (plane->type != type)
3656 continue;
3657 if (!drm_plane_is_available(plane, output))
3658 continue;
3659
3660 /* On some platforms, primary/cursor planes can roam
3661 * between different CRTCs, so make sure we don't claim the
3662 * same plane for two outputs. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01003663 wl_list_for_each(tmp, &b->compositor->output_list,
3664 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +00003665 if (tmp->cursor_plane == plane ||
3666 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +01003667 found_elsewhere = true;
3668 break;
3669 }
3670 }
3671
3672 if (found_elsewhere)
3673 continue;
3674
3675 plane->possible_crtcs = (1 << output->pipe);
3676 return plane;
3677 }
3678
3679 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +03003680}
3681
3682/**
3683 * Destroy one DRM plane
3684 *
3685 * Destroy a DRM plane, removing it from screen and releasing its retained
3686 * buffers in the process. The counterpart to drm_plane_create.
3687 *
3688 * @param plane Plane to deallocate (will be freed)
3689 */
3690static void
3691drm_plane_destroy(struct drm_plane *plane)
3692{
Daniel Stone2ba17f42015-05-19 20:02:41 +01003693 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
3694 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
3695 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +00003696 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003697 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +03003698 weston_plane_release(&plane->base);
3699 wl_list_remove(&plane->link);
3700 free(plane);
3701}
3702
3703/**
3704 * Initialise sprites (overlay planes)
3705 *
3706 * Walk the list of provided DRM planes, and add overlay planes.
3707 *
3708 * Call destroy_sprites to free these planes.
3709 *
3710 * @param b DRM compositor backend
3711 */
3712static void
3713create_sprites(struct drm_backend *b)
3714{
3715 drmModePlaneRes *kplane_res;
3716 drmModePlane *kplane;
3717 struct drm_plane *drm_plane;
3718 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +03003719 kplane_res = drmModeGetPlaneResources(b->drm.fd);
3720 if (!kplane_res) {
3721 weston_log("failed to get plane resources: %s\n",
3722 strerror(errno));
3723 return;
3724 }
3725
3726 for (i = 0; i < kplane_res->count_planes; i++) {
3727 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
3728 if (!kplane)
3729 continue;
3730
Daniel Stone2ba17f42015-05-19 20:02:41 +01003731 drm_plane = drm_plane_create(b, kplane, NULL,
3732 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +03003733 drmModeFreePlane(kplane);
3734 if (!drm_plane)
3735 continue;
3736
Daniel Stone085d2b92015-05-21 00:00:57 +01003737 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
3738 weston_compositor_stack_plane(b->compositor,
3739 &drm_plane->base,
3740 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +03003741 }
3742
3743 drmModeFreePlaneResources(kplane_res);
3744}
3745
3746/**
3747 * Clean up sprites (overlay planes)
3748 *
3749 * The counterpart to create_sprites.
3750 *
3751 * @param b DRM compositor backend
3752 */
3753static void
3754destroy_sprites(struct drm_backend *b)
3755{
3756 struct drm_plane *plane, *next;
3757
Daniel Stone085d2b92015-05-21 00:00:57 +01003758 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03003759 drm_plane_destroy(plane);
3760}
3761
Pekka Paalanendc14fd42017-11-10 15:31:39 +02003762static uint32_t
3763drm_refresh_rate_mHz(const drmModeModeInfo *info)
3764{
3765 uint64_t refresh;
3766
3767 /* Calculate higher precision (mHz) refresh rate */
3768 refresh = (info->clock * 1000000LL / info->htotal +
3769 info->vtotal / 2) / info->vtotal;
3770
3771 if (info->flags & DRM_MODE_FLAG_INTERLACE)
3772 refresh *= 2;
3773 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
3774 refresh /= 2;
3775 if (info->vscan > 1)
3776 refresh /= info->vscan;
3777
3778 return refresh;
3779}
3780
Pekka Paalanenec272712014-06-05 11:22:25 +03003781/**
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003782 * Add a mode to output's mode list
3783 *
3784 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
3785 * output's mode list.
3786 *
3787 * @param output DRM output to add mode to
3788 * @param info DRM mode structure to add
3789 * @returns Newly-allocated Weston/DRM mode structure
3790 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003791static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003792drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003793{
3794 struct drm_mode *mode;
3795
3796 mode = malloc(sizeof *mode);
3797 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003798 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003799
3800 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02003801 mode->base.width = info->hdisplay;
3802 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04003803
Pekka Paalanendc14fd42017-11-10 15:31:39 +02003804 mode->base.refresh = drm_refresh_rate_mHz(info);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003805 mode->mode_info = *info;
Daniel Stoned5526cb2016-11-16 10:54:10 +00003806 mode->blob_id = 0;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003807
3808 if (info->type & DRM_MODE_TYPE_PREFERRED)
3809 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
3810
Ankit Nautiyala21c3932097-03-19 00:24:57 +05303811 mode->base.aspect_ratio = drm_to_weston_mode_aspect_ratio(info->flags);
3812
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003813 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
3814
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003815 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003816}
3817
Daniel Stoned5526cb2016-11-16 10:54:10 +00003818/**
3819 * Destroys a mode, and removes it from the list.
3820 */
3821static void
3822drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
3823{
3824 if (mode->blob_id)
3825 drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
3826 wl_list_remove(&mode->base.link);
3827 free(mode);
3828}
3829
Pekka Paalanen383b3af2017-09-11 14:40:48 +03003830/** Destroy a list of drm_modes
3831 *
3832 * @param backend The backend for releasing mode property blobs.
3833 * @param mode_list The list linked by drm_mode::base.link.
3834 */
3835static void
3836drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
3837{
3838 struct drm_mode *mode, *next;
3839
3840 wl_list_for_each_safe(mode, next, mode_list, base.link)
3841 drm_output_destroy_mode(backend, mode);
3842}
3843
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003844static int
3845drm_subpixel_to_wayland(int drm_value)
3846{
3847 switch (drm_value) {
3848 default:
3849 case DRM_MODE_SUBPIXEL_UNKNOWN:
3850 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
3851 case DRM_MODE_SUBPIXEL_NONE:
3852 return WL_OUTPUT_SUBPIXEL_NONE;
3853 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
3854 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
3855 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
3856 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
3857 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
3858 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
3859 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
3860 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
3861 }
3862}
3863
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003864/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003865static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +03003866drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003867{
3868 long brightness, max_brightness, norm;
3869
Pekka Paalanence724242017-09-04 12:21:24 +03003870 brightness = backlight_get_brightness(head->backlight);
3871 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003872
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003873 /* convert it on a scale of 0 to 255 */
3874 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003875
3876 return (uint32_t) norm;
3877}
3878
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003879/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003880static void
3881drm_set_backlight(struct weston_output *output_base, uint32_t value)
3882{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03003883 struct drm_output *output = to_drm_output(output_base);
3884 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003885 long max_brightness, new_brightness;
3886
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04003887 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003888 return;
3889
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03003890 wl_list_for_each(head, &output->base.head_list, base.output_link) {
3891 if (!head->backlight)
3892 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003893
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03003894 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003895
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03003896 /* get denormalized value */
3897 new_brightness = (value * max_brightness) / 255;
3898
3899 backlight_set_brightness(head->backlight, new_brightness);
3900 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003901}
3902
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02003903static void
3904drm_output_init_backlight(struct drm_output *output)
3905{
3906 struct weston_head *base;
3907 struct drm_head *head;
3908
3909 output->base.set_backlight = NULL;
3910
3911 wl_list_for_each(base, &output->base.head_list, output_link) {
3912 head = to_drm_head(base);
3913
3914 if (head->backlight) {
3915 weston_log("Initialized backlight for head '%s', device %s\n",
3916 head->base.name, head->backlight->path);
3917
3918 if (!output->base.set_backlight) {
3919 output->base.set_backlight = drm_set_backlight;
3920 output->base.backlight_current =
3921 drm_get_backlight(head);
3922 }
3923 }
3924 }
3925
3926 if (!output->base.set_backlight) {
3927 weston_log("No backlight control for output '%s'\n",
3928 output->base.name);
3929 }
3930}
3931
Daniel Stonea08512f2016-11-08 17:46:10 +00003932/**
3933 * Power output on or off
3934 *
3935 * The DPMS/power level of an output is used to switch it on or off. This
3936 * is DRM's hook for doing so, which can called either as part of repaint,
3937 * or independently of the repaint loop.
3938 *
3939 * If we are called as part of repaint, we simply set the relevant bit in
3940 * state and return.
3941 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003942static void
3943drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
3944{
Armin Krezović545dba62016-08-05 15:54:18 +02003945 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00003946 struct drm_backend *b = to_drm_backend(output_base->compositor);
3947 struct drm_pending_state *pending_state = b->repaint_data;
3948 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01003949 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003950
Daniel Stonea08512f2016-11-08 17:46:10 +00003951 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003952 return;
3953
Daniel Stonea08512f2016-11-08 17:46:10 +00003954 /* If we're being called during the repaint loop, then this is
3955 * simple: discard any previously-generated state, and create a new
3956 * state where we disable everything. When we come to flush, this
3957 * will be applied.
3958 *
3959 * However, we need to be careful: we can be called whilst another
3960 * output is in its repaint cycle (pending_state exists), but our
3961 * output still has an incomplete state application outstanding.
3962 * In that case, we need to wait until that completes. */
3963 if (pending_state && !output->state_last) {
3964 /* The repaint loop already sets DPMS on; we don't need to
3965 * explicitly set it on here, as it will already happen
3966 * whilst applying the repaint state. */
3967 if (level == WESTON_DPMS_ON)
3968 return;
3969
3970 state = drm_pending_state_get_output(pending_state, output);
3971 if (state)
3972 drm_output_state_free(state);
3973 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01003974 return;
3975 }
3976
Daniel Stonea08512f2016-11-08 17:46:10 +00003977 /* As we throw everything away when disabling, just send us back through
3978 * a repaint cycle. */
3979 if (level == WESTON_DPMS_ON) {
3980 if (output->dpms_off_pending)
3981 output->dpms_off_pending = 0;
3982 weston_output_schedule_repaint(output_base);
3983 return;
3984 }
3985
3986 /* If we've already got a request in the pipeline, then we need to
3987 * park our DPMS request until that request has quiesced. */
3988 if (output->state_last) {
3989 output->dpms_off_pending = 1;
3990 return;
3991 }
3992
3993 pending_state = drm_pending_state_alloc(b);
3994 drm_output_get_disable_state(pending_state, output);
3995 ret = drm_pending_state_apply_sync(pending_state);
3996 if (ret != 0)
3997 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003998}
3999
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004000static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004001 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
4002 [DRM_MODE_CONNECTOR_VGA] = "VGA",
4003 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
4004 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
4005 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
4006 [DRM_MODE_CONNECTOR_Composite] = "Composite",
4007 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
4008 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
4009 [DRM_MODE_CONNECTOR_Component] = "Component",
4010 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
4011 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
4012 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
4013 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
4014 [DRM_MODE_CONNECTOR_TV] = "TV",
4015 [DRM_MODE_CONNECTOR_eDP] = "eDP",
Pekka Paalanenab81f152015-08-24 14:27:07 +03004016#ifdef DRM_MODE_CONNECTOR_DSI
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004017 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
4018 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Pekka Paalanenab81f152015-08-24 14:27:07 +03004019#endif
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04004020};
4021
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004022/** Create a name given a DRM connector
4023 *
4024 * \param con The DRM connector whose type and id form the name.
4025 * \return A newly allocate string, or NULL on error. Must be free()'d
4026 * after use.
4027 *
4028 * The name does not identify the DRM display device.
4029 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004030static char *
4031make_connector_name(const drmModeConnector *con)
4032{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004033 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004034 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004035 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004036
4037 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
4038 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03004039
4040 if (!type_name)
4041 type_name = "UNNAMED";
4042
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004043 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
4044 if (ret < 0)
4045 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004046
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03004047 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03004048}
4049
Daniel Stonee4256832017-04-04 17:54:27 +01004050static void drm_output_fini_cursor_egl(struct drm_output *output)
4051{
4052 unsigned int i;
4053
4054 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
4055 drm_fb_unref(output->gbm_cursor_fb[i]);
4056 output->gbm_cursor_fb[i] = NULL;
4057 }
4058}
4059
4060static int
4061drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
4062{
4063 unsigned int i;
4064
Daniel Stone2ba17f42015-05-19 20:02:41 +01004065 /* No point creating cursors if we don't have a plane for them. */
4066 if (!output->cursor_plane)
4067 return 0;
4068
Daniel Stonee4256832017-04-04 17:54:27 +01004069 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
4070 struct gbm_bo *bo;
4071
4072 bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
4073 GBM_FORMAT_ARGB8888,
4074 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
4075 if (!bo)
4076 goto err;
4077
4078 output->gbm_cursor_fb[i] =
Daniel Stonedb10df12016-12-08 13:15:58 +00004079 drm_fb_get_from_bo(bo, b, false, BUFFER_CURSOR);
Daniel Stonee4256832017-04-04 17:54:27 +01004080 if (!output->gbm_cursor_fb[i]) {
4081 gbm_bo_destroy(bo);
4082 goto err;
4083 }
4084 }
4085
4086 return 0;
4087
4088err:
4089 weston_log("cursor buffers unavailable, using gl cursors\n");
4090 b->cursors_are_broken = 1;
4091 drm_output_fini_cursor_egl(output);
4092 return -1;
4093}
4094
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004095/* Init output state that depends on gl or gbm */
4096static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004097drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004098{
Derek Foremanc4cfe852015-05-15 12:12:40 -05004099 EGLint format[2] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004100 output->gbm_format,
4101 fallback_format_for(output->gbm_format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05004102 };
Daniel Stonee4256832017-04-04 17:54:27 +01004103 int n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004104
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004105 output->gbm_surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02004106 output->base.current_mode->width,
4107 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05004108 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004109 GBM_BO_USE_SCANOUT |
4110 GBM_BO_USE_RENDERING);
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004111 if (!output->gbm_surface) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004112 weston_log("failed to create gbm surface\n");
4113 return -1;
4114 }
4115
Derek Foremanc4cfe852015-05-15 12:12:40 -05004116 if (format[1])
4117 n_formats = 2;
Miguel A. Vicoc095cde2016-05-18 17:43:00 +02004118 if (gl_renderer->output_window_create(&output->base,
4119 (EGLNativeWindowType)output->gbm_surface,
4120 output->gbm_surface,
4121 gl_renderer->opaque_attribs,
4122 format,
4123 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004124 weston_log("failed to create gl renderer output state\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004125 gbm_surface_destroy(output->gbm_surface);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004126 return -1;
4127 }
4128
Daniel Stonee4256832017-04-04 17:54:27 +01004129 drm_output_init_cursor_egl(output, b);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004130
4131 return 0;
4132}
4133
Daniel Stone3e661f72016-11-04 17:24:06 +00004134static void
4135drm_output_fini_egl(struct drm_output *output)
4136{
Daniel Stonee2e80132018-01-16 15:37:33 +00004137 struct drm_backend *b = to_drm_backend(output->base.compositor);
4138
4139 /* Destroying the GBM surface will destroy all our GBM buffers,
4140 * regardless of refcount. Ensure we destroy them here. */
4141 if (!b->shutting_down &&
4142 output->scanout_plane->state_cur->fb &&
4143 output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
4144 drm_plane_state_free(output->scanout_plane->state_cur, true);
4145 output->scanout_plane->state_cur =
4146 drm_plane_state_alloc(NULL, output->scanout_plane);
4147 output->scanout_plane->state_cur->complete = true;
4148 }
4149
Daniel Stone3e661f72016-11-04 17:24:06 +00004150 gl_renderer->output_destroy(&output->base);
4151 gbm_surface_destroy(output->gbm_surface);
Daniel Stonee4256832017-04-04 17:54:27 +01004152 drm_output_fini_cursor_egl(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00004153}
4154
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04004155static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004156drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004157{
Hardeningff39efa2013-09-18 23:56:35 +02004158 int w = output->base.current_mode->width;
4159 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004160 uint32_t format = output->gbm_format;
4161 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004162 unsigned int i;
Pekka Paalanendee412d2018-04-23 11:44:58 +02004163 uint32_t flags = 0;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004164
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004165 switch (format) {
4166 case GBM_FORMAT_XRGB8888:
4167 pixman_format = PIXMAN_x8r8g8b8;
4168 break;
4169 case GBM_FORMAT_RGB565:
4170 pixman_format = PIXMAN_r5g6b5;
4171 break;
4172 default:
4173 weston_log("Unsupported pixman format 0x%x\n", format);
4174 return -1;
4175 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004176
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004177 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004178 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004179 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004180 if (!output->dumb[i])
4181 goto err;
4182
4183 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004184 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004185 output->dumb[i]->map,
4186 output->dumb[i]->stride);
4187 if (!output->image[i])
4188 goto err;
4189 }
4190
Pekka Paalanendee412d2018-04-23 11:44:58 +02004191 if (b->use_pixman_shadow)
4192 flags |= PIXMAN_RENDERER_OUTPUT_USE_SHADOW;
4193
4194 if (pixman_renderer_output_create(&output->base, flags) < 0)
4195 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304196
Pekka Paalanendee412d2018-04-23 11:44:58 +02004197 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
4198 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004199
4200 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02004201 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004202
4203 return 0;
4204
4205err:
4206 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
4207 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01004208 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004209 if (output->image[i])
4210 pixman_image_unref(output->image[i]);
4211
4212 output->dumb[i] = NULL;
4213 output->image[i] = NULL;
4214 }
4215
4216 return -1;
4217}
4218
4219static void
4220drm_output_fini_pixman(struct drm_output *output)
4221{
Daniel Stonee2e80132018-01-16 15:37:33 +00004222 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004223 unsigned int i;
4224
Daniel Stonee2e80132018-01-16 15:37:33 +00004225 /* Destroying the Pixman surface will destroy all our buffers,
4226 * regardless of refcount. Ensure we destroy them here. */
4227 if (!b->shutting_down &&
4228 output->scanout_plane->state_cur->fb &&
4229 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
4230 drm_plane_state_free(output->scanout_plane->state_cur, true);
4231 output->scanout_plane->state_cur =
4232 drm_plane_state_alloc(NULL, output->scanout_plane);
4233 output->scanout_plane->state_cur->complete = true;
4234 }
4235
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004236 pixman_renderer_output_destroy(&output->base);
4237 pixman_region32_fini(&output->previous_damage);
4238
4239 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004240 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01004241 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004242 output->dumb[i] = NULL;
4243 output->image[i] = NULL;
4244 }
4245}
4246
Richard Hughes2b2092a2013-04-24 14:58:02 +01004247static void
4248edid_parse_string(const uint8_t *data, char text[])
4249{
4250 int i;
4251 int replaced = 0;
4252
4253 /* this is always 12 bytes, but we can't guarantee it's null
4254 * terminated or not junk. */
4255 strncpy(text, (const char *) data, 12);
4256
Bryce Harrington9c7de162015-08-28 13:04:26 -07004257 /* guarantee our new string is null-terminated */
4258 text[12] = '\0';
4259
Richard Hughes2b2092a2013-04-24 14:58:02 +01004260 /* remove insane chars */
4261 for (i = 0; text[i] != '\0'; i++) {
4262 if (text[i] == '\n' ||
4263 text[i] == '\r') {
4264 text[i] = '\0';
4265 break;
4266 }
4267 }
4268
4269 /* ensure string is printable */
4270 for (i = 0; text[i] != '\0'; i++) {
4271 if (!isprint(text[i])) {
4272 text[i] = '-';
4273 replaced++;
4274 }
4275 }
4276
4277 /* if the string is random junk, ignore the string */
4278 if (replaced > 4)
4279 text[0] = '\0';
4280}
4281
4282#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
4283#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
4284#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
4285#define EDID_OFFSET_DATA_BLOCKS 0x36
4286#define EDID_OFFSET_LAST_BLOCK 0x6c
4287#define EDID_OFFSET_PNPID 0x08
4288#define EDID_OFFSET_SERIAL 0x0c
4289
4290static int
4291edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
4292{
4293 int i;
4294 uint32_t serial_number;
4295
4296 /* check header */
4297 if (length < 128)
4298 return -1;
4299 if (data[0] != 0x00 || data[1] != 0xff)
4300 return -1;
4301
4302 /* decode the PNP ID from three 5 bit words packed into 2 bytes
4303 * /--08--\/--09--\
4304 * 7654321076543210
4305 * |\---/\---/\---/
4306 * R C1 C2 C3 */
4307 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
4308 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
4309 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
4310 edid->pnp_id[3] = '\0';
4311
4312 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
4313 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
4314 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
4315 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
4316 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
4317 if (serial_number > 0)
4318 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
4319
4320 /* parse EDID data */
4321 for (i = EDID_OFFSET_DATA_BLOCKS;
4322 i <= EDID_OFFSET_LAST_BLOCK;
4323 i += 18) {
4324 /* ignore pixel clock data */
4325 if (data[i] != 0)
4326 continue;
4327 if (data[i+2] != 0)
4328 continue;
4329
4330 /* any useful blocks? */
4331 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
4332 edid_parse_string(&data[i+5],
4333 edid->monitor_name);
4334 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
4335 edid_parse_string(&data[i+5],
4336 edid->serial_number);
4337 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
4338 edid_parse_string(&data[i+5],
4339 edid->eisa_id);
4340 }
4341 }
4342 return 0;
4343}
4344
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004345/** Parse monitor make, model and serial from EDID
4346 *
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004347 * \param head The head whose \c drm_edid to fill in.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004348 * \param props The DRM connector properties to get the EDID from.
4349 * \param make[out] The monitor make (PNP ID).
4350 * \param model[out] The monitor model (name).
4351 * \param serial_number[out] The monitor serial number.
4352 *
4353 * Each of \c *make, \c *model and \c *serial_number are set only if the
4354 * information is found in the EDID. The pointers they are set to must not
4355 * be free()'d explicitly, instead they get implicitly freed when the
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004356 * \c drm_head is destroyed.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004357 */
Richard Hughes2b2092a2013-04-24 14:58:02 +01004358static void
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004359find_and_parse_output_edid(struct drm_head *head,
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004360 drmModeObjectPropertiesPtr props,
4361 const char **make,
4362 const char **model,
4363 const char **serial_number)
Richard Hughes2b2092a2013-04-24 14:58:02 +01004364{
4365 drmModePropertyBlobPtr edid_blob = NULL;
Daniel Stone02cf4662017-03-03 16:19:39 +00004366 uint32_t blob_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004367 int rc;
4368
Daniel Stone02cf4662017-03-03 16:19:39 +00004369 blob_id =
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004370 drm_property_get_value(&head->props_conn[WDRM_CONNECTOR_EDID],
Daniel Stone02cf4662017-03-03 16:19:39 +00004371 props, 0);
4372 if (!blob_id)
4373 return;
4374
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004375 edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id);
Richard Hughes2b2092a2013-04-24 14:58:02 +01004376 if (!edid_blob)
4377 return;
4378
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004379 rc = edid_parse(&head->edid,
Richard Hughes2b2092a2013-04-24 14:58:02 +01004380 edid_blob->data,
4381 edid_blob->length);
4382 if (!rc) {
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004383 if (head->edid.pnp_id[0] != '\0')
4384 *make = head->edid.pnp_id;
4385 if (head->edid.monitor_name[0] != '\0')
4386 *model = head->edid.monitor_name;
4387 if (head->edid.serial_number[0] != '\0')
4388 *serial_number = head->edid.serial_number;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004389 }
4390 drmModeFreePropertyBlob(edid_blob);
4391}
4392
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004393static int
4394parse_modeline(const char *s, drmModeModeInfo *mode)
4395{
4396 char hsync[16];
4397 char vsync[16];
4398 float fclock;
4399
Pekka Paalanendc4e3c62017-12-05 15:37:41 +02004400 memset(mode, 0, sizeof *mode);
4401
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004402 mode->type = DRM_MODE_TYPE_USERDEF;
4403 mode->hskew = 0;
4404 mode->vscan = 0;
4405 mode->vrefresh = 0;
4406 mode->flags = 0;
4407
Rob Bradford307e09e2013-07-26 16:29:40 +01004408 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004409 &fclock,
4410 &mode->hdisplay,
4411 &mode->hsync_start,
4412 &mode->hsync_end,
4413 &mode->htotal,
4414 &mode->vdisplay,
4415 &mode->vsync_start,
4416 &mode->vsync_end,
4417 &mode->vtotal, hsync, vsync) != 11)
4418 return -1;
4419
4420 mode->clock = fclock * 1000;
Guido Günther92278e02018-06-26 20:40:08 +02004421 if (strcasecmp(hsync, "+hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004422 mode->flags |= DRM_MODE_FLAG_PHSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02004423 else if (strcasecmp(hsync, "-hsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004424 mode->flags |= DRM_MODE_FLAG_NHSYNC;
4425 else
4426 return -1;
4427
Guido Günther92278e02018-06-26 20:40:08 +02004428 if (strcasecmp(vsync, "+vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004429 mode->flags |= DRM_MODE_FLAG_PVSYNC;
Guido Günther92278e02018-06-26 20:40:08 +02004430 else if (strcasecmp(vsync, "-vsync") == 0)
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004431 mode->flags |= DRM_MODE_FLAG_NVSYNC;
4432 else
4433 return -1;
4434
Emmanuel Gil Peyrota62138b2016-05-02 22:40:11 +01004435 snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
4436 mode->hdisplay, mode->vdisplay, fclock);
4437
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004438 return 0;
4439}
4440
Rob Bradford66bd9f52013-06-25 18:56:42 +01004441static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03004442setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01004443 struct weston_output *output,
4444 const char *s)
4445{
4446 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05004447 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004448 struct udev_seat *seat;
4449
Giulio Camuffo954f1832014-10-11 18:27:30 +03004450 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05004451 if (!seat)
4452 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004453
Derek Foreman0720ea32015-07-15 13:00:35 -05004454 seat->base.output = output;
4455
Derek Foreman1281a362015-07-31 16:55:32 -05004456 pointer = weston_seat_get_pointer(&seat->base);
4457 if (pointer)
4458 weston_pointer_clamp(pointer,
4459 &pointer->x,
4460 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01004461 }
4462}
4463
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004464static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03004465drm_output_attach_head(struct weston_output *output_base,
4466 struct weston_head *head_base)
4467{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004468 struct drm_backend *b = to_drm_backend(output_base->compositor);
4469
Pekka Paalanenc112f002017-08-28 16:27:20 +03004470 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
4471 return -1;
4472
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004473 if (!output_base->enabled)
4474 return 0;
4475
4476 /* XXX: ensure the configuration will work.
4477 * This is actually impossible without major infrastructure
4478 * work. */
4479
4480 /* Need to go through modeset to add connectors. */
4481 /* XXX: Ideally we'd do this per-output, not globally. */
4482 /* XXX: Doing it globally, what guarantees another output's update
4483 * will not clear the flag before this output is updated?
4484 */
4485 b->state_invalid = true;
4486
4487 weston_output_schedule_repaint(output_base);
4488
Pekka Paalanenc112f002017-08-28 16:27:20 +03004489 return 0;
4490}
4491
Pekka Paalanen7f853792017-11-29 14:33:33 +02004492static void
4493drm_output_detach_head(struct weston_output *output_base,
4494 struct weston_head *head_base)
4495{
4496 struct drm_backend *b = to_drm_backend(output_base->compositor);
4497
4498 if (!output_base->enabled)
4499 return;
4500
4501 /* Need to go through modeset to drop connectors that should no longer
4502 * be driven. */
4503 /* XXX: Ideally we'd do this per-output, not globally. */
4504 b->state_invalid = true;
4505
4506 weston_output_schedule_repaint(output_base);
4507}
4508
Pekka Paalanenc112f002017-08-28 16:27:20 +03004509static int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004510parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004511{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004512 int ret = 0;
4513
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004514 if (s == NULL)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004515 *gbm_format = default_value;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004516 else if (strcmp(s, "xrgb8888") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004517 *gbm_format = GBM_FORMAT_XRGB8888;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004518 else if (strcmp(s, "rgb565") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004519 *gbm_format = GBM_FORMAT_RGB565;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004520 else if (strcmp(s, "xrgb2101010") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004521 *gbm_format = GBM_FORMAT_XRGB2101010;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004522 else {
4523 weston_log("fatal: unrecognized pixel format: %s\n", s);
4524 ret = -1;
4525 }
4526
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004527 return ret;
4528}
4529
Pekka Paalanenf005f252017-11-10 16:34:39 +02004530static uint32_t
4531u32distance(uint32_t a, uint32_t b)
4532{
4533 if (a < b)
4534 return b - a;
4535 else
4536 return a - b;
4537}
4538
4539/** Choose equivalent mode
4540 *
4541 * If the two modes are not equivalent, return NULL.
4542 * Otherwise return the mode that is more likely to work in place of both.
4543 *
4544 * None of the fuzzy matching criteria in this function have any justification.
4545 *
4546 * typedef struct _drmModeModeInfo {
4547 * uint32_t clock;
4548 * uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
4549 * uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
4550 *
4551 * uint32_t vrefresh;
4552 *
4553 * uint32_t flags;
4554 * uint32_t type;
4555 * char name[DRM_DISPLAY_MODE_LEN];
4556 * } drmModeModeInfo, *drmModeModeInfoPtr;
4557 */
4558static const drmModeModeInfo *
4559drm_mode_pick_equivalent(const drmModeModeInfo *a, const drmModeModeInfo *b)
4560{
4561 uint32_t refresh_a, refresh_b;
4562
4563 if (a->hdisplay != b->hdisplay || a->vdisplay != b->vdisplay)
4564 return NULL;
4565
4566 if (a->flags != b->flags)
4567 return NULL;
4568
4569 /* kHz */
4570 if (u32distance(a->clock, b->clock) > 500)
4571 return NULL;
4572
4573 refresh_a = drm_refresh_rate_mHz(a);
4574 refresh_b = drm_refresh_rate_mHz(b);
4575 if (u32distance(refresh_a, refresh_b) > 50)
4576 return NULL;
4577
4578 if ((a->type ^ b->type) & DRM_MODE_TYPE_PREFERRED) {
4579 if (a->type & DRM_MODE_TYPE_PREFERRED)
4580 return a;
4581 else
4582 return b;
4583 }
4584
4585 return a;
4586}
4587
4588/* If the given mode info is not already in the list, add it.
4589 * If it is in the list, either keep the existing or replace it,
4590 * depending on which one is "better".
4591 */
4592static int
4593drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
4594{
4595 struct weston_mode *base;
4596 struct drm_mode *mode;
4597 struct drm_backend *backend;
4598 const drmModeModeInfo *chosen = NULL;
4599
4600 assert(info);
4601
4602 wl_list_for_each(base, &output->base.mode_list, link) {
4603 mode = to_drm_mode(base);
4604 chosen = drm_mode_pick_equivalent(&mode->mode_info, info);
4605 if (chosen)
4606 break;
4607 }
4608
4609 if (chosen == info) {
4610 backend = to_drm_backend(output->base.compositor);
4611 drm_output_destroy_mode(backend, mode);
4612 chosen = NULL;
4613 }
4614
4615 if (!chosen) {
4616 mode = drm_output_add_mode(output, info);
4617 if (!mode)
4618 return -1;
4619 }
4620 /* else { the equivalent mode is already in the list } */
4621
4622 return 0;
4623}
4624
Pekka Paalanen4be24852017-09-11 15:01:12 +03004625/** Rewrite the output's mode list
4626 *
4627 * @param output The output.
4628 * @return 0 on success, -1 on failure.
4629 *
4630 * Destroy all existing modes in the list, and reconstruct a new list from
4631 * scratch, based on the currently attached heads.
4632 *
4633 * On failure the output's mode list may contain some modes.
4634 */
4635static int
4636drm_output_update_modelist_from_heads(struct drm_output *output)
4637{
4638 struct drm_backend *backend = to_drm_backend(output->base.compositor);
4639 struct weston_head *head_base;
4640 struct drm_head *head;
Pekka Paalanen4be24852017-09-11 15:01:12 +03004641 int i;
Pekka Paalanenf005f252017-11-10 16:34:39 +02004642 int ret;
Pekka Paalanen4be24852017-09-11 15:01:12 +03004643
4644 assert(!output->base.enabled);
4645
4646 drm_mode_list_destroy(backend, &output->base.mode_list);
4647
Pekka Paalanenf005f252017-11-10 16:34:39 +02004648 wl_list_for_each(head_base, &output->base.head_list, output_link) {
4649 head = to_drm_head(head_base);
4650 for (i = 0; i < head->connector->count_modes; i++) {
4651 ret = drm_output_try_add_mode(output,
4652 &head->connector->modes[i]);
4653 if (ret < 0)
4654 return -1;
4655 }
Pekka Paalanen4be24852017-09-11 15:01:12 +03004656 }
4657
4658 return 0;
4659}
4660
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004661/**
4662 * Choose suitable mode for an output
4663 *
4664 * Find the most suitable mode to use for initial setup (or reconfiguration on
4665 * hotplug etc) for a DRM output.
4666 *
4667 * @param output DRM output to choose mode for
4668 * @param kind Strategy and preference to use when choosing mode
4669 * @param width Desired width for this output
4670 * @param height Desired height for this output
4671 * @param current_mode Mode currently being displayed on this output
4672 * @param modeline Manually-entered mode (may be NULL)
4673 * @returns A mode from the output's mode list, or NULL if none available
4674 */
4675static struct drm_mode *
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004676drm_output_choose_initial_mode(struct drm_backend *backend,
4677 struct drm_output *output,
4678 enum weston_drm_backend_output_mode mode,
Armin Krezović08368132016-09-30 14:11:05 +02004679 const char *modeline,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004680 const drmModeModeInfo *current_mode)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004681{
4682 struct drm_mode *preferred = NULL;
4683 struct drm_mode *current = NULL;
4684 struct drm_mode *configured = NULL;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304685 struct drm_mode *config_fall_back = NULL;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004686 struct drm_mode *best = NULL;
4687 struct drm_mode *drm_mode;
Armin Krezović08368132016-09-30 14:11:05 +02004688 drmModeModeInfo drm_modeline;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004689 int32_t width = 0;
4690 int32_t height = 0;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01004691 uint32_t refresh = 0;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304692 uint32_t aspect_width = 0;
4693 uint32_t aspect_height = 0;
4694 enum weston_mode_aspect_ratio aspect_ratio = WESTON_MODE_PIC_AR_NONE;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01004695 int n;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004696
Armin Krezović08368132016-09-30 14:11:05 +02004697 if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304698 n = sscanf(modeline, "%dx%d@%d %u:%u", &width, &height,
4699 &refresh, &aspect_width, &aspect_height);
4700 if (backend->aspect_ratio_supported && n == 5) {
4701 if (aspect_width == 4 && aspect_height == 3)
4702 aspect_ratio = WESTON_MODE_PIC_AR_4_3;
4703 else if (aspect_width == 16 && aspect_height == 9)
4704 aspect_ratio = WESTON_MODE_PIC_AR_16_9;
4705 else if (aspect_width == 64 && aspect_height == 27)
4706 aspect_ratio = WESTON_MODE_PIC_AR_64_27;
4707 else if (aspect_width == 256 && aspect_height == 135)
4708 aspect_ratio = WESTON_MODE_PIC_AR_256_135;
4709 else
4710 weston_log("Invalid modeline \"%s\" for output %s\n",
4711 modeline, output->base.name);
4712 }
4713 if (n != 2 && n != 3 && n != 5) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004714 width = -1;
4715
Armin Krezović08368132016-09-30 14:11:05 +02004716 if (parse_modeline(modeline, &drm_modeline) == 0) {
4717 configured = drm_output_add_mode(output, &drm_modeline);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004718 if (!configured)
4719 return NULL;
4720 } else {
4721 weston_log("Invalid modeline \"%s\" for output %s\n",
Armin Krezović08368132016-09-30 14:11:05 +02004722 modeline, output->base.name);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004723 }
4724 }
4725 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004726
4727 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004728 if (width == drm_mode->base.width &&
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01004729 height == drm_mode->base.height &&
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304730 (refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) {
4731 if (!backend->aspect_ratio_supported ||
4732 aspect_ratio == drm_mode->base.aspect_ratio)
4733 configured = drm_mode;
4734 else
4735 config_fall_back = drm_mode;
4736 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004737
comic fans7a5c5622016-03-17 14:29:27 +02004738 if (memcmp(current_mode, &drm_mode->mode_info,
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004739 sizeof *current_mode) == 0)
4740 current = drm_mode;
4741
4742 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
4743 preferred = drm_mode;
4744
4745 best = drm_mode;
4746 }
4747
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004748 if (current == NULL && current_mode->clock != 0) {
4749 current = drm_output_add_mode(output, current_mode);
4750 if (!current)
4751 return NULL;
4752 }
4753
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004754 if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004755 configured = current;
4756
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004757 if (configured)
4758 return configured;
4759
Ankit Nautiyala21c3932097-03-19 00:24:57 +05304760 if (config_fall_back)
4761 return config_fall_back;
4762
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004763 if (preferred)
4764 return preferred;
4765
4766 if (current)
4767 return current;
4768
4769 if (best)
4770 return best;
4771
4772 weston_log("no available modes for %s\n", output->base.name);
4773 return NULL;
4774}
4775
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004776static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02004777drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004778{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02004779 int drm_fd = backend->drm.fd;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004780 drmModeEncoder *encoder;
4781 drmModeCrtc *crtc;
4782
4783 /* Get the current mode on the crtc that's currently driving
4784 * this connector. */
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02004785 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004786 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004787 head->inherited_crtc_id = encoder->crtc_id;
4788
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004789 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
4790 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004791
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004792 if (crtc == NULL)
4793 return -1;
4794 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02004795 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004796 drmModeFreeCrtc(crtc);
4797 }
4798
4799 return 0;
4800}
4801
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004802static int
Armin Krezović08368132016-09-30 14:11:05 +02004803drm_output_set_mode(struct weston_output *base,
4804 enum weston_drm_backend_output_mode mode,
4805 const char *modeline)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004806{
Armin Krezović08368132016-09-30 14:11:05 +02004807 struct drm_output *output = to_drm_output(base);
4808 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004809 struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004810
Armin Krezović445b41b2016-10-09 23:48:16 +02004811 struct drm_mode *current;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004812
Pekka Paalanen4be24852017-09-11 15:01:12 +03004813 if (drm_output_update_modelist_from_heads(output) < 0)
4814 return -1;
4815
Pekka Paalanen13d233e2017-09-11 14:06:11 +03004816 current = drm_output_choose_initial_mode(b, output, mode, modeline,
4817 &head->inherited_mode);
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004818 if (!current)
Armin Krezović445b41b2016-10-09 23:48:16 +02004819 return -1;
Armin Krezović08368132016-09-30 14:11:05 +02004820
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004821 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02004822 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04004823
Armin Krezović08368132016-09-30 14:11:05 +02004824 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
4825 output->base.native_mode = output->base.current_mode;
4826 output->base.native_scale = output->base.current_scale;
4827
Armin Krezović08368132016-09-30 14:11:05 +02004828 return 0;
Armin Krezović08368132016-09-30 14:11:05 +02004829}
4830
4831static void
4832drm_output_set_gbm_format(struct weston_output *base,
4833 const char *gbm_format)
4834{
4835 struct drm_output *output = to_drm_output(base);
4836 struct drm_backend *b = to_drm_backend(base->compositor);
4837
4838 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
4839 output->gbm_format = b->gbm_format;
Daniel Stonee2e80132018-01-16 15:37:33 +00004840
4841 /* Without universal planes, we can't discover which formats are
4842 * supported by the primary plane; we just hope that the GBM format
4843 * works. */
4844 if (!b->universal_planes)
4845 output->scanout_plane->formats[0] = output->gbm_format;
Armin Krezović08368132016-09-30 14:11:05 +02004846}
4847
4848static void
4849drm_output_set_seat(struct weston_output *base,
4850 const char *seat)
4851{
4852 struct drm_output *output = to_drm_output(base);
4853 struct drm_backend *b = to_drm_backend(base->compositor);
4854
4855 setup_output_seat_constraint(b, &output->base,
4856 seat ? seat : "");
4857}
4858
4859static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03004860drm_output_init_gamma_size(struct drm_output *output)
4861{
4862 struct drm_backend *backend = to_drm_backend(output->base.compositor);
4863 drmModeCrtc *crtc;
4864
4865 assert(output->base.compositor);
4866 assert(output->crtc_id != 0);
4867 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
4868 if (!crtc)
4869 return -1;
4870
4871 output->base.gamma_size = crtc->gamma_size;
4872
4873 drmModeFreeCrtc(crtc);
4874
4875 return 0;
4876}
4877
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004878static uint32_t
4879drm_head_get_possible_crtcs_mask(struct drm_head *head)
4880{
4881 uint32_t possible_crtcs = 0;
4882 drmModeEncoder *encoder;
4883 int i;
4884
4885 for (i = 0; i < head->connector->count_encoders; i++) {
4886 encoder = drmModeGetEncoder(head->backend->drm.fd,
4887 head->connector->encoders[i]);
4888 if (!encoder)
4889 continue;
4890
4891 possible_crtcs |= encoder->possible_crtcs;
4892 drmModeFreeEncoder(encoder);
4893 }
4894
4895 return possible_crtcs;
4896}
4897
4898static int
4899drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
4900{
4901 int i;
4902
4903 for (i = 0; i < resources->count_crtcs; i++) {
4904 if (resources->crtcs[i] == crtc_id)
4905 return i;
4906 }
4907
4908 assert(0 && "unknown crtc id");
4909 return -1;
4910}
4911
4912/** Pick a CRTC that might be able to drive all attached connectors
4913 *
4914 * @param output The output whose attached heads to include.
4915 * @param resources The DRM KMS resources.
4916 * @return CRTC index, or -1 on failure or not found.
4917 */
4918static int
4919drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
4920{
4921 struct drm_backend *backend;
4922 struct weston_head *base;
4923 struct drm_head *head;
4924 uint32_t possible_crtcs = 0xffffffff;
4925 int existing_crtc[32];
4926 unsigned j, n = 0;
4927 uint32_t crtc_id;
4928 int best_crtc_index = -1;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02004929 int fallback_crtc_index = -1;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004930 int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02004931 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004932
4933 backend = to_drm_backend(output->base.compositor);
4934
4935 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
4936 * because it is more often set wrong than not in the kernel. */
4937
4938 /* Accumulate a mask of possible crtcs and find existing routings. */
4939 wl_list_for_each(base, &output->base.head_list, output_link) {
4940 head = to_drm_head(base);
4941
4942 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
4943
4944 crtc_id = head->inherited_crtc_id;
4945 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
4946 existing_crtc[n++] = drm_crtc_get_index(resources,
4947 crtc_id);
4948 }
4949
4950 /* Find a crtc that could drive each connector individually at least,
4951 * and prefer existing routings. */
4952 for (i = 0; i < resources->count_crtcs; i++) {
4953 crtc_id = resources->crtcs[i];
4954
4955 /* Could the crtc not drive each connector? */
4956 if (!(possible_crtcs & (1 << i)))
4957 continue;
4958
4959 /* Is the crtc already in use? */
4960 if (drm_output_find_by_crtc(backend, crtc_id))
4961 continue;
4962
4963 /* Try to preserve the existing CRTC -> connector routing;
4964 * it makes initialisation faster, and also since we have a
4965 * very dumb picking algorithm, may preserve a better
4966 * choice. */
4967 for (j = 0; j < n; j++) {
4968 if (existing_crtc[j] == i)
4969 return i;
4970 }
4971
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02004972 /* Check if any other head had existing routing to this CRTC.
4973 * If they did, this is not the best CRTC as it might be needed
4974 * for another output we haven't enabled yet. */
4975 match = false;
4976 wl_list_for_each(base, &backend->compositor->head_list,
4977 compositor_link) {
4978 head = to_drm_head(base);
4979
4980 if (head->base.output == &output->base)
4981 continue;
4982
4983 if (weston_head_is_enabled(&head->base))
4984 continue;
4985
4986 if (head->inherited_crtc_id == crtc_id) {
4987 match = true;
4988 break;
4989 }
4990 }
4991 if (!match)
4992 best_crtc_index = i;
4993
4994 fallback_crtc_index = i;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004995 }
4996
4997 if (best_crtc_index != -1)
4998 return best_crtc_index;
4999
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02005000 if (fallback_crtc_index != -1)
5001 return fallback_crtc_index;
5002
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005003 /* Likely possible_crtcs was empty due to asking for clones,
5004 * but since the DRM documentation says the kernel lies, let's
5005 * pick one crtc anyway. Trial and error is the only way to
5006 * be sure if something doesn't work. */
5007
5008 /* First pick any existing assignment. */
5009 for (j = 0; j < n; j++) {
5010 crtc_id = resources->crtcs[existing_crtc[j]];
5011 if (!drm_output_find_by_crtc(backend, crtc_id))
5012 return existing_crtc[j];
5013 }
5014
5015 /* Otherwise pick any available crtc. */
5016 for (i = 0; i < resources->count_crtcs; i++) {
5017 crtc_id = resources->crtcs[i];
5018
5019 if (!drm_output_find_by_crtc(backend, crtc_id))
5020 return i;
5021 }
5022
5023 return -1;
5024}
5025
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005026/** Allocate a CRTC for the output
5027 *
5028 * @param output The output with no allocated CRTC.
5029 * @param resources DRM KMS resources.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005030 * @return 0 on success, -1 on failure.
5031 *
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005032 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005033 * for the output, and loads the CRTC properties.
5034 *
5035 * Populates the cursor and scanout planes.
5036 *
5037 * On failure, the output remains without a CRTC.
5038 */
5039static int
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005040drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005041{
5042 struct drm_backend *b = to_drm_backend(output->base.compositor);
5043 drmModeObjectPropertiesPtr props;
5044 int i;
5045
5046 assert(output->crtc_id == 0);
5047
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005048 i = drm_output_pick_crtc(output, resources);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005049 if (i < 0) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005050 weston_log("Output '%s': No available CRTCs.\n",
5051 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005052 return -1;
5053 }
5054
5055 output->crtc_id = resources->crtcs[i];
5056 output->pipe = i;
5057
5058 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
5059 DRM_MODE_OBJECT_CRTC);
5060 if (!props) {
5061 weston_log("failed to get CRTC properties\n");
5062 goto err_crtc;
5063 }
5064 drm_property_info_populate(b, crtc_props, output->props_crtc,
5065 WDRM_CRTC__COUNT, props);
5066 drmModeFreeObjectProperties(props);
5067
5068 output->scanout_plane =
5069 drm_output_find_special_plane(b, output,
5070 WDRM_PLANE_TYPE_PRIMARY);
5071 if (!output->scanout_plane) {
5072 weston_log("Failed to find primary plane for output %s\n",
5073 output->base.name);
5074 goto err_crtc;
5075 }
5076
5077 /* Failing to find a cursor plane is not fatal, as we'll fall back
5078 * to software cursor. */
5079 output->cursor_plane =
5080 drm_output_find_special_plane(b, output,
5081 WDRM_PLANE_TYPE_CURSOR);
5082
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005083 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
5084
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005085 return 0;
5086
5087err_crtc:
5088 output->crtc_id = 0;
5089 output->pipe = 0;
5090
5091 return -1;
5092}
5093
5094/** Free the CRTC from the output
5095 *
5096 * @param output The output whose CRTC to deallocate.
5097 *
5098 * The CRTC reserved for the given output becomes free to use again.
5099 */
5100static void
5101drm_output_fini_crtc(struct drm_output *output)
5102{
5103 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005104 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005105
5106 if (!b->universal_planes && !b->shutting_down) {
5107 /* With universal planes, the 'special' planes are allocated at
5108 * startup, freed at shutdown, and live on the plane list in
5109 * between. We want the planes to continue to exist and be freed
5110 * up for other outputs.
5111 *
5112 * Without universal planes, our special planes are
5113 * pseudo-planes allocated at output creation, freed at output
5114 * destruction, and not usable by other outputs.
5115 *
5116 * On the other hand, if the compositor is already shutting down,
5117 * the plane has already been destroyed.
5118 */
5119 if (output->cursor_plane)
5120 drm_plane_destroy(output->cursor_plane);
5121 if (output->scanout_plane)
5122 drm_plane_destroy(output->scanout_plane);
5123 }
5124
5125 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005126
5127 assert(output->crtc_id != 0);
5128
5129 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
5130 *unused = output->crtc_id;
5131
5132 /* Force resetting unused CRTCs */
5133 b->state_invalid = true;
5134
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005135 output->crtc_id = 0;
5136 output->cursor_plane = NULL;
5137 output->scanout_plane = NULL;
5138}
5139
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005140static void
5141drm_output_print_modes(struct drm_output *output)
5142{
5143 struct weston_mode *m;
5144 struct drm_mode *dm;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305145 const char *aspect_ratio;
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005146
5147 wl_list_for_each(m, &output->base.mode_list, link) {
5148 dm = to_drm_mode(m);
5149
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305150 aspect_ratio = aspect_ratio_to_string(m->aspect_ratio);
5151 weston_log_continue(STAMP_SPACE "%dx%d@%.1f%s%s%s, %.1f MHz\n",
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005152 m->width, m->height, m->refresh / 1000.0,
Ankit Nautiyala21c3932097-03-19 00:24:57 +05305153 aspect_ratio,
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005154 m->flags & WL_OUTPUT_MODE_PREFERRED ?
5155 ", preferred" : "",
5156 m->flags & WL_OUTPUT_MODE_CURRENT ?
5157 ", current" : "",
5158 dm->mode_info.clock / 1000.0);
5159 }
5160}
5161
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03005162static int
Armin Krezović08368132016-09-30 14:11:05 +02005163drm_output_enable(struct weston_output *base)
5164{
5165 struct drm_output *output = to_drm_output(base);
5166 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005167 drmModeRes *resources;
5168 int ret;
5169
5170 resources = drmModeGetResources(b->drm.fd);
5171 if (!resources) {
5172 weston_log("drmModeGetResources failed\n");
5173 return -1;
5174 }
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005175 ret = drm_output_init_crtc(output, resources);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005176 drmModeFreeResources(resources);
5177 if (ret < 0)
5178 return -1;
5179
5180 if (drm_output_init_gamma_size(output) < 0)
5181 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02005182
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005183 if (b->pageflip_timeout)
5184 drm_output_pageflip_timer_create(output);
5185
Giulio Camuffo954f1832014-10-11 18:27:30 +03005186 if (b->use_pixman) {
5187 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005188 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005189 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005190 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03005191 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005192 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005193 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04005194 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04005195
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02005196 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005197
Jonas Ådahle5a12252013-04-05 23:07:11 +02005198 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05005199 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05005200 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005201 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08005202 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01005203 output->base.set_gamma = drm_output_set_gamma;
5204
Daniel Stone2ba17f42015-05-19 20:02:41 +01005205 if (output->cursor_plane)
5206 weston_compositor_stack_plane(b->compositor,
5207 &output->cursor_plane->base,
5208 NULL);
5209 else
5210 b->cursors_are_broken = 1;
5211
Daniel Stonee2e80132018-01-16 15:37:33 +00005212 weston_compositor_stack_plane(b->compositor,
5213 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03005214 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02005215
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005216 weston_log("Output %s (crtc %d) video modes:\n",
5217 output->base.name, output->crtc_id);
5218 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04005219
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005220 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01005221
Daniel Stone02cf4662017-03-03 16:19:39 +00005222err:
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005223 drm_output_fini_crtc(output);
5224
David Herrmann0f0d54e2011-12-08 17:05:45 +01005225 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005226}
5227
Jesse Barnes58ef3792012-02-23 09:45:49 -05005228static void
Armin Krezović08368132016-09-30 14:11:05 +02005229drm_output_deinit(struct weston_output *base)
5230{
5231 struct drm_output *output = to_drm_output(base);
5232 struct drm_backend *b = to_drm_backend(base->compositor);
5233
Daniel Stone3e661f72016-11-04 17:24:06 +00005234 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02005235 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00005236 else
5237 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02005238
Daniel Stone2ba17f42015-05-19 20:02:41 +01005239 /* Since our planes are no longer in use anywhere, remove their base
5240 * weston_plane's link from the plane stacking list, unless we're
5241 * shutting down, in which case the plane has already been
5242 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00005243 if (!b->shutting_down) {
5244 wl_list_remove(&output->scanout_plane->base.link);
5245 wl_list_init(&output->scanout_plane->base.link);
5246
5247 if (output->cursor_plane) {
5248 wl_list_remove(&output->cursor_plane->base.link);
5249 wl_list_init(&output->cursor_plane->base.link);
5250 /* Turn off hardware cursor */
5251 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
5252 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01005253 }
Daniel Stone087ddf02017-02-14 17:51:30 +00005254
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005255 drm_output_fini_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02005256}
5257
5258static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03005259drm_head_destroy(struct drm_head *head);
5260
5261static void
Armin Krezović08368132016-09-30 14:11:05 +02005262drm_output_destroy(struct weston_output *base)
5263{
5264 struct drm_output *output = to_drm_output(base);
5265 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02005266
Daniel Stone598ee9d2016-11-16 11:55:20 +00005267 if (output->page_flip_pending || output->vblank_pending ||
5268 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005269 output->destroy_pending = 1;
5270 weston_log("destroy output while page flip pending\n");
5271 return;
5272 }
5273
5274 if (output->base.enabled)
5275 drm_output_deinit(&output->base);
5276
Pekka Paalanen383b3af2017-09-11 14:40:48 +03005277 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02005278
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005279 if (output->pageflip_timer)
5280 wl_event_source_remove(output->pageflip_timer);
5281
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03005282 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02005283
Daniel Stone7b2ddac2016-11-11 19:11:49 +00005284 assert(!output->state_last);
5285 drm_output_state_free(output->state_cur);
5286
Armin Krezović08368132016-09-30 14:11:05 +02005287 free(output);
5288}
5289
5290static int
5291drm_output_disable(struct weston_output *base)
5292{
5293 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02005294
Daniel Stone598ee9d2016-11-16 11:55:20 +00005295 if (output->page_flip_pending || output->vblank_pending ||
5296 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005297 output->disable_pending = 1;
5298 return -1;
5299 }
5300
Daniel Stonea08512f2016-11-08 17:46:10 +00005301 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00005302
Armin Krezović08368132016-09-30 14:11:05 +02005303 if (output->base.enabled)
5304 drm_output_deinit(&output->base);
5305
5306 output->disable_pending = 0;
5307
Armin Krezović08368132016-09-30 14:11:05 +02005308 return 0;
5309}
5310
5311/**
Daniel Stone087ddf02017-02-14 17:51:30 +00005312 * Update the list of unused connectors and CRTCs
5313 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03005314 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00005315 *
5316 * @param b Weston backend structure
5317 * @param resources DRM resources for this device
5318 */
5319static void
5320drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
5321{
5322 int i;
5323
Daniel Stone087ddf02017-02-14 17:51:30 +00005324 wl_array_release(&b->unused_crtcs);
5325 wl_array_init(&b->unused_crtcs);
5326
5327 for (i = 0; i < resources->count_crtcs; i++) {
5328 struct drm_output *output;
5329 uint32_t *crtc_id;
5330
5331 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
5332 if (output && output->base.enabled)
5333 continue;
5334
5335 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
5336 *crtc_id = resources->crtcs[i];
5337 }
5338}
5339
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005340/** Replace connector data and monitor information
5341 *
5342 * @param head The head to update.
5343 * @param connector The connector data to be owned by the head, must match
5344 * the head's connector ID.
5345 * @return 0 on success, -1 on failure.
5346 *
5347 * Takes ownership of @c connector on success, not on failure.
5348 *
5349 * May schedule a heads changed call.
5350 */
5351static int
5352drm_head_assign_connector_info(struct drm_head *head,
5353 drmModeConnector *connector)
5354{
5355 drmModeObjectProperties *props;
5356 const char *make = "unknown";
5357 const char *model = "unknown";
5358 const char *serial_number = "unknown";
5359
5360 assert(connector);
5361 assert(head->connector_id == connector->connector_id);
5362
5363 props = drmModeObjectGetProperties(head->backend->drm.fd,
5364 head->connector_id,
5365 DRM_MODE_OBJECT_CONNECTOR);
5366 if (!props) {
5367 weston_log("Error: failed to get connector '%s' properties\n",
5368 head->base.name);
5369 return -1;
5370 }
5371
5372 if (head->connector)
5373 drmModeFreeConnector(head->connector);
5374 head->connector = connector;
5375
5376 drm_property_info_populate(head->backend, connector_props,
5377 head->props_conn,
5378 WDRM_CONNECTOR__COUNT, props);
5379 find_and_parse_output_edid(head, props, &make, &model, &serial_number);
5380 weston_head_set_monitor_strings(&head->base, make, model, serial_number);
5381 weston_head_set_subpixel(&head->base,
5382 drm_subpixel_to_wayland(head->connector->subpixel));
5383
5384 weston_head_set_physical_size(&head->base, head->connector->mmWidth,
5385 head->connector->mmHeight);
5386
5387 drmModeFreeObjectProperties(props);
5388
5389 /* Unknown connection status is assumed disconnected. */
5390 weston_head_set_connection_status(&head->base,
5391 head->connector->connection == DRM_MODE_CONNECTED);
5392
5393 return 0;
5394}
5395
Pekka Paalanen456dc732017-11-09 15:10:11 +02005396static void
5397drm_head_log_info(struct drm_head *head, const char *msg)
5398{
5399 if (head->base.connected) {
5400 weston_log("DRM: head '%s' %s, connector %d is connected, "
5401 "EDID make '%s', model '%s', serial '%s'\n",
5402 head->base.name, msg, head->connector_id,
5403 head->base.make, head->base.model,
5404 head->base.serial_number ?: "");
5405 } else {
5406 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
5407 head->base.name, msg, head->connector_id);
5408 }
5409}
5410
Pekka Paalanend2e62422017-09-08 15:48:07 +03005411/** Update connector and monitor information
5412 *
5413 * @param head The head to update.
5414 *
5415 * Re-reads the DRM property lists for the connector and updates monitor
5416 * information and connection status. This may schedule a heads changed call
5417 * to the user.
5418 */
5419static void
5420drm_head_update_info(struct drm_head *head)
5421{
5422 drmModeConnector *connector;
5423
5424 connector = drmModeGetConnector(head->backend->drm.fd,
5425 head->connector_id);
5426 if (!connector) {
5427 weston_log("DRM: getting connector info for '%s' failed.\n",
5428 head->base.name);
5429 return;
5430 }
5431
5432 if (drm_head_assign_connector_info(head, connector) < 0)
5433 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005434
5435 if (head->base.device_changed)
5436 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03005437}
5438
Daniel Stone087ddf02017-02-14 17:51:30 +00005439/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03005440 * Create a Weston head for a connector
5441 *
5442 * Given a DRM connector, create a matching drm_head structure and add it
5443 * to Weston's head list.
5444 *
5445 * @param b Weston backend structure
5446 * @param connector_id DRM connector ID for the head
5447 * @param drm_device udev device pointer
5448 * @returns The new head, or NULL on failure.
5449 */
5450static struct drm_head *
5451drm_head_create(struct drm_backend *backend, uint32_t connector_id,
5452 struct udev_device *drm_device)
5453{
5454 struct drm_head *head;
5455 drmModeConnector *connector;
5456 char *name;
5457
5458 head = zalloc(sizeof *head);
5459 if (!head)
5460 return NULL;
5461
5462 connector = drmModeGetConnector(backend->drm.fd, connector_id);
5463 if (!connector)
5464 goto err_alloc;
5465
5466 name = make_connector_name(connector);
5467 if (!name)
5468 goto err_alloc;
5469
5470 weston_head_init(&head->base, name);
5471 free(name);
5472
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005473 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03005474 head->backend = backend;
5475
Pekka Paalanence724242017-09-04 12:21:24 +03005476 head->backlight = backlight_init(drm_device, connector->connector_type);
5477
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005478 if (drm_head_assign_connector_info(head, connector) < 0)
5479 goto err_init;
5480
5481 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
5482 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
5483 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03005484
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005485 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005486 weston_log("Failed to retrieve current mode from connector %d.\n",
5487 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02005488 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005489 }
5490
Pekka Paalanenc112f002017-08-28 16:27:20 +03005491 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005492 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03005493
5494 return head;
5495
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005496err_init:
5497 weston_head_release(&head->base);
5498
Pekka Paalanenc112f002017-08-28 16:27:20 +03005499err_alloc:
5500 if (connector)
5501 drmModeFreeConnector(connector);
5502
5503 free(head);
5504
5505 return NULL;
5506}
5507
5508static void
5509drm_head_destroy(struct drm_head *head)
5510{
5511 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03005512
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005513 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
5514 drmModeFreeConnector(head->connector);
5515
Pekka Paalanence724242017-09-04 12:21:24 +03005516 if (head->backlight)
5517 backlight_destroy(head->backlight);
5518
Pekka Paalanenc112f002017-08-28 16:27:20 +03005519 free(head);
5520}
5521
5522/**
Armin Krezović08368132016-09-30 14:11:05 +02005523 * Create a Weston output structure
5524 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03005525 * Create an "empty" drm_output. This is the implementation of
5526 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02005527 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03005528 * Creating an output is usually followed by drm_output_attach_head()
5529 * and drm_output_enable() to make use of it.
5530 *
5531 * @param compositor The compositor instance.
5532 * @param name Name for the new output.
5533 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02005534 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03005535static struct weston_output *
5536drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02005537{
Pekka Paalanend2e62422017-09-08 15:48:07 +03005538 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02005539 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02005540
Armin Krezović08368132016-09-30 14:11:05 +02005541 output = zalloc(sizeof *output);
5542 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03005543 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02005544
Pekka Paalanend2e62422017-09-08 15:48:07 +03005545 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005546
Armin Krezović08368132016-09-30 14:11:05 +02005547 output->base.enable = drm_output_enable;
5548 output->base.destroy = drm_output_destroy;
5549 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03005550 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02005551 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02005552
5553 output->destroy_pending = 0;
5554 output->disable_pending = 0;
Armin Krezović08368132016-09-30 14:11:05 +02005555
Pekka Paalanen01f60212017-03-24 15:39:24 +02005556 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03005557
Armin Krezović08368132016-09-30 14:11:05 +02005558 weston_compositor_add_pending_output(&output->base, b->compositor);
5559
Pekka Paalanend2e62422017-09-08 15:48:07 +03005560 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02005561}
5562
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005563static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03005564drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005565{
Pekka Paalanend2e62422017-09-08 15:48:07 +03005566 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005567 drmModeRes *resources;
5568 int i;
5569
Giulio Camuffo954f1832014-10-11 18:27:30 +03005570 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005571 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02005572 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005573 return -1;
5574 }
5575
Giulio Camuffo954f1832014-10-11 18:27:30 +03005576 b->min_width = resources->min_width;
5577 b->max_width = resources->max_width;
5578 b->min_height = resources->min_height;
5579 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05005580
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005581 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005582 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00005583
Pekka Paalanend2e62422017-09-08 15:48:07 +03005584 head = drm_head_create(b, connector_id, drm_device);
5585 if (!head) {
5586 weston_log("DRM: failed to create head for connector %d.\n",
5587 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02005588 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005589 }
5590
Daniel Stone087ddf02017-02-14 17:51:30 +00005591 drm_backend_update_unused_outputs(b, resources);
5592
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005593 drmModeFreeResources(resources);
5594
5595 return 0;
5596}
5597
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005598static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03005599drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005600{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005601 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03005602 struct weston_head *base, *next;
5603 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005604 int i;
5605
Giulio Camuffo954f1832014-10-11 18:27:30 +03005606 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005607 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02005608 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005609 return;
5610 }
5611
Pekka Paalanend2e62422017-09-08 15:48:07 +03005612 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005613 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00005614 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02005615
Pekka Paalanend2e62422017-09-08 15:48:07 +03005616 head = drm_head_find_by_connector(b, connector_id);
5617 if (head) {
5618 drm_head_update_info(head);
5619 } else {
5620 head = drm_head_create(b, connector_id, drm_device);
5621 if (!head)
5622 weston_log("DRM: failed to create head for hot-added connector %d.\n",
5623 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01005624 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005625 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005626
Pekka Paalanend2e62422017-09-08 15:48:07 +03005627 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03005628 wl_list_for_each_safe(base, next,
5629 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005630 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005631
Pekka Paalanena0a37462017-08-31 15:41:57 +03005632 head = to_drm_head(base);
5633
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005634 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005635 if (resources->connectors[i] == head->connector_id) {
5636 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005637 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005638 }
5639 }
Armin Krezović08368132016-09-30 14:11:05 +02005640
Pekka Paalanend2e62422017-09-08 15:48:07 +03005641 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005642 continue;
5643
Pekka Paalanend2e62422017-09-08 15:48:07 +03005644 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
5645 head->base.name, head->connector_id);
5646 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005647 }
5648
Daniel Stone087ddf02017-02-14 17:51:30 +00005649 drm_backend_update_unused_outputs(b, resources);
5650
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005651 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005652}
5653
5654static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03005655udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005656{
David Herrmannd7488c22012-03-11 20:05:21 +01005657 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01005658 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01005659
5660 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005661 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01005662 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02005663
David Herrmann6ac52db2012-03-11 20:05:22 +01005664 val = udev_device_get_property_value(device, "HOTPLUG");
5665 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005666 return 0;
5667
David Herrmann6ac52db2012-03-11 20:05:22 +01005668 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005669}
5670
Kristian Høgsbergb1868472011-04-22 12:27:57 -04005671static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005672udev_drm_event(int fd, uint32_t mask, void *data)
5673{
Giulio Camuffo954f1832014-10-11 18:27:30 +03005674 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005675 struct udev_device *event;
5676
Giulio Camuffo954f1832014-10-11 18:27:30 +03005677 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02005678
Giulio Camuffo954f1832014-10-11 18:27:30 +03005679 if (udev_event_is_hotplug(b, event))
Pekka Paalanend2e62422017-09-08 15:48:07 +03005680 drm_backend_update_heads(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005681
5682 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04005683
5684 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005685}
5686
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005687static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005688drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005689{
Armin Krezović545dba62016-08-05 15:54:18 +02005690 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03005691 struct weston_head *base, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005692
Giulio Camuffo954f1832014-10-11 18:27:30 +03005693 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02005694
Giulio Camuffo954f1832014-10-11 18:27:30 +03005695 wl_event_source_remove(b->udev_drm_source);
5696 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02005697
Daniel Stoneb57c6a02017-10-05 16:27:21 +01005698 b->shutting_down = true;
5699
Giulio Camuffo954f1832014-10-11 18:27:30 +03005700 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04005701
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03005702 weston_compositor_shutdown(ec);
5703
Pekka Paalanenc112f002017-08-28 16:27:20 +03005704 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
5705 drm_head_destroy(to_drm_head(base));
5706
Giulio Camuffo954f1832014-10-11 18:27:30 +03005707 if (b->gbm)
5708 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005709
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02005710 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03005711 udev_unref(b->udev);
5712
Giulio Camuffo954f1832014-10-11 18:27:30 +03005713 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005714
Daniel Stone087ddf02017-02-14 17:51:30 +00005715 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00005716
Giulio Camuffo954f1832014-10-11 18:27:30 +03005717 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02005718 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005719 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005720}
5721
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005722static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005723session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005724{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005725 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02005726 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01005727 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04005728 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005729
Giulio Camuffo954f1832014-10-11 18:27:30 +03005730 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005731 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00005732 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005733 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00005734 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03005735 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005736 } else {
5737 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03005738 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04005739
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01005740 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04005741
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05005742 /* If we have a repaint scheduled (either from a
5743 * pending pageflip or the idle handler), make sure we
5744 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01005745 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05005746 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05005747 * back, we schedule a repaint, which will process
5748 * pending frame callbacks. */
5749
Giulio Camuffo954f1832014-10-11 18:27:30 +03005750 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00005751 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01005752 if (output->cursor_plane)
5753 drmModeSetCursor(b->drm.fd, output->crtc_id,
5754 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05005755 }
5756
Giulio Camuffo954f1832014-10-11 18:27:30 +03005757 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04005758 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05005759
Daniel Stone085d2b92015-05-21 00:00:57 +01005760 wl_list_for_each(plane, &b->plane_list, link) {
5761 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
5762 continue;
5763
Giulio Camuffo954f1832014-10-11 18:27:30 +03005764 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01005765 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04005766 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05005767 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01005768 }
5769 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005770}
5771
Daniel Stoneefa504f2016-12-19 16:48:20 +00005772/**
5773 * Determines whether or not a device is capable of modesetting. If successful,
5774 * sets b->drm.fd and b->drm.filename to the opened device.
5775 */
5776static bool
5777drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
5778{
5779 const char *filename = udev_device_get_devnode(device);
5780 const char *sysnum = udev_device_get_sysnum(device);
5781 drmModeRes *res;
5782 int id, fd;
5783
5784 if (!filename)
5785 return false;
5786
5787 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
5788 if (fd < 0)
5789 return false;
5790
5791 res = drmModeGetResources(fd);
5792 if (!res)
5793 goto out_fd;
5794
5795 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
5796 res->count_encoders <= 0)
5797 goto out_res;
5798
5799 if (sysnum)
5800 id = atoi(sysnum);
5801 if (!sysnum || id < 0) {
5802 weston_log("couldn't get sysnum for device %s\n", filename);
5803 goto out_res;
5804 }
5805
5806 /* We can be called successfully on multiple devices; if we have,
5807 * clean up old entries. */
5808 if (b->drm.fd >= 0)
5809 weston_launcher_close(b->compositor->launcher, b->drm.fd);
5810 free(b->drm.filename);
5811
5812 b->drm.fd = fd;
5813 b->drm.id = id;
5814 b->drm.filename = strdup(filename);
5815
Sergi Granellceb59812017-03-28 12:44:04 +02005816 drmModeFreeResources(res);
5817
Daniel Stoneefa504f2016-12-19 16:48:20 +00005818 return true;
5819
5820out_res:
5821 drmModeFreeResources(res);
5822out_fd:
5823 weston_launcher_close(b->compositor->launcher, fd);
5824 return false;
5825}
5826
David Herrmann0af066f2012-10-29 19:21:16 +01005827/*
5828 * Find primary GPU
5829 * Some systems may have multiple DRM devices attached to a single seat. This
5830 * function loops over all devices and tries to find a PCI device with the
5831 * boot_vga sysfs attribute set to 1.
5832 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00005833 * Devices are also vetted to make sure they are are capable of modesetting,
5834 * rather than pure render nodes (GPU with no display), or pure
5835 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01005836 */
5837static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03005838find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01005839{
5840 struct udev_enumerate *e;
5841 struct udev_list_entry *entry;
5842 const char *path, *device_seat, *id;
5843 struct udev_device *device, *drm_device, *pci;
5844
Giulio Camuffo954f1832014-10-11 18:27:30 +03005845 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01005846 udev_enumerate_add_match_subsystem(e, "drm");
5847 udev_enumerate_add_match_sysname(e, "card[0-9]*");
5848
5849 udev_enumerate_scan_devices(e);
5850 drm_device = NULL;
5851 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00005852 bool is_boot_vga = false;
5853
David Herrmann0af066f2012-10-29 19:21:16 +01005854 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005855 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01005856 if (!device)
5857 continue;
5858 device_seat = udev_device_get_property_value(device, "ID_SEAT");
5859 if (!device_seat)
5860 device_seat = default_seat;
5861 if (strcmp(device_seat, seat)) {
5862 udev_device_unref(device);
5863 continue;
5864 }
5865
5866 pci = udev_device_get_parent_with_subsystem_devtype(device,
5867 "pci", NULL);
5868 if (pci) {
5869 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00005870 if (id && !strcmp(id, "1"))
5871 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01005872 }
5873
Daniel Stoneefa504f2016-12-19 16:48:20 +00005874 /* If we already have a modesetting-capable device, and this
5875 * device isn't our boot-VGA device, we aren't going to use
5876 * it. */
5877 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01005878 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00005879 continue;
5880 }
5881
5882 /* Make sure this device is actually capable of modesetting;
5883 * if this call succeeds, b->drm.{fd,filename} will be set,
5884 * and any old values freed. */
5885 if (!drm_device_is_kms(b, device)) {
5886 udev_device_unref(device);
5887 continue;
5888 }
5889
5890 /* There can only be one boot_vga device, and we try to use it
5891 * at all costs. */
5892 if (is_boot_vga) {
5893 if (drm_device)
5894 udev_device_unref(drm_device);
5895 drm_device = device;
5896 break;
5897 }
5898
5899 /* Per the (!is_boot_vga && drm_device) test above, we only
5900 * trump existing saved devices with boot-VGA devices, so if
5901 * we end up here, this must be the first device we've seen. */
5902 assert(!drm_device);
5903 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01005904 }
5905
Daniel Stoneefa504f2016-12-19 16:48:20 +00005906 /* If we're returning a device to use, we must have an open FD for
5907 * it. */
5908 assert(!!drm_device == (b->drm.fd >= 0));
5909
David Herrmann0af066f2012-10-29 19:21:16 +01005910 udev_enumerate_unref(e);
5911 return drm_device;
5912}
5913
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03005914static struct udev_device *
5915open_specific_drm_device(struct drm_backend *b, const char *name)
5916{
5917 struct udev_device *device;
5918
5919 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
5920 if (!device) {
5921 weston_log("ERROR: could not open DRM device '%s'\n", name);
5922 return NULL;
5923 }
5924
5925 if (!drm_device_is_kms(b, device)) {
5926 udev_device_unref(device);
5927 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
5928 return NULL;
5929 }
5930
5931 /* If we're returning a device to use, we must have an open FD for
5932 * it. */
5933 assert(b->drm.fd >= 0);
5934
5935 return device;
5936}
5937
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02005938static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02005939planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
5940 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02005941{
Giulio Camuffo954f1832014-10-11 18:27:30 +03005942 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02005943
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02005944 switch (key) {
5945 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005946 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02005947 break;
5948 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005949 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02005950 break;
5951 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005952 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02005953 break;
5954 default:
5955 break;
5956 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02005957}
5958
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07005959#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005960static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03005961recorder_destroy(struct drm_output *output)
5962{
5963 vaapi_recorder_destroy(output->recorder);
5964 output->recorder = NULL;
5965
5966 output->base.disable_planes--;
5967
5968 wl_list_remove(&output->recorder_frame_listener.link);
5969 weston_log("[libva recorder] done\n");
5970}
5971
5972static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005973recorder_frame_notify(struct wl_listener *listener, void *data)
5974{
5975 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03005976 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005977 int fd, ret;
5978
5979 output = container_of(listener, struct drm_output,
5980 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02005981 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005982
5983 if (!output->recorder)
5984 return;
5985
Daniel Stonee2e80132018-01-16 15:37:33 +00005986 ret = drmPrimeHandleToFD(b->drm.fd,
5987 output->scanout_plane->state_cur->fb->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005988 DRM_CLOEXEC, &fd);
5989 if (ret) {
5990 weston_log("[libva recorder] "
5991 "failed to create prime fd for front buffer\n");
5992 return;
5993 }
5994
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03005995 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stonee2e80132018-01-16 15:37:33 +00005996 output->scanout_plane->state_cur->fb->stride);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03005997 if (ret < 0) {
5998 weston_log("[libva recorder] aborted: %m\n");
5999 recorder_destroy(output);
6000 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006001}
6002
6003static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03006004create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006005 const char *filename)
6006{
6007 int fd;
6008 drm_magic_t magic;
6009
Giulio Camuffo954f1832014-10-11 18:27:30 +03006010 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006011 if (fd < 0)
6012 return NULL;
6013
6014 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006015 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006016
6017 return vaapi_recorder_create(fd, width, height, filename);
6018}
6019
6020static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006021recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6022 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006023{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006024 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006025 struct drm_output *output;
6026 int width, height;
6027
Giulio Camuffo954f1832014-10-11 18:27:30 +03006028 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006029 struct drm_output, base.link);
6030
6031 if (!output->recorder) {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01006032 if (output->gbm_format != GBM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03006033 weston_log("failed to start vaapi recorder: "
6034 "output format not supported\n");
6035 return;
6036 }
6037
Hardeningff39efa2013-09-18 23:56:35 +02006038 width = output->base.current_mode->width;
6039 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006040
6041 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03006042 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006043 if (!output->recorder) {
6044 weston_log("failed to create vaapi recorder\n");
6045 return;
6046 }
6047
6048 output->base.disable_planes++;
6049
6050 output->recorder_frame_listener.notify = recorder_frame_notify;
6051 wl_signal_add(&output->base.frame_signal,
6052 &output->recorder_frame_listener);
6053
6054 weston_output_schedule_repaint(&output->base);
6055
6056 weston_log("[libva recorder] initialized\n");
6057 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03006058 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006059 }
6060}
6061#else
6062static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006063recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
6064 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03006065{
6066 weston_log("Compiled without libva support\n");
6067}
6068#endif
6069
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006070static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03006071switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006072{
6073 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006074 bool dmabuf_support_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006075
Giulio Camuffo954f1832014-10-11 18:27:30 +03006076 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006077 return;
6078
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006079 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
6080
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006081 weston_log("Switching to GL renderer\n");
6082
Giulio Camuffo954f1832014-10-11 18:27:30 +03006083 b->gbm = create_gbm_device(b->drm.fd);
6084 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006085 weston_log("Failed to create gbm device. "
6086 "Aborting renderer switch\n");
6087 return;
6088 }
6089
Giulio Camuffo954f1832014-10-11 18:27:30 +03006090 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006091 pixman_renderer_output_destroy(&output->base);
6092
Giulio Camuffo954f1832014-10-11 18:27:30 +03006093 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006094
Giulio Camuffo954f1832014-10-11 18:27:30 +03006095 if (drm_backend_create_gl_renderer(b) < 0) {
6096 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006097 weston_log("Failed to create GL renderer. Quitting.\n");
6098 /* FIXME: we need a function to shutdown cleanly */
6099 assert(0);
6100 }
6101
Giulio Camuffo954f1832014-10-11 18:27:30 +03006102 wl_list_for_each(output, &b->compositor->output_list, base.link)
6103 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006104
Giulio Camuffo954f1832014-10-11 18:27:30 +03006105 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006106
6107 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
6108 if (linux_dmabuf_setup(b->compositor) < 0)
6109 weston_log("Error: initializing dmabuf "
6110 "support failed.\n");
6111 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006112}
6113
6114static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006115renderer_switch_binding(struct weston_keyboard *keyboard,
6116 const struct timespec *time, uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006117{
Derek Foreman8ae2db52015-07-15 13:00:36 -05006118 struct drm_backend *b =
Armin Krezović545dba62016-08-05 15:54:18 +02006119 to_drm_backend(keyboard->seat->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006120
Giulio Camuffo954f1832014-10-11 18:27:30 +03006121 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006122}
6123
Armin Krezović08368132016-09-30 14:11:05 +02006124static const struct weston_drm_output_api api = {
6125 drm_output_set_mode,
6126 drm_output_set_gbm_format,
6127 drm_output_set_seat,
6128};
6129
Giulio Camuffo954f1832014-10-11 18:27:30 +03006130static struct drm_backend *
6131drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006132 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006133{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006134 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01006135 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006136 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006137 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04006138 const char *session_seat;
Armin Krezović08368132016-09-30 14:11:05 +02006139 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006140
nerdopolisb16c4ac2018-06-29 08:17:46 -04006141 session_seat = getenv("XDG_SEAT");
6142 if (session_seat)
6143 seat_id = session_seat;
6144
6145 if (config->seat_id)
6146 seat_id = config->seat_id;
6147
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04006148 weston_log("initializing drm backend\n");
6149
Giulio Camuffo954f1832014-10-11 18:27:30 +03006150 b = zalloc(sizeof *b);
6151 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006152 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01006153
Daniel Stone6020f472018-02-05 15:46:20 +00006154 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00006155 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00006156 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006157
Pekka Paalanen68583832015-05-19 09:53:16 +03006158 /*
6159 * KMS support for hardware planes cannot properly synchronize
6160 * without nuclear page flip. Without nuclear/atomic, hw plane
6161 * and cursor plane updates would either tear or cause extra
6162 * waits for vblanks which means dropping the compositor framerate
Pekka Paalanen3f32a132015-09-07 15:38:43 +03006163 * to a fraction. For cursors, it's not so bad, so they are
6164 * enabled.
Pekka Paalanen68583832015-05-19 09:53:16 +03006165 *
6166 * These can be enabled again when nuclear/atomic support lands.
6167 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03006168 b->sprites_are_broken = 1;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006169 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006170 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00006171 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02006172 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006173
Pekka Paalanen7da9a382017-08-30 11:29:49 +03006174 compositor->backend = &b->base;
6175
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006176 if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
6177 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006178
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006179 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006180 compositor->launcher = weston_launcher_connect(compositor, config->tty,
6181 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006182 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02006183 weston_log("fatal: drm backend should be run using "
6184 "weston-launch binary, or your system should "
6185 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006186 goto err_compositor;
6187 }
6188
Giulio Camuffo954f1832014-10-11 18:27:30 +03006189 b->udev = udev_new();
6190 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006191 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006192 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006193 }
6194
Giulio Camuffo954f1832014-10-11 18:27:30 +03006195 b->session_listener.notify = session_notify;
6196 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05006197
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03006198 if (config->specific_device)
6199 drm_device = open_specific_drm_device(b, config->specific_device);
6200 else
6201 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04006202 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006203 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006204 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006205 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006206
Daniel Stoneefa504f2016-12-19 16:48:20 +00006207 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02006208 weston_log("failed to initialize kms\n");
6209 goto err_udev_dev;
6210 }
6211
Giulio Camuffo954f1832014-10-11 18:27:30 +03006212 if (b->use_pixman) {
6213 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006214 weston_log("failed to initialize pixman renderer\n");
6215 goto err_udev_dev;
6216 }
6217 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03006218 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006219 weston_log("failed to initialize egl\n");
6220 goto err_udev_dev;
6221 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006222 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05006223
Giulio Camuffo954f1832014-10-11 18:27:30 +03006224 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00006225 b->base.repaint_begin = drm_repaint_begin;
6226 b->base.repaint_flush = drm_repaint_flush;
6227 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03006228 b->base.create_output = drm_output_create;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02006229
Bob Ham91880f12016-01-12 10:21:47 +00006230 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04006231
Daniel Stone085d2b92015-05-21 00:00:57 +01006232 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006233 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05006234
Giulio Camuffo954f1832014-10-11 18:27:30 +03006235 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03006236 compositor, b->udev, seat_id,
6237 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006238 weston_log("failed to create input devices\n");
6239 goto err_sprite;
6240 }
6241
Pekka Paalanend2e62422017-09-08 15:48:07 +03006242 if (drm_backend_create_heads(b, drm_device) < 0) {
6243 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006244 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006245 }
6246
Jason Ekstrand9fc71512014-04-02 19:53:46 -05006247 /* A this point we have some idea of whether or not we have a working
6248 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03006249 if (!b->cursors_are_broken)
6250 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05006251
Giulio Camuffo954f1832014-10-11 18:27:30 +03006252 loop = wl_display_get_event_loop(compositor->wl_display);
6253 b->drm_source =
6254 wl_event_loop_add_fd(loop, b->drm.fd,
6255 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006256
Giulio Camuffo954f1832014-10-11 18:27:30 +03006257 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
6258 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05006259 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01006260 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006261 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03006262 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006263 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006264 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02006265 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03006266 udev_monitor_get_fd(b->udev_monitor),
6267 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006268
Giulio Camuffo954f1832014-10-11 18:27:30 +03006269 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02006270 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01006271 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006272 }
6273
Daniel Stonea96b93c2012-06-22 14:04:37 +01006274 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006275
Giulio Camuffo954f1832014-10-11 18:27:30 +03006276 weston_compositor_add_debug_binding(compositor, KEY_O,
6277 planes_binding, b);
6278 weston_compositor_add_debug_binding(compositor, KEY_C,
6279 planes_binding, b);
6280 weston_compositor_add_debug_binding(compositor, KEY_V,
6281 planes_binding, b);
6282 weston_compositor_add_debug_binding(compositor, KEY_Q,
6283 recorder_binding, b);
6284 weston_compositor_add_debug_binding(compositor, KEY_W,
6285 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006286
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006287 if (compositor->renderer->import_dmabuf) {
6288 if (linux_dmabuf_setup(compositor) < 0)
6289 weston_log("Error: initializing dmabuf "
6290 "support failed.\n");
6291 }
6292
Armin Krezović08368132016-09-30 14:11:05 +02006293 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
6294 &api, sizeof(api));
6295
6296 if (ret < 0) {
6297 weston_log("Failed to register output API.\n");
6298 goto err_udev_monitor;
6299 }
6300
Giulio Camuffo954f1832014-10-11 18:27:30 +03006301 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01006302
6303err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006304 wl_event_source_remove(b->udev_drm_source);
6305 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006306err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006307 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006308err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006309 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04006310err_sprite:
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01006311 if (b->gbm)
6312 gbm_device_destroy(b->gbm);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006313 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006314err_udev_dev:
6315 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006316err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006317 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006318err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006319 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006320err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006321 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006322 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006323 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006324}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006325
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006326static void
6327config_init_to_defaults(struct weston_drm_backend_config *config)
6328{
Pekka Paalanendee412d2018-04-23 11:44:58 +02006329 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006330}
6331
Giulio Camuffo954f1832014-10-11 18:27:30 +03006332WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01006333weston_backend_init(struct weston_compositor *compositor,
6334 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006335{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006336 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006337 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006338
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006339 if (config_base == NULL ||
6340 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
6341 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
6342 weston_log("drm backend config structure is invalid\n");
6343 return -1;
6344 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02006345
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006346 config_init_to_defaults(&config);
6347 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07006348
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006349 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006350 if (b == NULL)
6351 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006352
Giulio Camuffo954f1832014-10-11 18:27:30 +03006353 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006354}