blob: 52b5dd70c64cb2bb4ae60a37652257a81fb332ae [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
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030076#ifndef DRM_CAP_CURSOR_WIDTH
77#define DRM_CAP_CURSOR_WIDTH 0x8
78#endif
79
80#ifndef DRM_CAP_CURSOR_HEIGHT
81#define DRM_CAP_CURSOR_HEIGHT 0x9
82#endif
83
84#ifndef GBM_BO_USE_CURSOR
85#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
86#endif
87
Pekka Paalanendfc06832017-11-20 14:04:38 +020088#define MAX_CLONED_CONNECTORS 4
Pekka Paalanenc112f002017-08-28 16:27:20 +030089
Daniel Stone02cf4662017-03-03 16:19:39 +000090/**
Daniel Stone02cf4662017-03-03 16:19:39 +000091 * Represents the values of an enum-type KMS property
92 */
93struct drm_property_enum_info {
94 const char *name; /**< name as string (static, not freed) */
95 bool valid; /**< true if value is supported; ignore if false */
96 uint64_t value; /**< raw value */
97};
98
99/**
100 * Holds information on a DRM property, including its ID and the enum
101 * values it holds.
102 *
103 * DRM properties are allocated dynamically, and maintained as DRM objects
104 * within the normal object ID space; they thus do not have a stable ID
105 * to refer to. This includes enum values, which must be referred to by
106 * integer values, but these are not stable.
107 *
108 * drm_property_info allows a cache to be maintained where Weston can use
109 * enum values internally to refer to properties, with the mapping to DRM
110 * ID values being maintained internally.
111 */
112struct drm_property_info {
113 const char *name; /**< name as string (static, not freed) */
114 uint32_t prop_id; /**< KMS property object ID */
115 unsigned int num_enum_values; /**< number of enum values */
116 struct drm_property_enum_info *enum_values; /**< array of enum values */
117};
118
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000119/**
Daniel Stone598ee9d2016-11-16 11:55:20 +0000120 * List of properties attached to DRM planes
121 */
122enum wdrm_plane_property {
123 WDRM_PLANE_TYPE = 0,
124 WDRM_PLANE_SRC_X,
125 WDRM_PLANE_SRC_Y,
126 WDRM_PLANE_SRC_W,
127 WDRM_PLANE_SRC_H,
128 WDRM_PLANE_CRTC_X,
129 WDRM_PLANE_CRTC_Y,
130 WDRM_PLANE_CRTC_W,
131 WDRM_PLANE_CRTC_H,
132 WDRM_PLANE_FB_ID,
133 WDRM_PLANE_CRTC_ID,
134 WDRM_PLANE__COUNT
135};
136
137/**
138 * Possible values for the WDRM_PLANE_TYPE property.
139 */
140enum wdrm_plane_type {
141 WDRM_PLANE_TYPE_PRIMARY = 0,
142 WDRM_PLANE_TYPE_CURSOR,
143 WDRM_PLANE_TYPE_OVERLAY,
144 WDRM_PLANE_TYPE__COUNT
145};
146
147static struct drm_property_enum_info plane_type_enums[] = {
148 [WDRM_PLANE_TYPE_PRIMARY] = {
149 .name = "Primary",
150 },
151 [WDRM_PLANE_TYPE_OVERLAY] = {
152 .name = "Overlay",
153 },
154 [WDRM_PLANE_TYPE_CURSOR] = {
155 .name = "Cursor",
156 },
157};
158
159static const struct drm_property_info plane_props[] = {
160 [WDRM_PLANE_TYPE] = {
161 .name = "type",
162 .enum_values = plane_type_enums,
163 .num_enum_values = WDRM_PLANE_TYPE__COUNT,
164 },
165 [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
166 [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
167 [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
168 [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
169 [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
170 [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
171 [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
172 [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
173 [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
174 [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
175};
176
177/**
178 * List of properties attached to a DRM connector
179 */
180enum wdrm_connector_property {
181 WDRM_CONNECTOR_EDID = 0,
182 WDRM_CONNECTOR_DPMS,
183 WDRM_CONNECTOR_CRTC_ID,
184 WDRM_CONNECTOR__COUNT
185};
186
187static const struct drm_property_info connector_props[] = {
188 [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
189 [WDRM_CONNECTOR_DPMS] = { .name = "DPMS" },
190 [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
191};
192
193/**
Pekka Paalanencd011a62016-11-15 22:07:49 +0000194 * List of properties attached to DRM CRTCs
195 */
196enum wdrm_crtc_property {
197 WDRM_CRTC_MODE_ID = 0,
198 WDRM_CRTC_ACTIVE,
199 WDRM_CRTC__COUNT
200};
201
Daniel Stone598ee9d2016-11-16 11:55:20 +0000202static const struct drm_property_info crtc_props[] = {
203 [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
204 [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
205};
206
Pekka Paalanencd011a62016-11-15 22:07:49 +0000207/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000208 * Mode for drm_output_state_duplicate.
209 */
210enum drm_output_state_duplicate_mode {
211 DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
212 DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
213};
214
215/**
216 * Mode for drm_pending_state_apply and co.
217 */
218enum drm_state_apply_mode {
219 DRM_STATE_APPLY_SYNC, /**< state fully processed */
220 DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
221};
222
Giulio Camuffo954f1832014-10-11 18:27:30 +0300223struct drm_backend {
224 struct weston_backend base;
225 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400226
227 struct udev *udev;
228 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400229
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100230 struct udev_monitor *udev_monitor;
231 struct wl_event_source *udev_drm_source;
232
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100233 struct {
David Herrmannd7488c22012-03-11 20:05:21 +0100234 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100235 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300236 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100237 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200238 struct gbm_device *gbm;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700239 struct wl_listener session_listener;
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +0100240 uint32_t gbm_format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200241
Rob Clark4339add2012-08-09 14:18:28 -0500242 /* we need these parameters in order to not fail drmModeAddFB2()
243 * due to out of bounds dimensions, and then mistakenly set
244 * sprites_are_broken:
245 */
Daniel Stonef214fdc2016-11-14 17:43:57 +0000246 int min_width, max_width;
247 int min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -0500248
Daniel Stone085d2b92015-05-21 00:00:57 +0100249 struct wl_list plane_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500250 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200251 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500252
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000253 void *repaint_data;
254
Daniel Stone6020f472018-02-05 15:46:20 +0000255 bool state_invalid;
256
Pekka Paalaneneacec812017-09-12 13:43:51 +0300257 /* CRTC IDs not used by any enabled output. */
Daniel Stone087ddf02017-02-14 17:51:30 +0000258 struct wl_array unused_crtcs;
259
Rob Clarkab5b1e32012-08-09 13:24:45 -0500260 int cursors_are_broken;
261
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100262 bool universal_planes;
Pekka Paalanencd011a62016-11-15 22:07:49 +0000263 bool atomic_modeset;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100264
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200265 int use_pixman;
266
Rob Bradfordd355b802013-05-31 18:09:55 +0100267 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300268
Daniel Stone70d337d2015-06-16 18:42:23 +0100269 int32_t cursor_width;
270 int32_t cursor_height;
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +0000271
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000272 uint32_t pageflip_timeout;
Daniel Stoneb57c6a02017-10-05 16:27:21 +0100273
274 bool shutting_down;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400275};
276
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400277struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500278 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400279 drmModeModeInfo mode_info;
Daniel Stoned5526cb2016-11-16 10:54:10 +0000280 uint32_t blob_id;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400281};
282
Daniel Stonefc175a72017-04-04 17:54:22 +0100283enum drm_fb_type {
284 BUFFER_INVALID = 0, /**< never used */
285 BUFFER_CLIENT, /**< directly sourced from client */
286 BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
287 BUFFER_GBM_SURFACE, /**< internal EGL rendering */
Daniel Stonee4256832017-04-04 17:54:27 +0100288 BUFFER_CURSOR, /**< internal cursor buffer */
Daniel Stonefc175a72017-04-04 17:54:22 +0100289};
290
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300291struct drm_fb {
Daniel Stonefc175a72017-04-04 17:54:22 +0100292 enum drm_fb_type type;
293
Daniel Stone6e7a9612017-04-04 17:54:26 +0100294 int refcnt;
295
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200296 uint32_t fb_id, stride, handle, size;
Daniel Stone0b70fa42017-04-04 17:54:23 +0100297 const struct pixel_format_info *format;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000298 int width, height;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200299 int fd;
Pekka Paalanende685b82012-12-04 15:58:12 +0200300 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200301
302 /* Used by gbm fbs */
303 struct gbm_bo *bo;
Daniel Stone05a5ac22017-04-04 17:54:25 +0100304 struct gbm_surface *gbm_surface;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200305
306 /* Used by dumb fbs */
307 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300308};
309
Richard Hughes2b2092a2013-04-24 14:58:02 +0100310struct drm_edid {
311 char eisa_id[13];
312 char monitor_name[13];
313 char pnp_id[5];
314 char serial_number[13];
315};
316
Daniel Stone08d4edf2017-04-04 17:54:34 +0100317/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000318 * Pending state holds one or more drm_output_state structures, collected from
319 * performing repaint. This pending state is transient, and only lives between
320 * beginning a repaint group and flushing the results: after flush, each
321 * output state will complete and be retired separately.
322 */
323struct drm_pending_state {
324 struct drm_backend *backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000325 struct wl_list output_list;
326};
327
328/*
329 * Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
330 * plus >= 1 each of encoder/connector/plane. Since everything but the planes
331 * is currently statically assigned per-output, we mainly use this to track
332 * plane state.
333 *
334 * pending_state is set when the output state is owned by a pending_state,
335 * i.e. when it is being constructed and has not yet been applied. When the
336 * output state has been applied, the owning pending_state is freed.
337 */
338struct drm_output_state {
339 struct drm_pending_state *pending_state;
340 struct drm_output *output;
341 struct wl_list link;
Daniel Stonea08512f2016-11-08 17:46:10 +0000342 enum dpms_enum dpms;
Daniel Stonebc15f682016-11-14 16:57:01 +0000343 struct wl_list plane_list;
344};
345
346/**
347 * Plane state holds the dynamic state for a plane: where it is positioned,
348 * and which buffer it is currently displaying.
349 *
350 * The plane state is owned by an output state, except when setting an initial
351 * state. See drm_output_state for notes on state object lifetime.
352 */
353struct drm_plane_state {
354 struct drm_plane *plane;
355 struct drm_output *output;
356 struct drm_output_state *output_state;
357
358 struct drm_fb *fb;
359
360 int32_t src_x, src_y;
361 uint32_t src_w, src_h;
362 int32_t dest_x, dest_y;
363 uint32_t dest_w, dest_h;
364
365 bool complete;
366
367 struct wl_list link; /* drm_output_state::plane_list */
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000368};
369
370/**
Daniel Stone08d4edf2017-04-04 17:54:34 +0100371 * A plane represents one buffer, positioned within a CRTC, and stacked
372 * relative to other planes on the same CRTC.
373 *
374 * Each CRTC has a 'primary plane', which use used to display the classic
375 * framebuffer contents, as accessed through the legacy drmModeSetCrtc
376 * call (which combines setting the CRTC's actual physical mode, and the
377 * properties of the primary plane).
378 *
379 * The cursor plane also has its own alternate legacy API.
380 *
381 * Other planes are used opportunistically to display content we do not
382 * wish to blit into the primary plane. These non-primary/cursor planes
383 * are referred to as 'sprites'.
384 */
385struct drm_plane {
Daniel Stone08d4edf2017-04-04 17:54:34 +0100386 struct weston_plane base;
387
Daniel Stone08d4edf2017-04-04 17:54:34 +0100388 struct drm_backend *backend;
389
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100390 enum wdrm_plane_type type;
391
Daniel Stone08d4edf2017-04-04 17:54:34 +0100392 uint32_t possible_crtcs;
393 uint32_t plane_id;
394 uint32_t count_formats;
395
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100396 struct drm_property_info props[WDRM_PLANE__COUNT];
397
Daniel Stonebc15f682016-11-14 16:57:01 +0000398 /* The last state submitted to the kernel for this plane. */
399 struct drm_plane_state *state_cur;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100400
Daniel Stonebc15f682016-11-14 16:57:01 +0000401 struct wl_list link;
Daniel Stone08d4edf2017-04-04 17:54:34 +0100402
403 uint32_t formats[];
404};
405
Pekka Paalanenc112f002017-08-28 16:27:20 +0300406struct drm_head {
407 struct weston_head base;
408 struct drm_backend *backend;
409
Armin Krezović08368132016-09-30 14:11:05 +0200410 drmModeConnector *connector;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400411 uint32_t connector_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100412 struct drm_edid edid;
Daniel Stone02cf4662017-03-03 16:19:39 +0000413
414 /* Holds the properties for the connector */
415 struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300416
417 struct backlight *backlight;
Pekka Paalanen13d233e2017-09-11 14:06:11 +0300418
419 drmModeModeInfo inherited_mode; /**< Original mode on the connector */
Pekka Paalanen27cc4812017-11-20 13:31:06 +0200420 uint32_t inherited_crtc_id; /**< Original CRTC assignment */
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300421};
422
423struct drm_output {
424 struct weston_output base;
425
426 uint32_t crtc_id; /* object ID to pass to DRM functions */
427 int pipe; /* index of CRTC in resource array / bitmasks */
428
Pekka Paalanencd011a62016-11-15 22:07:49 +0000429 /* Holds the properties for the CRTC */
430 struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200431
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300432 int vblank_pending;
433 int page_flip_pending;
Daniel Stone598ee9d2016-11-16 11:55:20 +0000434 int atomic_complete_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800435 int destroy_pending;
Armin Krezović08368132016-09-30 14:11:05 +0200436 int disable_pending;
Daniel Stonea08512f2016-11-08 17:46:10 +0000437 int dpms_off_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300438
Daniel Stonee4256832017-04-04 17:54:27 +0100439 struct drm_fb *gbm_cursor_fb[2];
Daniel Stone2ba17f42015-05-19 20:02:41 +0100440 struct drm_plane *cursor_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500441 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400442 int current_cursor;
Daniel Stone5bb8f582017-04-04 17:54:28 +0100443
444 struct gbm_surface *gbm_surface;
445 uint32_t gbm_format;
446
Daniel Stonee2e80132018-01-16 15:37:33 +0000447 /* Plane being displayed directly on the CRTC */
448 struct drm_plane *scanout_plane;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200449
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000450 /* The last state submitted to the kernel for this CRTC. */
451 struct drm_output_state *state_cur;
452 /* The previously-submitted state, where the hardware has not
453 * yet acknowledged completion of state_cur. */
454 struct drm_output_state *state_last;
455
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200456 struct drm_fb *dumb[2];
457 pixman_image_t *image[2];
458 int current_image;
459 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300460
461 struct vaapi_recorder *recorder;
462 struct wl_listener recorder_frame_listener;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000463
464 struct wl_event_source *pageflip_timer;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400465};
466
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300467static struct gl_renderer_interface *gl_renderer;
468
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500469static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400470
Daniel Stone087ddf02017-02-14 17:51:30 +0000471static void
472wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
473{
474 uint32_t *pos, *end;
475
476 end = (uint32_t *) ((char *) array->data + array->size);
477
478 wl_array_for_each(pos, array) {
479 if (*pos != elm)
480 continue;
481
482 array->size -= sizeof(*pos);
483 if (pos + 1 == end)
484 break;
485
486 memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
487 break;
488 }
489}
490
Pekka Paalanenc112f002017-08-28 16:27:20 +0300491static inline struct drm_head *
492to_drm_head(struct weston_head *base)
493{
494 return container_of(base, struct drm_head, base);
495}
496
Armin Krezović545dba62016-08-05 15:54:18 +0200497static inline struct drm_output *
498to_drm_output(struct weston_output *base)
499{
500 return container_of(base, struct drm_output, base);
501}
502
503static inline struct drm_backend *
504to_drm_backend(struct weston_compositor *base)
505{
506 return container_of(base->backend, struct drm_backend, base);
507}
508
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000509static int
510pageflip_timeout(void *data) {
511 /*
512 * Our timer just went off, that means we're not receiving drm
513 * page flip events anymore for that output. Let's gracefully exit
514 * weston with a return value so devs can debug what's going on.
515 */
516 struct drm_output *output = data;
517 struct weston_compositor *compositor = output->base.compositor;
518
519 weston_log("Pageflip timeout reached on output %s, your "
520 "driver is probably buggy! Exiting.\n",
521 output->base.name);
522 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
523
524 return 0;
525}
526
527/* Creates the pageflip timer. Note that it isn't armed by default */
528static int
529drm_output_pageflip_timer_create(struct drm_output *output)
530{
531 struct wl_event_loop *loop = NULL;
532 struct weston_compositor *ec = output->base.compositor;
533
534 loop = wl_display_get_event_loop(ec->wl_display);
535 assert(loop);
536 output->pageflip_timer = wl_event_loop_add_timer(loop,
537 pageflip_timeout,
538 output);
539
540 if (output->pageflip_timer == NULL) {
541 weston_log("creating drm pageflip timer failed: %m\n");
542 return -1;
543 }
544
545 return 0;
546}
547
Daniel Stonecb04cc42016-11-16 11:51:27 +0000548static inline struct drm_mode *
549to_drm_mode(struct weston_mode *base)
550{
551 return container_of(base, struct drm_mode, base);
552}
553
Daniel Stone02cf4662017-03-03 16:19:39 +0000554/**
555 * Get the current value of a KMS property
556 *
557 * Given a drmModeObjectGetProperties return, as well as the drm_property_info
558 * for the target property, return the current value of that property,
559 * with an optional default. If the property is a KMS enum type, the return
560 * value will be translated into the appropriate internal enum.
561 *
562 * If the property is not present, the default value will be returned.
563 *
564 * @param info Internal structure for property to look up
565 * @param props Raw KMS properties for the target object
566 * @param def Value to return if property is not found
567 */
568static uint64_t
569drm_property_get_value(struct drm_property_info *info,
570 drmModeObjectPropertiesPtr props,
571 uint64_t def)
572{
573 unsigned int i;
574
575 if (info->prop_id == 0)
576 return def;
577
578 for (i = 0; i < props->count_props; i++) {
579 unsigned int j;
580
581 if (props->props[i] != info->prop_id)
582 continue;
583
584 /* Simple (non-enum) types can return the value directly */
585 if (info->num_enum_values == 0)
586 return props->prop_values[i];
587
588 /* Map from raw value to enum value */
589 for (j = 0; j < info->num_enum_values; j++) {
590 if (!info->enum_values[j].valid)
591 continue;
592 if (info->enum_values[j].value != props->prop_values[i])
593 continue;
594
595 return j;
596 }
597
598 /* We don't have a mapping for this enum; return default. */
599 break;
600 }
601
602 return def;
603}
604
605/**
606 * Cache DRM property values
607 *
608 * Update a per-object array of drm_property_info structures, given the
609 * DRM properties of the object.
610 *
611 * Call this every time an object newly appears (note that only connectors
612 * can be hotplugged), the first time it is seen, or when its status changes
613 * in a way which invalidates the potential property values (currently, the
614 * only case for this is connector hotplug).
615 *
616 * This updates the property IDs and enum values within the drm_property_info
617 * array.
618 *
619 * DRM property enum values are dynamic at runtime; the user must query the
620 * property to find out the desired runtime value for a requested string
621 * name. Using the 'type' field on planes as an example, there is no single
622 * hardcoded constant for primary plane types; instead, the property must be
623 * queried at runtime to find the value associated with the string "Primary".
624 *
625 * This helper queries and caches the enum values, to allow us to use a set
626 * of compile-time-constant enums portably across various implementations.
627 * The values given in enum_names are searched for, and stored in the
628 * same-indexed field of the map array.
629 *
630 * @param b DRM backend object
631 * @param src DRM property info array to source from
632 * @param info DRM property info array to copy into
633 * @param num_infos Number of entries in the source array
634 * @param props DRM object properties for the object
635 */
636static void
637drm_property_info_populate(struct drm_backend *b,
638 const struct drm_property_info *src,
639 struct drm_property_info *info,
640 unsigned int num_infos,
641 drmModeObjectProperties *props)
642{
643 drmModePropertyRes *prop;
644 unsigned i, j;
645
646 for (i = 0; i < num_infos; i++) {
647 unsigned int j;
648
649 info[i].name = src[i].name;
650 info[i].prop_id = 0;
651 info[i].num_enum_values = src[i].num_enum_values;
652
653 if (src[i].num_enum_values == 0)
654 continue;
655
656 info[i].enum_values =
657 malloc(src[i].num_enum_values *
658 sizeof(*info[i].enum_values));
659 assert(info[i].enum_values);
660 for (j = 0; j < info[i].num_enum_values; j++) {
661 info[i].enum_values[j].name = src[i].enum_values[j].name;
662 info[i].enum_values[j].valid = false;
663 }
664 }
665
666 for (i = 0; i < props->count_props; i++) {
667 unsigned int k;
668
669 prop = drmModeGetProperty(b->drm.fd, props->props[i]);
670 if (!prop)
671 continue;
672
673 for (j = 0; j < num_infos; j++) {
674 if (!strcmp(prop->name, info[j].name))
675 break;
676 }
677
678 /* We don't know/care about this property. */
679 if (j == num_infos) {
680#ifdef DEBUG
681 weston_log("DRM debug: unrecognized property %u '%s'\n",
682 prop->prop_id, prop->name);
683#endif
684 drmModeFreeProperty(prop);
685 continue;
686 }
687
688 if (info[j].num_enum_values == 0 &&
689 (prop->flags & DRM_MODE_PROP_ENUM)) {
690 weston_log("DRM: expected property %s to not be an"
691 " enum, but it is; ignoring\n", prop->name);
692 drmModeFreeProperty(prop);
693 continue;
694 }
695
696 info[j].prop_id = props->props[i];
697
698 if (info[j].num_enum_values == 0) {
699 drmModeFreeProperty(prop);
700 continue;
701 }
702
703 if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
704 weston_log("DRM: expected property %s to be an enum,"
705 " but it is not; ignoring\n", prop->name);
706 drmModeFreeProperty(prop);
707 info[j].prop_id = 0;
708 continue;
709 }
710
711 for (k = 0; k < info[j].num_enum_values; k++) {
712 int l;
713
714 for (l = 0; l < prop->count_enums; l++) {
715 if (!strcmp(prop->enums[l].name,
716 info[j].enum_values[k].name))
717 break;
718 }
719
720 if (l == prop->count_enums)
721 continue;
722
723 info[j].enum_values[k].valid = true;
724 info[j].enum_values[k].value = prop->enums[l].value;
725 }
726
727 drmModeFreeProperty(prop);
728 }
729
730#ifdef DEBUG
731 for (i = 0; i < num_infos; i++) {
732 if (info[i].prop_id == 0)
733 weston_log("DRM warning: property '%s' missing\n",
734 info[i].name);
735 }
736#endif
737}
738
739/**
740 * Free DRM property information
741 *
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300742 * Frees all memory associated with a DRM property info array and zeroes
743 * it out, leaving it usable for a further drm_property_info_update() or
744 * drm_property_info_free().
Daniel Stone02cf4662017-03-03 16:19:39 +0000745 *
746 * @param info DRM property info array
747 * @param num_props Number of entries in array to free
748 */
749static void
750drm_property_info_free(struct drm_property_info *info, int num_props)
751{
752 int i;
753
754 for (i = 0; i < num_props; i++)
755 free(info[i].enum_values);
Pekka Paalanen46e4f972017-09-07 15:32:01 +0300756
757 memset(info, 0, sizeof(*info) * num_props);
Daniel Stone02cf4662017-03-03 16:19:39 +0000758}
759
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400760static void
Daniel Stone2ba17f42015-05-19 20:02:41 +0100761drm_output_set_cursor(struct drm_output_state *output_state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400762
Mario Kleinerf507ec32015-06-21 21:25:14 +0200763static void
764drm_output_update_msc(struct drm_output *output, unsigned int seq);
765
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000766static void
767drm_output_destroy(struct weston_output *output_base);
768
Daniel Stone5ff289a2017-10-07 12:59:02 +0100769/**
770 * Returns true if the plane can be used on the given output for its current
771 * repaint cycle.
772 */
773static bool
774drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100776 assert(plane->state_cur);
777
778 /* The plane still has a request not yet completed by the kernel. */
779 if (!plane->state_cur->complete)
780 return false;
781
782 /* The plane is still active on another output. */
783 if (plane->state_cur->output && plane->state_cur->output != output)
784 return false;
785
786 /* Check whether the plane can be used with this CRTC; possible_crtcs
787 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Daniel Stone08d4edf2017-04-04 17:54:34 +0100788 return !!(plane->possible_crtcs & (1 << output->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500789}
790
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000791static struct drm_output *
792drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
793{
794 struct drm_output *output;
795
796 wl_list_for_each(output, &b->compositor->output_list, base.link) {
797 if (output->crtc_id == crtc_id)
798 return output;
799 }
800
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000801 return NULL;
802}
803
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300804static struct drm_head *
805drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
806{
807 struct weston_head *base;
808 struct drm_head *head;
809
810 wl_list_for_each(base,
811 &backend->compositor->head_list, compositor_link) {
812 head = to_drm_head(base);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +0300813 if (head->connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300814 return head;
815 }
816
817 return NULL;
818}
819
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300820static void
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100821drm_fb_destroy(struct drm_fb *fb)
822{
823 if (fb->fb_id != 0)
824 drmModeRmFB(fb->fd, fb->fb_id);
825 weston_buffer_reference(&fb->buffer_ref, NULL);
826 free(fb);
827}
828
829static void
830drm_fb_destroy_dumb(struct drm_fb *fb)
831{
832 struct drm_mode_destroy_dumb destroy_arg;
833
834 assert(fb->type == BUFFER_PIXMAN_DUMB);
835
836 if (fb->map && fb->size > 0)
837 munmap(fb->map, fb->size);
838
839 memset(&destroy_arg, 0, sizeof(destroy_arg));
840 destroy_arg.handle = fb->handle;
841 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
842
843 drm_fb_destroy(fb);
844}
845
846static void
847drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300848{
849 struct drm_fb *fb = data;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300850
Daniel Stonee4256832017-04-04 17:54:27 +0100851 assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
852 fb->type == BUFFER_CURSOR);
Tomohito Esaki576f42e2017-04-04 17:54:24 +0100853 drm_fb_destroy(fb);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300854}
855
856static struct drm_fb *
Daniel Stonef214fdc2016-11-14 17:43:57 +0000857drm_fb_create_dumb(struct drm_backend *b, int width, int height,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300858 uint32_t format)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200859{
860 struct drm_fb *fb;
861 int ret;
862
863 struct drm_mode_create_dumb create_arg;
864 struct drm_mode_destroy_dumb destroy_arg;
865 struct drm_mode_map_dumb map_arg;
Daniel Stone1de42522016-11-17 18:17:16 +0000866 uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200867
Peter Huttererf3d62272013-08-08 11:57:05 +1000868 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200869 if (!fb)
870 return NULL;
871
Daniel Stone6e7a9612017-04-04 17:54:26 +0100872 fb->refcnt = 1;
873
Daniel Stone0b70fa42017-04-04 17:54:23 +0100874 fb->format = pixel_format_get_info(format);
875 if (!fb->format) {
876 weston_log("failed to look up format 0x%lx\n",
877 (unsigned long) format);
878 goto err_fb;
879 }
880
881 if (!fb->format->depth || !fb->format->bpp) {
882 weston_log("format 0x%lx is not compatible with dumb buffers\n",
883 (unsigned long) format);
884 goto err_fb;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300885 }
886
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700887 memset(&create_arg, 0, sizeof create_arg);
Daniel Stone0b70fa42017-04-04 17:54:23 +0100888 create_arg.bpp = fb->format->bpp;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200889 create_arg.width = width;
890 create_arg.height = height;
891
Giulio Camuffo954f1832014-10-11 18:27:30 +0300892 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200893 if (ret)
894 goto err_fb;
895
Daniel Stonefc175a72017-04-04 17:54:22 +0100896 fb->type = BUFFER_PIXMAN_DUMB;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200897 fb->handle = create_arg.handle;
898 fb->stride = create_arg.pitch;
899 fb->size = create_arg.size;
Daniel Stonec8c917c2016-11-14 17:45:58 +0000900 fb->width = width;
901 fb->height = height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300902 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200903
Daniel Stone1de42522016-11-17 18:17:16 +0000904 handles[0] = fb->handle;
905 pitches[0] = fb->stride;
906 offsets[0] = 0;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300907
Daniel Stone1de42522016-11-17 18:17:16 +0000908 ret = drmModeAddFB2(b->drm.fd, width, height, fb->format->format,
909 handles, pitches, offsets, &fb->fb_id, 0);
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300910 if (ret) {
Daniel Stone0b70fa42017-04-04 17:54:23 +0100911 ret = drmModeAddFB(b->drm.fd, width, height,
912 fb->format->depth, fb->format->bpp,
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +0300913 fb->stride, fb->handle, &fb->fb_id);
914 }
915
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200916 if (ret)
917 goto err_bo;
918
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700919 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200920 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400921 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200922 if (ret)
923 goto err_add_fb;
924
Chris Michael4a7ce1f2015-11-10 10:40:37 -0500925 fb->map = mmap(NULL, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300926 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200927 if (fb->map == MAP_FAILED)
928 goto err_add_fb;
929
930 return fb;
931
932err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300933 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200934err_bo:
935 memset(&destroy_arg, 0, sizeof(destroy_arg));
936 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300937 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200938err_fb:
939 free(fb);
940 return NULL;
941}
942
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200943static struct drm_fb *
Daniel Stone6e7a9612017-04-04 17:54:26 +0100944drm_fb_ref(struct drm_fb *fb)
945{
946 fb->refcnt++;
947 return fb;
948}
949
950static struct drm_fb *
Daniel Stonefc175a72017-04-04 17:54:22 +0100951drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
952 uint32_t format, enum drm_fb_type type)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300953{
954 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Derek Foreman482ffdf2016-07-08 12:50:57 -0500955 uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300956 int ret;
957
Daniel Stonefc175a72017-04-04 17:54:22 +0100958 if (fb) {
959 assert(fb->type == type);
Daniel Stone6e7a9612017-04-04 17:54:26 +0100960 return drm_fb_ref(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +0100961 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300962
Daniel Stone1de42522016-11-17 18:17:16 +0000963 assert(format != 0);
964
Bryce Harringtonde16d892014-11-20 22:21:57 -0800965 fb = zalloc(sizeof *fb);
966 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200967 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300968
Daniel Stonefc175a72017-04-04 17:54:22 +0100969 fb->type = type;
Daniel Stone6e7a9612017-04-04 17:54:26 +0100970 fb->refcnt = 1;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300971 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300972
Daniel Stonec8c917c2016-11-14 17:45:58 +0000973 fb->width = gbm_bo_get_width(bo);
974 fb->height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200975 fb->stride = gbm_bo_get_stride(bo);
976 fb->handle = gbm_bo_get_handle(bo).u32;
Daniel Stone0b70fa42017-04-04 17:54:23 +0100977 fb->format = pixel_format_get_info(format);
Daniel Stonec8c917c2016-11-14 17:45:58 +0000978 fb->size = fb->stride * fb->height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300979 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300980
Daniel Stone0b70fa42017-04-04 17:54:23 +0100981 if (!fb->format) {
982 weston_log("couldn't look up format 0x%lx\n",
983 (unsigned long) format);
984 goto err_free;
985 }
986
Daniel Stonec8c917c2016-11-14 17:45:58 +0000987 if (backend->min_width > fb->width ||
988 fb->width > backend->max_width ||
989 backend->min_height > fb->height ||
990 fb->height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200991 weston_log("bo geometry out of bounds\n");
992 goto err_free;
993 }
994
Daniel Stone1de42522016-11-17 18:17:16 +0000995 handles[0] = fb->handle;
996 pitches[0] = fb->stride;
997 offsets[0] = 0;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200998
Daniel Stone1de42522016-11-17 18:17:16 +0000999 ret = drmModeAddFB2(backend->drm.fd, fb->width, fb->height,
1000 fb->format->format, handles, pitches, offsets,
1001 &fb->fb_id, 0);
Daniel Stone0b70fa42017-04-04 17:54:23 +01001002 if (ret && fb->format->depth && fb->format->bpp)
Daniel Stonec8c917c2016-11-14 17:45:58 +00001003 ret = drmModeAddFB(backend->drm.fd, fb->width, fb->height,
Daniel Stone0b70fa42017-04-04 17:54:23 +01001004 fb->format->depth, fb->format->bpp,
1005 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001006
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001007 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001008 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001009 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001010 }
1011
Tomohito Esaki576f42e2017-04-04 17:54:24 +01001012 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001013
1014 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001015
1016err_free:
1017 free(fb);
1018 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001019}
1020
1021static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001022drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001023{
Pekka Paalanende685b82012-12-04 15:58:12 +02001024 assert(fb->buffer_ref.buffer == NULL);
Daniel Stonefc175a72017-04-04 17:54:22 +01001025 assert(fb->type == BUFFER_CLIENT);
Pekka Paalanende685b82012-12-04 15:58:12 +02001026 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001027}
1028
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001029static void
Daniel Stone05a5ac22017-04-04 17:54:25 +01001030drm_fb_unref(struct drm_fb *fb)
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001031{
1032 if (!fb)
1033 return;
1034
Daniel Stone6e7a9612017-04-04 17:54:26 +01001035 assert(fb->refcnt > 0);
1036 if (--fb->refcnt > 0)
1037 return;
1038
Daniel Stonefc175a72017-04-04 17:54:22 +01001039 switch (fb->type) {
1040 case BUFFER_PIXMAN_DUMB:
Daniel Stone6e7a9612017-04-04 17:54:26 +01001041 drm_fb_destroy_dumb(fb);
Daniel Stonefc175a72017-04-04 17:54:22 +01001042 break;
Daniel Stonee4256832017-04-04 17:54:27 +01001043 case BUFFER_CURSOR:
Daniel Stonefc175a72017-04-04 17:54:22 +01001044 case BUFFER_CLIENT:
1045 gbm_bo_destroy(fb->bo);
1046 break;
1047 case BUFFER_GBM_SURFACE:
Daniel Stone05a5ac22017-04-04 17:54:25 +01001048 gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
Daniel Stonefc175a72017-04-04 17:54:22 +01001049 break;
1050 default:
1051 assert(NULL);
1052 break;
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001053 }
1054}
1055
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001056/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001057 * Allocate a new, empty, plane state.
1058 */
1059static struct drm_plane_state *
1060drm_plane_state_alloc(struct drm_output_state *state_output,
1061 struct drm_plane *plane)
1062{
1063 struct drm_plane_state *state = zalloc(sizeof(*state));
1064
1065 assert(state);
1066 state->output_state = state_output;
1067 state->plane = plane;
1068
1069 /* Here we only add the plane state to the desired link, and not
1070 * set the member. Having an output pointer set means that the
1071 * plane will be displayed on the output; this won't be the case
1072 * when we go to disable a plane. In this case, it must be part of
1073 * the commit (and thus the output state), but the member must be
1074 * NULL, as it will not be on any output when the state takes
1075 * effect.
1076 */
1077 if (state_output)
1078 wl_list_insert(&state_output->plane_list, &state->link);
1079 else
1080 wl_list_init(&state->link);
1081
1082 return state;
1083}
1084
1085/**
1086 * Free an existing plane state. As a special case, the state will not
1087 * normally be freed if it is the current state; see drm_plane_set_state.
1088 */
1089static void
1090drm_plane_state_free(struct drm_plane_state *state, bool force)
1091{
1092 if (!state)
1093 return;
1094
1095 wl_list_remove(&state->link);
1096 wl_list_init(&state->link);
1097 state->output_state = NULL;
1098
1099 if (force || state != state->plane->state_cur) {
1100 drm_fb_unref(state->fb);
1101 free(state);
1102 }
1103}
1104
1105/**
1106 * Duplicate an existing plane state into a new plane state, storing it within
1107 * the given output state. If the output state already contains a plane state
1108 * for the drm_plane referenced by 'src', that plane state is freed first.
1109 */
1110static struct drm_plane_state *
1111drm_plane_state_duplicate(struct drm_output_state *state_output,
1112 struct drm_plane_state *src)
1113{
1114 struct drm_plane_state *dst = malloc(sizeof(*dst));
1115 struct drm_plane_state *old, *tmp;
1116
1117 assert(src);
1118 assert(dst);
1119 *dst = *src;
1120 wl_list_init(&dst->link);
1121
1122 wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
1123 /* Duplicating a plane state into the same output state, so
1124 * it can replace itself with an identical copy of itself,
1125 * makes no sense. */
1126 assert(old != src);
1127 if (old->plane == dst->plane)
1128 drm_plane_state_free(old, false);
1129 }
1130
1131 wl_list_insert(&state_output->plane_list, &dst->link);
1132 if (src->fb)
1133 dst->fb = drm_fb_ref(src->fb);
1134 dst->output_state = state_output;
1135 dst->complete = false;
1136
1137 return dst;
1138}
1139
1140/**
1141 * Remove a plane state from an output state; if the plane was previously
1142 * enabled, then replace it with a disabling state. This ensures that the
1143 * output state was untouched from it was before the plane state was
1144 * modified by the caller of this function.
1145 *
1146 * This is required as drm_output_state_get_plane may either allocate a
1147 * new plane state, in which case this function will just perform a matching
1148 * drm_plane_state_free, or it may instead repurpose an existing disabling
1149 * state (if the plane was previously active), in which case this function
1150 * will reset it.
1151 */
1152static void
1153drm_plane_state_put_back(struct drm_plane_state *state)
1154{
1155 struct drm_output_state *state_output;
1156 struct drm_plane *plane;
1157
1158 if (!state)
1159 return;
1160
1161 state_output = state->output_state;
1162 plane = state->plane;
1163 drm_plane_state_free(state, false);
1164
1165 /* Plane was previously disabled; no need to keep this temporary
1166 * state around. */
1167 if (!plane->state_cur->fb)
1168 return;
1169
1170 (void) drm_plane_state_alloc(state_output, plane);
1171}
1172
1173/**
Daniel Stone2ba17f42015-05-19 20:02:41 +01001174 * Return a plane state from a drm_output_state.
1175 */
1176static struct drm_plane_state *
1177drm_output_state_get_existing_plane(struct drm_output_state *state_output,
1178 struct drm_plane *plane)
1179{
1180 struct drm_plane_state *ps;
1181
1182 wl_list_for_each(ps, &state_output->plane_list, link) {
1183 if (ps->plane == plane)
1184 return ps;
1185 }
1186
1187 return NULL;
1188}
1189
1190/**
Daniel Stonebc15f682016-11-14 16:57:01 +00001191 * Return a plane state from a drm_output_state, either existing or
1192 * freshly allocated.
1193 */
1194static struct drm_plane_state *
1195drm_output_state_get_plane(struct drm_output_state *state_output,
1196 struct drm_plane *plane)
1197{
1198 struct drm_plane_state *ps;
1199
Daniel Stone2ba17f42015-05-19 20:02:41 +01001200 ps = drm_output_state_get_existing_plane(state_output, plane);
1201 if (ps)
1202 return ps;
Daniel Stonebc15f682016-11-14 16:57:01 +00001203
1204 return drm_plane_state_alloc(state_output, plane);
1205}
1206
1207/**
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001208 * Allocate a new, empty drm_output_state. This should not generally be used
1209 * in the repaint cycle; see drm_output_state_duplicate.
1210 */
1211static struct drm_output_state *
1212drm_output_state_alloc(struct drm_output *output,
1213 struct drm_pending_state *pending_state)
Daniel Stone90648872016-10-21 18:08:37 +01001214{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001215 struct drm_output_state *state = zalloc(sizeof(*state));
1216
1217 assert(state);
1218 state->output = output;
Daniel Stonea08512f2016-11-08 17:46:10 +00001219 state->dpms = WESTON_DPMS_OFF;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001220 state->pending_state = pending_state;
1221 if (pending_state)
1222 wl_list_insert(&pending_state->output_list, &state->link);
1223 else
1224 wl_list_init(&state->link);
1225
Daniel Stonebc15f682016-11-14 16:57:01 +00001226 wl_list_init(&state->plane_list);
1227
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001228 return state;
1229}
1230
1231/**
1232 * Duplicate an existing drm_output_state into a new one. This is generally
1233 * used during the repaint cycle, to capture the existing state of an output
1234 * and modify it to create a new state to be used.
1235 *
1236 * The mode determines whether the output will be reset to an a blank state,
1237 * or an exact mirror of the current state.
1238 */
1239static struct drm_output_state *
1240drm_output_state_duplicate(struct drm_output_state *src,
1241 struct drm_pending_state *pending_state,
1242 enum drm_output_state_duplicate_mode plane_mode)
1243{
1244 struct drm_output_state *dst = malloc(sizeof(*dst));
Daniel Stonebc15f682016-11-14 16:57:01 +00001245 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001246
1247 assert(dst);
1248
1249 /* Copy the whole structure, then individually modify the
1250 * pending_state, as well as the list link into our pending
1251 * state. */
1252 *dst = *src;
1253
1254 dst->pending_state = pending_state;
1255 if (pending_state)
1256 wl_list_insert(&pending_state->output_list, &dst->link);
1257 else
1258 wl_list_init(&dst->link);
1259
Daniel Stonebc15f682016-11-14 16:57:01 +00001260 wl_list_init(&dst->plane_list);
1261
1262 wl_list_for_each(ps, &src->plane_list, link) {
1263 /* Don't carry planes which are now disabled; these should be
1264 * free for other outputs to reuse. */
1265 if (!ps->output)
1266 continue;
1267
1268 if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
1269 (void) drm_plane_state_alloc(dst, ps->plane);
1270 else
1271 (void) drm_plane_state_duplicate(dst, ps);
1272 }
1273
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001274 return dst;
1275}
1276
1277/**
1278 * Free an unused drm_output_state.
1279 */
1280static void
1281drm_output_state_free(struct drm_output_state *state)
1282{
Daniel Stonebc15f682016-11-14 16:57:01 +00001283 struct drm_plane_state *ps, *next;
1284
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001285 if (!state)
1286 return;
1287
Daniel Stonebc15f682016-11-14 16:57:01 +00001288 wl_list_for_each_safe(ps, next, &state->plane_list, link)
1289 drm_plane_state_free(ps, false);
1290
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001291 wl_list_remove(&state->link);
Daniel Stonebc15f682016-11-14 16:57:01 +00001292
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001293 free(state);
Daniel Stone90648872016-10-21 18:08:37 +01001294}
1295
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001296/**
Daniel Stonea08512f2016-11-08 17:46:10 +00001297 * Get output state to disable output
1298 *
1299 * Returns a pointer to an output_state object which can be used to disable
1300 * an output (e.g. DPMS off).
1301 *
1302 * @param pending_state The pending state object owning this update
1303 * @param output The output to disable
1304 * @returns A drm_output_state to disable the output
1305 */
1306static struct drm_output_state *
1307drm_output_get_disable_state(struct drm_pending_state *pending_state,
1308 struct drm_output *output)
1309{
1310 struct drm_output_state *output_state;
1311
1312 output_state = drm_output_state_duplicate(output->state_cur,
1313 pending_state,
1314 DRM_OUTPUT_STATE_CLEAR_PLANES);
1315 output_state->dpms = WESTON_DPMS_OFF;
1316
1317 return output_state;
1318}
1319
1320/**
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001321 * Allocate a new drm_pending_state
1322 *
1323 * Allocate a new, empty, 'pending state' structure to be used across a
1324 * repaint cycle or similar.
1325 *
1326 * @param backend DRM backend
1327 * @returns Newly-allocated pending state structure
1328 */
1329static struct drm_pending_state *
1330drm_pending_state_alloc(struct drm_backend *backend)
1331{
1332 struct drm_pending_state *ret;
1333
1334 ret = calloc(1, sizeof(*ret));
1335 if (!ret)
1336 return NULL;
1337
1338 ret->backend = backend;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001339 wl_list_init(&ret->output_list);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001340
1341 return ret;
1342}
1343
1344/**
1345 * Free a drm_pending_state structure
1346 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001347 * Frees a pending_state structure, as well as any output_states connected
1348 * to this pending state.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001349 *
1350 * @param pending_state Pending state structure to free
1351 */
1352static void
1353drm_pending_state_free(struct drm_pending_state *pending_state)
1354{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001355 struct drm_output_state *output_state, *tmp;
1356
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001357 if (!pending_state)
1358 return;
1359
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001360 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1361 link) {
1362 drm_output_state_free(output_state);
1363 }
1364
Daniel Stoneeedf84c2017-02-10 18:06:04 +00001365 free(pending_state);
1366}
1367
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001368/**
1369 * Find an output state in a pending state
1370 *
1371 * Given a pending_state structure, find the output_state for a particular
1372 * output.
1373 *
1374 * @param pending_state Pending state structure to search
1375 * @param output Output to find state for
1376 * @returns Output state if present, or NULL if not
1377 */
1378static struct drm_output_state *
1379drm_pending_state_get_output(struct drm_pending_state *pending_state,
1380 struct drm_output *output)
1381{
1382 struct drm_output_state *output_state;
1383
1384 wl_list_for_each(output_state, &pending_state->output_list, link) {
1385 if (output_state->output == output)
1386 return output_state;
1387 }
1388
1389 return NULL;
1390}
1391
Daniel Stonea08512f2016-11-08 17:46:10 +00001392static int drm_pending_state_apply_sync(struct drm_pending_state *state);
1393
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001394/**
1395 * Mark a drm_output_state (the output's last state) as complete. This handles
1396 * any post-completion actions such as updating the repaint timer, disabling the
1397 * output, and finally freeing the state.
1398 */
1399static void
1400drm_output_update_complete(struct drm_output *output, uint32_t flags,
1401 unsigned int sec, unsigned int usec)
1402{
Daniel Stonea08512f2016-11-08 17:46:10 +00001403 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001404 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001405 struct timespec ts;
1406
1407 /* Stop the pageflip timer instead of rearming it here */
1408 if (output->pageflip_timer)
1409 wl_event_source_timer_update(output->pageflip_timer, 0);
1410
Daniel Stonebc15f682016-11-14 16:57:01 +00001411 wl_list_for_each(ps, &output->state_cur->plane_list, link)
1412 ps->complete = true;
1413
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001414 drm_output_state_free(output->state_last);
1415 output->state_last = NULL;
1416
1417 if (output->destroy_pending) {
Daniel Stonea08512f2016-11-08 17:46:10 +00001418 output->destroy_pending = 0;
1419 output->disable_pending = 0;
1420 output->dpms_off_pending = 0;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001421 drm_output_destroy(&output->base);
1422 return;
1423 } else if (output->disable_pending) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001424 output->disable_pending = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00001425 output->dpms_off_pending = 0;
1426 weston_output_disable(&output->base);
1427 return;
1428 } else if (output->dpms_off_pending) {
1429 struct drm_pending_state *pending = drm_pending_state_alloc(b);
1430 output->dpms_off_pending = 0;
1431 drm_output_get_disable_state(pending, output);
1432 drm_pending_state_apply_sync(pending);
1433 return;
1434 } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
1435 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
1436 /* DPMS can happen to us either in the middle of a repaint
1437 * cycle (when we have painted fresh content, only to throw it
1438 * away for DPMS off), or at any other random point. If the
1439 * latter is true, then we cannot go through finish_frame,
1440 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001441 return;
1442 }
1443
1444 ts.tv_sec = sec;
1445 ts.tv_nsec = usec * 1000;
1446 weston_output_finish_frame(&output->base, &ts, flags);
1447
1448 /* We can't call this from frame_notify, because the output's
1449 * repaint needed flag is cleared just after that */
1450 if (output->recorder)
1451 weston_output_schedule_repaint(&output->base);
1452}
1453
1454/**
1455 * Mark an output state as current on the output, i.e. it has been
1456 * submitted to the kernel. The mode argument determines whether this
1457 * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
1458 * or asynchronously (in which case we wait for events to complete).
1459 */
1460static void
1461drm_output_assign_state(struct drm_output_state *state,
1462 enum drm_state_apply_mode mode)
1463{
1464 struct drm_output *output = state->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00001465 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +00001466 struct drm_plane_state *plane_state;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001467
1468 assert(!output->state_last);
1469
1470 if (mode == DRM_STATE_APPLY_ASYNC)
1471 output->state_last = output->state_cur;
1472 else
1473 drm_output_state_free(output->state_cur);
1474
1475 wl_list_remove(&state->link);
1476 wl_list_init(&state->link);
1477 state->pending_state = NULL;
1478
1479 output->state_cur = state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001480
Daniel Stone598ee9d2016-11-16 11:55:20 +00001481 if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC)
1482 output->atomic_complete_pending = 1;
1483
Daniel Stonebc15f682016-11-14 16:57:01 +00001484 /* Replace state_cur on each affected plane with the new state, being
1485 * careful to dispose of orphaned (but only orphaned) previous state.
1486 * If the previous state is not orphaned (still has an output_state
1487 * attached), it will be disposed of by freeing the output_state. */
1488 wl_list_for_each(plane_state, &state->plane_list, link) {
1489 struct drm_plane *plane = plane_state->plane;
1490
1491 if (plane->state_cur && !plane->state_cur->output_state)
1492 drm_plane_state_free(plane->state_cur, true);
1493 plane->state_cur = plane_state;
1494
1495 if (mode != DRM_STATE_APPLY_ASYNC) {
1496 plane_state->complete = true;
1497 continue;
1498 }
1499
Daniel Stone598ee9d2016-11-16 11:55:20 +00001500 if (b->atomic_modeset)
1501 continue;
1502
Daniel Stonebc15f682016-11-14 16:57:01 +00001503 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
1504 output->vblank_pending++;
Daniel Stonee2e80132018-01-16 15:37:33 +00001505 else if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
1506 output->page_flip_pending = 1;
Daniel Stonebc15f682016-11-14 16:57:01 +00001507 }
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001508}
1509
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001510static int
1511drm_view_transform_supported(struct weston_view *ev)
1512{
1513 return !ev->transform.enabled ||
1514 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
1515}
1516
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001517static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001518drm_output_check_scanout_format(struct drm_output *output,
1519 struct weston_surface *es, struct gbm_bo *bo)
1520{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001521 uint32_t format;
1522 pixman_region32_t r;
1523
1524 format = gbm_bo_get_format(bo);
1525
Kristian Høgsberg3f97b342013-10-16 16:08:57 -07001526 if (format == GBM_FORMAT_ARGB8888) {
1527 /* We can scanout an ARGB buffer if the surface's
1528 * opaque region covers the whole output, but we have
1529 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -08001530 pixman_region32_init_rect(&r, 0, 0,
1531 output->base.width,
1532 output->base.height);
1533 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001534
1535 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001536 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001537
1538 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001539 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -07001540
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001541 if (output->gbm_format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -07001542 return format;
1543
1544 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +02001545}
1546
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001547static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001548drm_output_prepare_scanout_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001549 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001550{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001551 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02001552 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00001553 struct drm_plane *scanout_plane = output->scanout_plane;
1554 struct drm_plane_state *state;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001555 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001556 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001557 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001558 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001559
Daniel Stone90648872016-10-21 18:08:37 +01001560 /* Don't import buffers which span multiple outputs. */
1561 if (ev->output_mask != (1u << output->base.id))
1562 return NULL;
1563
Daniel Stone296d7a92016-10-21 18:05:37 +01001564 /* We use GBM to import buffers. */
1565 if (b->gbm == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001566 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001567
Daniel Stone296d7a92016-10-21 18:05:37 +01001568 if (buffer == NULL)
1569 return NULL;
Daniel Stone90648872016-10-21 18:08:37 +01001570 if (wl_shm_buffer_get(buffer->resource))
1571 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001572
1573 /* Make sure our view is exactly compatible with the output. */
1574 if (ev->geometry.x != output->base.x ||
1575 ev->geometry.y != output->base.y)
1576 return NULL;
Daniel Stone90648872016-10-21 18:08:37 +01001577 if (buffer->width != output->base.current_mode->width ||
1578 buffer->height != output->base.current_mode->height)
1579 return NULL;
1580
Daniel Stone296d7a92016-10-21 18:05:37 +01001581 if (ev->transform.enabled)
1582 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001583 if (ev->geometry.scissor_enabled)
1584 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001585 if (viewport->buffer.transform != output->base.transform)
1586 return NULL;
Daniel Stone90648872016-10-21 18:08:37 +01001587 if (viewport->buffer.scale != output->base.current_scale)
1588 return NULL;
1589 if (!drm_view_transform_supported(ev))
1590 return NULL;
1591
1592 if (ev->alpha != 1.0f)
1593 return NULL;
Daniel Stone296d7a92016-10-21 18:05:37 +01001594
Daniel Stonee2e80132018-01-16 15:37:33 +00001595 state = drm_output_state_get_plane(output_state, scanout_plane);
1596 if (state->fb) {
1597 /* If there is already a framebuffer on the scanout plane,
1598 * a client view has already been placed on the scanout
1599 * view. In that case, do not free or put back the state,
1600 * but just leave it in place and quietly exit. */
1601 return NULL;
1602 }
1603
Giulio Camuffo954f1832014-10-11 18:27:30 +03001604 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -07001605 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001606
Rob Bradford9b101872012-09-14 23:25:41 +01001607 /* Unable to use the buffer for scanout */
1608 if (!bo)
1609 return NULL;
1610
Jason Ekstranda7af7042013-10-12 22:38:11 -05001611 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05001612 if (format == 0) {
Daniel Stonee2e80132018-01-16 15:37:33 +00001613 drm_plane_state_put_back(state);
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +03001614 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001615 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +03001616 }
1617
Daniel Stonee2e80132018-01-16 15:37:33 +00001618 state->fb = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
1619 if (!state->fb) {
1620 drm_plane_state_put_back(state);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001621 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001622 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001623 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001624
Daniel Stonee2e80132018-01-16 15:37:33 +00001625 drm_fb_set_buffer(state->fb, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001626
Daniel Stonee2e80132018-01-16 15:37:33 +00001627 state->output = output;
1628
1629 state->src_x = 0;
1630 state->src_y = 0;
1631 state->src_w = state->fb->width << 16;
1632 state->src_h = state->fb->height << 16;
1633
1634 state->dest_x = 0;
1635 state->dest_y = 0;
1636 state->dest_w = output->base.current_mode->width;
1637 state->dest_h = output->base.current_mode->height;
1638
1639 return &scanout_plane->base;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -05001640}
1641
Daniel Stone95d48a22017-04-04 17:54:30 +01001642static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001643drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001644{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001645 struct drm_output *output = state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02001646 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001647 struct gbm_bo *bo;
Daniel Stone95d48a22017-04-04 17:54:30 +01001648 struct drm_fb *ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001649
Giulio Camuffo954f1832014-10-11 18:27:30 +03001650 output->base.compositor->renderer->repaint_output(&output->base,
1651 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001652
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001653 bo = gbm_surface_lock_front_buffer(output->gbm_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001654 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +02001655 weston_log("failed to lock front buffer: %m\n");
Daniel Stone95d48a22017-04-04 17:54:30 +01001656 return NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001657 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001658
Daniel Stone95d48a22017-04-04 17:54:30 +01001659 ret = drm_fb_get_from_bo(bo, b, output->gbm_format, BUFFER_GBM_SURFACE);
1660 if (!ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001661 weston_log("failed to get drm_fb for bo\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01001662 gbm_surface_release_buffer(output->gbm_surface, bo);
Daniel Stone95d48a22017-04-04 17:54:30 +01001663 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001664 }
Daniel Stone95d48a22017-04-04 17:54:30 +01001665 ret->gbm_surface = output->gbm_surface;
1666
1667 return ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001668}
1669
Daniel Stone95d48a22017-04-04 17:54:30 +01001670static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001671drm_output_render_pixman(struct drm_output_state *state,
1672 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001673{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001674 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001675 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001676
1677 output->current_image ^= 1;
1678
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001679 pixman_renderer_output_set_buffer(&output->base,
1680 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +02001681 pixman_renderer_output_set_hw_extra_damage(&output->base,
1682 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001683
Pekka Paalanenacf50c32018-04-23 11:44:56 +02001684 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001685
Pekka Paalanenacf50c32018-04-23 11:44:56 +02001686 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +01001687
1688 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001689}
1690
1691static void
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001692drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001693{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001694 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001695 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +00001696 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +00001697 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02001698 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +01001699 struct drm_fb *fb;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001700
Daniel Stone4e84f7d2017-04-04 17:54:29 +01001701 /* If we already have a client buffer promoted to scanout, then we don't
1702 * want to render. */
Daniel Stonee2e80132018-01-16 15:37:33 +00001703 scanout_state = drm_output_state_get_plane(state,
1704 output->scanout_plane);
1705 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +01001706 return;
1707
Daniel Stonee95169b2016-11-14 17:46:59 +00001708 if (!pixman_region32_not_empty(damage) &&
1709 scanout_plane->state_cur->fb &&
1710 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
1711 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
1712 scanout_plane->state_cur->fb->width ==
1713 output->base.current_mode->width &&
1714 scanout_plane->state_cur->fb->height ==
1715 output->base.current_mode->height) {
1716 fb = drm_fb_ref(scanout_plane->state_cur->fb);
1717 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001718 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00001719 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001720 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +00001721 }
Daniel Stone95d48a22017-04-04 17:54:30 +01001722
Daniel Stonee2e80132018-01-16 15:37:33 +00001723 if (!fb) {
1724 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +01001725 return;
Daniel Stonee2e80132018-01-16 15:37:33 +00001726 }
1727
1728 scanout_state->fb = fb;
1729 scanout_state->output = output;
1730
1731 scanout_state->src_x = 0;
1732 scanout_state->src_y = 0;
1733 scanout_state->src_w = output->base.current_mode->width << 16;
1734 scanout_state->src_h = output->base.current_mode->height << 16;
1735
1736 scanout_state->dest_x = 0;
1737 scanout_state->dest_y = 0;
1738 scanout_state->dest_w = scanout_state->src_w >> 16;
1739 scanout_state->dest_h = scanout_state->src_h >> 16;
1740
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001741
Giulio Camuffo954f1832014-10-11 18:27:30 +03001742 pixman_region32_subtract(&c->primary_plane.damage,
1743 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001744}
1745
1746static void
Richard Hughese7299962013-05-01 21:52:12 +01001747drm_output_set_gamma(struct weston_output *output_base,
1748 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
1749{
1750 int rc;
Armin Krezović545dba62016-08-05 15:54:18 +02001751 struct drm_output *output = to_drm_output(output_base);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001752 struct drm_backend *backend =
Armin Krezović545dba62016-08-05 15:54:18 +02001753 to_drm_backend(output->base.compositor);
Richard Hughese7299962013-05-01 21:52:12 +01001754
1755 /* check */
1756 if (output_base->gamma_size != size)
1757 return;
Richard Hughese7299962013-05-01 21:52:12 +01001758
Giulio Camuffo954f1832014-10-11 18:27:30 +03001759 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +01001760 output->crtc_id,
1761 size, r, g, b);
1762 if (rc)
1763 weston_log("set gamma failed: %m\n");
1764}
1765
Bryce Harringtonada4f072015-06-30 13:25:46 -07001766/* Determine the type of vblank synchronization to use for the output.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001767 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07001768 * The pipe parameter indicates which CRTC is in use. Knowing this, we
1769 * can determine which vblank sequence type to use for it. Traditional
1770 * cards had only two CRTCs, with CRTC 0 using no special flags, and
1771 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
1772 * parameter indicates this.
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02001773 *
Bryce Harringtonada4f072015-06-30 13:25:46 -07001774 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
1775 * 0-31. If this is non-zero it indicates we're dealing with a
1776 * multi-gpu situation and we need to calculate the vblank sync
1777 * using DRM_BLANK_HIGH_CRTC_MASK.
1778 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +03001779static unsigned int
1780drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02001781{
1782 if (output->pipe > 1)
1783 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
1784 DRM_VBLANK_HIGH_CRTC_MASK;
1785 else if (output->pipe > 0)
1786 return DRM_VBLANK_SECONDARY;
1787 else
1788 return 0;
1789}
1790
David Herrmann1edf44c2013-10-22 17:11:26 +02001791static int
Daniel Stone598ee9d2016-11-16 11:55:20 +00001792drm_output_apply_state_legacy(struct drm_output_state *state)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001793{
Daniel Stonea08512f2016-11-08 17:46:10 +00001794 struct drm_output *output = state->output;
1795 struct drm_backend *backend = to_drm_backend(output->base.compositor);
Daniel Stonee2e80132018-01-16 15:37:33 +00001796 struct drm_plane *scanout_plane = output->scanout_plane;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001797 struct drm_property_info *dpms_prop;
Daniel Stonee2e80132018-01-16 15:37:33 +00001798 struct drm_plane_state *scanout_state;
Daniel Stonebc15f682016-11-14 16:57:01 +00001799 struct drm_plane_state *ps;
Daniel Stone085d2b92015-05-21 00:00:57 +01001800 struct drm_plane *p;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001801 struct drm_mode *mode;
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001802 struct drm_head *head;
1803 uint32_t connectors[MAX_CLONED_CONNECTORS];
1804 int n_conn = 0;
Daniel Stonea08512f2016-11-08 17:46:10 +00001805 struct timespec now;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001806 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001807
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001808 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1809 assert(n_conn < MAX_CLONED_CONNECTORS);
1810 connectors[n_conn++] = head->connector_id;
1811 }
1812
Derek Foreman2cd87fe2017-04-13 13:48:48 -05001813 /* If disable_planes is set then assign_planes() wasn't
1814 * called for this render, so we could still have a stale
1815 * cursor plane set up.
1816 */
1817 if (output->base.disable_planes) {
1818 output->cursor_view = NULL;
Greg V1f781762018-02-19 17:59:42 +03001819 if (output->cursor_plane) {
1820 output->cursor_plane->base.x = INT32_MIN;
1821 output->cursor_plane->base.y = INT32_MIN;
1822 }
Derek Foreman2cd87fe2017-04-13 13:48:48 -05001823 }
1824
Daniel Stonea08512f2016-11-08 17:46:10 +00001825 if (state->dpms != WESTON_DPMS_ON) {
1826 wl_list_for_each(ps, &state->plane_list, link) {
1827 p = ps->plane;
1828 assert(ps->fb == NULL);
1829 assert(ps->output == NULL);
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001830
Daniel Stonea08512f2016-11-08 17:46:10 +00001831 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
1832 continue;
1833
1834 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
1835 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1836 if (ret)
1837 weston_log("drmModeSetPlane failed disable: %m\n");
1838 }
1839
1840 if (output->cursor_plane) {
1841 ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
1842 0, 0, 0);
1843 if (ret)
1844 weston_log("drmModeSetCursor failed disable: %m\n");
1845 }
1846
1847 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001848 NULL, 0, NULL);
Daniel Stonea08512f2016-11-08 17:46:10 +00001849 if (ret)
1850 weston_log("drmModeSetCrtc failed disabling: %m\n");
1851
1852 drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
1853 weston_compositor_read_presentation_clock(output->base.compositor, &now);
1854 drm_output_update_complete(output,
1855 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
1856 now.tv_sec, now.tv_nsec / 1000);
1857
1858 return 0;
1859 }
1860
1861 scanout_state =
1862 drm_output_state_get_existing_plane(state, scanout_plane);
Daniel Stone087ddf02017-02-14 17:51:30 +00001863
Daniel Stonee2e80132018-01-16 15:37:33 +00001864 /* The legacy SetCrtc API doesn't allow us to do scaling, and the
1865 * legacy PageFlip API doesn't allow us to do clipping either. */
1866 assert(scanout_state->src_x == 0);
1867 assert(scanout_state->src_y == 0);
1868 assert(scanout_state->src_w ==
1869 (unsigned) (output->base.current_mode->width << 16));
1870 assert(scanout_state->src_h ==
1871 (unsigned) (output->base.current_mode->height << 16));
1872 assert(scanout_state->dest_x == 0);
1873 assert(scanout_state->dest_y == 0);
1874 assert(scanout_state->dest_w == scanout_state->src_w >> 16);
1875 assert(scanout_state->dest_h == scanout_state->src_h >> 16);
1876
Daniel Stonecb04cc42016-11-16 11:51:27 +00001877 mode = to_drm_mode(output->base.current_mode);
Daniel Stone6020f472018-02-05 15:46:20 +00001878 if (backend->state_invalid || !scanout_plane->state_cur->fb ||
Daniel Stonee2e80132018-01-16 15:37:33 +00001879 scanout_plane->state_cur->fb->stride != scanout_state->fb->stride) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001880 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00001881 scanout_state->fb->fb_id,
1882 0, 0,
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001883 connectors, n_conn,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001884 &mode->mode_info);
1885 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001886 weston_log("set mode failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001887 goto err;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001888 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02001889 }
1890
Giulio Camuffo954f1832014-10-11 18:27:30 +03001891 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Daniel Stonee2e80132018-01-16 15:37:33 +00001892 scanout_state->fb->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05001893 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001894 weston_log("queueing pageflip failed: %m\n");
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001895 goto err;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -05001896 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +01001897
Daniel Stone205c0a02017-04-04 17:54:33 +01001898 assert(!output->page_flip_pending);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03001899
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001900 if (output->pageflip_timer)
1901 wl_event_source_timer_update(output->pageflip_timer,
1902 backend->pageflip_timeout);
1903
Daniel Stone2ba17f42015-05-19 20:02:41 +01001904 drm_output_set_cursor(state);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001905
Jesse Barnes58ef3792012-02-23 09:45:49 -05001906 /*
1907 * Now, update all the sprite surfaces
1908 */
Daniel Stonebc15f682016-11-14 16:57:01 +00001909 wl_list_for_each(ps, &state->plane_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001910 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001911 drmVBlank vbl = {
1912 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
1913 .request.sequence = 1,
1914 };
1915
Daniel Stonebc15f682016-11-14 16:57:01 +00001916 p = ps->plane;
Daniel Stone085d2b92015-05-21 00:00:57 +01001917 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001918 continue;
1919
Daniel Stonebc15f682016-11-14 16:57:01 +00001920 assert(p->state_cur->complete);
1921 assert(!!p->state_cur->output == !!p->state_cur->fb);
1922 assert(!p->state_cur->output || p->state_cur->output == output);
1923 assert(!ps->complete);
1924 assert(!ps->output || ps->output == output);
1925 assert(!!ps->output == !!ps->fb);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001926
Daniel Stonebc15f682016-11-14 16:57:01 +00001927 if (ps->fb && !backend->sprites_hidden)
1928 fb_id = ps->fb->fb_id;
Daniel Stone085d2b92015-05-21 00:00:57 +01001929
1930 ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001931 output->crtc_id, fb_id, flags,
Daniel Stonebc15f682016-11-14 16:57:01 +00001932 ps->dest_x, ps->dest_y,
1933 ps->dest_w, ps->dest_h,
1934 ps->src_x, ps->src_y,
1935 ps->src_w, ps->src_h);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001936 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +02001937 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001938 ret, strerror(errno));
1939
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +02001940 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -05001941
Jesse Barnes58ef3792012-02-23 09:45:49 -05001942 /*
1943 * Queue a vblank signal so we know when the surface
1944 * becomes active on the display or has been replaced.
1945 */
Daniel Stonebc15f682016-11-14 16:57:01 +00001946 vbl.request.signal = (unsigned long) ps;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001947 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001948 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001949 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001950 ret, strerror(errno));
1951 }
1952 }
1953
Pekka Paalanen02aeb5c2017-09-12 16:02:01 +03001954 if (state->dpms != output->state_cur->dpms) {
1955 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1956 dpms_prop = &head->props_conn[WDRM_CONNECTOR_DPMS];
1957 if (dpms_prop->prop_id == 0)
1958 continue;
1959
1960 ret = drmModeConnectorSetProperty(backend->drm.fd,
1961 head->connector_id,
1962 dpms_prop->prop_id,
1963 state->dpms);
1964 if (ret) {
1965 weston_log("DRM: DPMS: failed property set for %s\n",
1966 head->base.name);
1967 }
Daniel Stonea08512f2016-11-08 17:46:10 +00001968 }
1969 }
1970
1971 drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
1972
David Herrmann1edf44c2013-10-22 17:11:26 +02001973 return 0;
1974
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001975err:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -08001976 output->cursor_view = NULL;
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001977 drm_output_state_free(state);
Daniel Stonea08512f2016-11-08 17:46:10 +00001978 return -1;
1979}
David Herrmann1edf44c2013-10-22 17:11:26 +02001980
Daniel Stone598ee9d2016-11-16 11:55:20 +00001981#ifdef HAVE_DRM_ATOMIC
1982static int
1983crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
1984 enum wdrm_crtc_property prop, uint64_t val)
1985{
1986 struct drm_property_info *info = &output->props_crtc[prop];
1987 int ret;
1988
1989 if (info->prop_id == 0)
1990 return -1;
1991
1992 ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
1993 val);
1994 return (ret <= 0) ? -1 : 0;
1995}
1996
1997static int
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03001998connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
Daniel Stone598ee9d2016-11-16 11:55:20 +00001999 enum wdrm_connector_property prop, uint64_t val)
2000{
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002001 struct drm_property_info *info = &head->props_conn[prop];
Daniel Stone598ee9d2016-11-16 11:55:20 +00002002 int ret;
2003
2004 if (info->prop_id == 0)
2005 return -1;
2006
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002007 ret = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002008 info->prop_id, val);
2009 return (ret <= 0) ? -1 : 0;
2010}
2011
2012static int
2013plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
2014 enum wdrm_plane_property prop, uint64_t val)
2015{
2016 struct drm_property_info *info = &plane->props[prop];
2017 int ret;
2018
2019 if (info->prop_id == 0)
2020 return -1;
2021
2022 ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
2023 val);
2024 return (ret <= 0) ? -1 : 0;
2025}
2026
2027static int
2028drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
2029{
2030 int ret;
2031
2032 if (mode->blob_id)
2033 return 0;
2034
2035 ret = drmModeCreatePropertyBlob(backend->drm.fd,
2036 &mode->mode_info,
2037 sizeof(mode->mode_info),
2038 &mode->blob_id);
2039 if (ret != 0)
2040 weston_log("failed to create mode property blob: %m\n");
2041
2042 return ret;
2043}
2044
2045static int
2046drm_output_apply_state_atomic(struct drm_output_state *state,
2047 drmModeAtomicReq *req,
2048 uint32_t *flags)
2049{
2050 struct drm_output *output = state->output;
2051 struct drm_backend *backend = to_drm_backend(output->base.compositor);
2052 struct drm_plane_state *plane_state;
2053 struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002054 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002055 int ret = 0;
2056
2057 if (state->dpms != output->state_cur->dpms)
2058 *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2059
2060 if (state->dpms == WESTON_DPMS_ON) {
2061 ret = drm_mode_ensure_blob(backend, current_mode);
2062 if (ret != 0)
2063 return ret;
2064
2065 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
2066 current_mode->blob_id);
2067 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002068
2069 wl_list_for_each(head, &output->base.head_list, base.output_link) {
2070 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
2071 output->crtc_id);
2072 }
Daniel Stone598ee9d2016-11-16 11:55:20 +00002073 } else {
2074 ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
2075 ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
Pekka Paalanen2f661302017-09-12 16:07:32 +03002076
2077 wl_list_for_each(head, &output->base.head_list, base.output_link)
2078 ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002079 }
2080
2081 if (ret != 0) {
2082 weston_log("couldn't set atomic CRTC/connector state\n");
2083 return ret;
2084 }
2085
2086 wl_list_for_each(plane_state, &state->plane_list, link) {
2087 struct drm_plane *plane = plane_state->plane;
2088
2089 ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
2090 plane_state->fb ? plane_state->fb->fb_id : 0);
2091 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
2092 plane_state->fb ? output->crtc_id : 0);
2093 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
2094 plane_state->src_x);
2095 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
2096 plane_state->src_y);
2097 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
2098 plane_state->src_w);
2099 ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
2100 plane_state->src_h);
2101 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
2102 plane_state->dest_x);
2103 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
2104 plane_state->dest_y);
2105 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
2106 plane_state->dest_w);
2107 ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
2108 plane_state->dest_h);
2109
2110 if (ret != 0) {
2111 weston_log("couldn't set plane state\n");
2112 return ret;
2113 }
2114 }
2115
2116 return 0;
2117}
2118
2119/**
2120 * Helper function used only by drm_pending_state_apply, with the same
2121 * guarantees and constraints as that function.
2122 */
2123static int
2124drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
2125 enum drm_state_apply_mode mode)
2126{
2127 struct drm_backend *b = pending_state->backend;
2128 struct drm_output_state *output_state, *tmp;
2129 struct drm_plane *plane;
2130 drmModeAtomicReq *req = drmModeAtomicAlloc();
2131 uint32_t flags = 0;
2132 int ret = 0;
2133
2134 if (!req)
2135 return -1;
2136
2137 if (b->state_invalid) {
Pekka Paalaneneacec812017-09-12 13:43:51 +03002138 struct weston_head *head_base;
2139 struct drm_head *head;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002140 uint32_t *unused;
2141 int err;
2142
2143 /* If we need to reset all our state (e.g. because we've
2144 * just started, or just been VT-switched in), explicitly
2145 * disable all the CRTCs and connectors we aren't using. */
Pekka Paalaneneacec812017-09-12 13:43:51 +03002146 wl_list_for_each(head_base,
2147 &b->compositor->head_list, compositor_link) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00002148 struct drm_property_info *info;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002149
Pekka Paalaneneacec812017-09-12 13:43:51 +03002150 if (weston_head_is_enabled(head_base))
Daniel Stone598ee9d2016-11-16 11:55:20 +00002151 continue;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002152
Pekka Paalaneneacec812017-09-12 13:43:51 +03002153 head = to_drm_head(head_base);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002154
Pekka Paalaneneacec812017-09-12 13:43:51 +03002155 info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
2156 err = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002157 info->prop_id, 0);
2158 if (err <= 0)
2159 ret = -1;
2160
Pekka Paalaneneacec812017-09-12 13:43:51 +03002161 info = &head->props_conn[WDRM_CONNECTOR_DPMS];
Daniel Stone598ee9d2016-11-16 11:55:20 +00002162 if (info->prop_id > 0)
Pekka Paalaneneacec812017-09-12 13:43:51 +03002163 err = drmModeAtomicAddProperty(req, head->connector_id,
Daniel Stone598ee9d2016-11-16 11:55:20 +00002164 info->prop_id,
2165 DRM_MODE_DPMS_OFF);
2166 if (err <= 0)
2167 ret = -1;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002168 }
2169
2170 wl_array_for_each(unused, &b->unused_crtcs) {
2171 struct drm_property_info infos[WDRM_CRTC__COUNT];
2172 struct drm_property_info *info;
2173 drmModeObjectProperties *props;
2174 uint64_t active;
2175
2176 memset(infos, 0, sizeof(infos));
2177
2178 /* We can't emit a disable on a CRTC that's already
2179 * off, as the kernel will refuse to generate an event
2180 * for an off->off state and fail the commit.
2181 */
2182 props = drmModeObjectGetProperties(b->drm.fd,
2183 *unused,
2184 DRM_MODE_OBJECT_CRTC);
2185 if (!props) {
2186 ret = -1;
2187 continue;
2188 }
2189
2190 drm_property_info_populate(b, crtc_props, infos,
2191 WDRM_CRTC__COUNT,
2192 props);
2193
2194 info = &infos[WDRM_CRTC_ACTIVE];
2195 active = drm_property_get_value(info, props, 0);
2196 drmModeFreeObjectProperties(props);
2197 if (active == 0) {
2198 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2199 continue;
2200 }
2201
2202 err = drmModeAtomicAddProperty(req, *unused,
2203 info->prop_id, 0);
2204 if (err <= 0)
2205 ret = -1;
2206
2207 info = &infos[WDRM_CRTC_MODE_ID];
2208 err = drmModeAtomicAddProperty(req, *unused,
2209 info->prop_id, 0);
2210 if (err <= 0)
2211 ret = -1;
2212
2213 drm_property_info_free(infos, WDRM_CRTC__COUNT);
2214 }
2215
2216 /* Disable all the planes; planes which are being used will
2217 * override this state in the output-state application. */
2218 wl_list_for_each(plane, &b->plane_list, link) {
2219 plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
2220 plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
2221 }
2222
2223 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2224 }
2225
2226 wl_list_for_each(output_state, &pending_state->output_list, link) {
2227 if (mode == DRM_STATE_APPLY_SYNC)
2228 assert(output_state->dpms == WESTON_DPMS_OFF);
2229 ret |= drm_output_apply_state_atomic(output_state, req, &flags);
2230 }
2231
2232 if (ret != 0) {
2233 weston_log("atomic: couldn't compile atomic state\n");
2234 goto out;
2235 }
2236
2237 switch (mode) {
2238 case DRM_STATE_APPLY_SYNC:
2239 break;
2240 case DRM_STATE_APPLY_ASYNC:
2241 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
2242 break;
2243 }
2244
2245 ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
2246 if (ret != 0) {
2247 weston_log("atomic: couldn't commit new state: %m\n");
2248 goto out;
2249 }
2250
2251 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2252 link)
2253 drm_output_assign_state(output_state, mode);
2254
2255 b->state_invalid = false;
2256
2257 assert(wl_list_empty(&pending_state->output_list));
2258
2259out:
2260 drmModeAtomicFree(req);
2261 drm_pending_state_free(pending_state);
2262 return ret;
2263}
2264#endif
2265
Daniel Stonea08512f2016-11-08 17:46:10 +00002266/**
2267 * Applies all of a pending_state asynchronously: the primary entry point for
2268 * applying KMS state to a device. Updates the state for all outputs in the
2269 * pending_state, as well as disabling any unclaimed outputs.
2270 *
2271 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2272 */
2273static int
2274drm_pending_state_apply(struct drm_pending_state *pending_state)
2275{
2276 struct drm_backend *b = pending_state->backend;
2277 struct drm_output_state *output_state, *tmp;
2278 uint32_t *unused;
2279
Daniel Stone598ee9d2016-11-16 11:55:20 +00002280#ifdef HAVE_DRM_ATOMIC
2281 if (b->atomic_modeset)
2282 return drm_pending_state_apply_atomic(pending_state,
2283 DRM_STATE_APPLY_ASYNC);
2284#endif
2285
Daniel Stonea08512f2016-11-08 17:46:10 +00002286 if (b->state_invalid) {
2287 /* If we need to reset all our state (e.g. because we've
2288 * just started, or just been VT-switched in), explicitly
2289 * disable all the CRTCs we aren't using. This also disables
2290 * all connectors on these CRTCs, so we don't need to do that
2291 * separately with the pre-atomic API. */
2292 wl_array_for_each(unused, &b->unused_crtcs)
2293 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2294 NULL);
2295 }
2296
2297 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2298 link) {
2299 struct drm_output *output = output_state->output;
2300 int ret;
2301
Daniel Stone598ee9d2016-11-16 11:55:20 +00002302 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002303 if (ret != 0) {
2304 weston_log("Couldn't apply state for output %s\n",
2305 output->base.name);
2306 }
2307 }
2308
2309 b->state_invalid = false;
2310
2311 assert(wl_list_empty(&pending_state->output_list));
2312
2313 drm_pending_state_free(pending_state);
2314
2315 return 0;
2316}
2317
2318/**
2319 * The synchronous version of drm_pending_state_apply. May only be used to
2320 * disable outputs. Does so synchronously: the request is guaranteed to have
2321 * completed on return, and the output will not be touched afterwards.
2322 *
2323 * Unconditionally takes ownership of pending_state, and clears state_invalid.
2324 */
2325static int
2326drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
2327{
2328 struct drm_backend *b = pending_state->backend;
2329 struct drm_output_state *output_state, *tmp;
2330 uint32_t *unused;
2331
Daniel Stone598ee9d2016-11-16 11:55:20 +00002332#ifdef HAVE_DRM_ATOMIC
2333 if (b->atomic_modeset)
2334 return drm_pending_state_apply_atomic(pending_state,
2335 DRM_STATE_APPLY_SYNC);
2336#endif
2337
Daniel Stonea08512f2016-11-08 17:46:10 +00002338 if (b->state_invalid) {
2339 /* If we need to reset all our state (e.g. because we've
2340 * just started, or just been VT-switched in), explicitly
2341 * disable all the CRTCs we aren't using. This also disables
2342 * all connectors on these CRTCs, so we don't need to do that
2343 * separately with the pre-atomic API. */
2344 wl_array_for_each(unused, &b->unused_crtcs)
2345 drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2346 NULL);
2347 }
2348
2349 wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2350 link) {
2351 int ret;
2352
2353 assert(output_state->dpms == WESTON_DPMS_OFF);
Daniel Stone598ee9d2016-11-16 11:55:20 +00002354 ret = drm_output_apply_state_legacy(output_state);
Daniel Stonea08512f2016-11-08 17:46:10 +00002355 if (ret != 0) {
2356 weston_log("Couldn't apply state for output %s\n",
2357 output_state->output->base.name);
2358 }
2359 }
2360
2361 b->state_invalid = false;
2362
2363 assert(wl_list_empty(&pending_state->output_list));
2364
2365 drm_pending_state_free(pending_state);
2366
2367 return 0;
2368}
2369
2370static int
2371drm_output_repaint(struct weston_output *output_base,
2372 pixman_region32_t *damage,
2373 void *repaint_data)
2374{
2375 struct drm_pending_state *pending_state = repaint_data;
2376 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00002377 struct drm_output_state *state = NULL;
2378 struct drm_plane_state *scanout_state;
2379
2380 if (output->disable_pending || output->destroy_pending)
2381 goto err;
2382
2383 assert(!output->state_last);
2384
2385 /* If planes have been disabled in the core, we might not have
2386 * hit assign_planes at all, so might not have valid output state
2387 * here. */
2388 state = drm_pending_state_get_output(pending_state, output);
2389 if (!state)
2390 state = drm_output_state_duplicate(output->state_cur,
2391 pending_state,
2392 DRM_OUTPUT_STATE_CLEAR_PLANES);
2393 state->dpms = WESTON_DPMS_ON;
2394
2395 drm_output_render(state, damage);
2396 scanout_state = drm_output_state_get_plane(state,
2397 output->scanout_plane);
2398 if (!scanout_state || !scanout_state->fb)
2399 goto err;
2400
Daniel Stonea08512f2016-11-08 17:46:10 +00002401 return 0;
2402
2403err:
2404 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +02002405 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002406}
2407
2408static void
Jonas Ådahle5a12252013-04-05 23:07:11 +02002409drm_output_start_repaint_loop(struct weston_output *output_base)
2410{
Armin Krezović545dba62016-08-05 15:54:18 +02002411 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +00002412 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +00002413 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +02002414 struct drm_backend *backend =
2415 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002416 struct timespec ts, tnow;
2417 struct timespec vbl2now;
2418 int64_t refresh_nsec;
2419 int ret;
2420 drmVBlank vbl = {
2421 .request.type = DRM_VBLANK_RELATIVE,
2422 .request.sequence = 0,
2423 .request.signal = 0,
2424 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002425
Armin Krezović08368132016-09-30 14:11:05 +02002426 if (output->disable_pending || output->destroy_pending)
Xiong Zhangabd5d472013-10-11 14:43:07 +08002427 return;
2428
Daniel Stonee2e80132018-01-16 15:37:33 +00002429 if (!output->scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002430 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +02002431 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03002432 }
2433
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002434 /* Need to smash all state in from scratch; current timings might not
2435 * be what we want, page flip might not work, etc.
2436 */
Daniel Stone6020f472018-02-05 15:46:20 +00002437 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +03002438 goto finish_frame;
2439
Daniel Stonee2e80132018-01-16 15:37:33 +00002440 assert(scanout_plane->state_cur->output == output);
2441
Mario Kleinerf507ec32015-06-21 21:25:14 +02002442 /* Try to get current msc and timestamp via instant query */
2443 vbl.request.type |= drm_waitvblank_pipe(output);
2444 ret = drmWaitVBlank(backend->drm.fd, &vbl);
2445
2446 /* Error ret or zero timestamp means failure to get valid timestamp */
2447 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
2448 ts.tv_sec = vbl.reply.tval_sec;
2449 ts.tv_nsec = vbl.reply.tval_usec * 1000;
2450
2451 /* Valid timestamp for most recent vblank - not stale?
2452 * Stale ts could happen on Linux 3.17+, so make sure it
2453 * is not older than 1 refresh duration since now.
2454 */
2455 weston_compositor_read_presentation_clock(backend->compositor,
2456 &tnow);
2457 timespec_sub(&vbl2now, &tnow, &ts);
2458 refresh_nsec =
2459 millihz_to_nsec(output->base.current_mode->refresh);
2460 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
2461 drm_output_update_msc(output, vbl.reply.sequence);
2462 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002463 WP_PRESENTATION_FEEDBACK_INVALID);
Mario Kleinerf507ec32015-06-21 21:25:14 +02002464 return;
2465 }
2466 }
2467
2468 /* Immediate query didn't provide valid timestamp.
2469 * Use pageflip fallback.
2470 */
Jonas Ådahle5a12252013-04-05 23:07:11 +02002471
Daniel Stone205c0a02017-04-04 17:54:33 +01002472 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002473 assert(!output->state_last);
2474
2475 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +00002476 drm_output_state_duplicate(output->state_cur, pending_state,
2477 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +01002478
Daniel Stone8747f952016-11-29 20:17:32 +00002479 ret = drm_pending_state_apply(pending_state);
2480 if (ret != 0) {
2481 weston_log("applying repaint-start state failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +02002482 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +02002483 }
David Herrmann3c688c52013-10-22 17:11:25 +02002484
2485 return;
2486
2487finish_frame:
2488 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +00002489 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002490 WP_PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002491}
2492
2493static void
Pekka Paalanen641307c2014-09-23 22:08:47 -04002494drm_output_update_msc(struct drm_output *output, unsigned int seq)
2495{
2496 uint64_t msc_hi = output->base.msc >> 32;
2497
2498 if (seq < (output->base.msc & 0xffffffff))
2499 msc_hi++;
2500
2501 output->base.msc = (msc_hi << 32) + seq;
2502}
2503
2504static void
Jesse Barnes58ef3792012-02-23 09:45:49 -05002505vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
2506 void *data)
2507{
Daniel Stonebc15f682016-11-14 16:57:01 +00002508 struct drm_plane_state *ps = (struct drm_plane_state *) data;
2509 struct drm_output_state *os = ps->output_state;
2510 struct drm_output *output = os->output;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002511 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002512 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2513 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002514
Daniel Stone598ee9d2016-11-16 11:55:20 +00002515 assert(!b->atomic_modeset);
2516
Pekka Paalanen641307c2014-09-23 22:08:47 -04002517 drm_output_update_msc(output, frame);
Daniel Stone65d87d02017-04-04 17:54:32 +01002518 output->vblank_pending--;
2519 assert(output->vblank_pending >= 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002520
Daniel Stonebc15f682016-11-14 16:57:01 +00002521 assert(ps->fb);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +03002522
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002523 if (output->page_flip_pending || output->vblank_pending)
2524 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002525
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002526 drm_output_update_complete(output, flags, sec, usec);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002527}
2528
2529static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002530page_flip_handler(int fd, unsigned int frame,
2531 unsigned int sec, unsigned int usec, void *data)
2532{
Armin Krezović545dba62016-08-05 15:54:18 +02002533 struct drm_output *output = data;
Daniel Stone598ee9d2016-11-16 11:55:20 +00002534 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02002535 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2536 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2537 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002538
Pekka Paalanen641307c2014-09-23 22:08:47 -04002539 drm_output_update_msc(output, frame);
2540
Daniel Stone598ee9d2016-11-16 11:55:20 +00002541 assert(!b->atomic_modeset);
Daniel Stone205c0a02017-04-04 17:54:33 +01002542 assert(output->page_flip_pending);
Jonas Ådahle5a12252013-04-05 23:07:11 +02002543 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002544
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002545 if (output->vblank_pending)
2546 return;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00002547
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002548 drm_output_update_complete(output, flags, sec, usec);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +02002549}
2550
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002551/**
2552 * Begin a new repaint cycle
2553 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002554 * Called by the core compositor at the beginning of a repaint cycle. Creates
2555 * a new pending_state structure to own any output state created by individual
2556 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002557 */
2558static void *
2559drm_repaint_begin(struct weston_compositor *compositor)
2560{
2561 struct drm_backend *b = to_drm_backend(compositor);
2562 struct drm_pending_state *ret;
2563
2564 ret = drm_pending_state_alloc(b);
2565 b->repaint_data = ret;
2566
2567 return ret;
2568}
2569
2570/**
2571 * Flush a repaint set
2572 *
2573 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002574 * and should be flushed. Frees the pending state, transitioning ownership
2575 * of the output state from the pending state, to the update itself. When
2576 * the update completes (see drm_output_update_complete), the output
2577 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002578 */
2579static void
2580drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
2581{
2582 struct drm_backend *b = to_drm_backend(compositor);
2583 struct drm_pending_state *pending_state = repaint_data;
Daniel Stone6020f472018-02-05 15:46:20 +00002584
Daniel Stonea08512f2016-11-08 17:46:10 +00002585 drm_pending_state_apply(pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +00002586 b->repaint_data = NULL;
2587}
2588
2589/**
2590 * Cancel a repaint set
2591 *
2592 * Called by the core compositor when a repaint has finished, so the data
2593 * held across the repaint cycle should be discarded.
2594 */
2595static void
2596drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
2597{
2598 struct drm_backend *b = to_drm_backend(compositor);
2599 struct drm_pending_state *pending_state = repaint_data;
2600
2601 drm_pending_state_free(pending_state);
2602 b->repaint_data = NULL;
2603}
2604
Daniel Stone598ee9d2016-11-16 11:55:20 +00002605#ifdef HAVE_DRM_ATOMIC
2606static void
2607atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
2608 unsigned int usec, unsigned int crtc_id, void *data)
2609{
2610 struct drm_backend *b = data;
2611 struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
2612 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2613 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2614 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
2615
2616 /* During the initial modeset, we can disable CRTCs which we don't
2617 * actually handle during normal operation; this will give us events
2618 * for unknown outputs. Ignore them. */
2619 if (!output || !output->base.enabled)
2620 return;
2621
2622 drm_output_update_msc(output, frame);
2623
2624 assert(b->atomic_modeset);
2625 assert(output->atomic_complete_pending);
2626 output->atomic_complete_pending = 0;
2627
2628 drm_output_update_complete(output, flags, sec, usec);
2629}
2630#endif
2631
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05002632static uint32_t
Daniel Stone08d4edf2017-04-04 17:54:34 +01002633drm_output_check_plane_format(struct drm_plane *p,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002634 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002635{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05002636 uint32_t i, format;
2637
2638 format = gbm_bo_get_format(bo);
2639
2640 if (format == GBM_FORMAT_ARGB8888) {
2641 pixman_region32_t r;
2642
Kristian Høgsberg63093a32013-03-01 14:29:16 -05002643 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002644 ev->surface->width,
2645 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002646 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05002647
2648 if (!pixman_region32_not_empty(&r))
2649 format = GBM_FORMAT_XRGB8888;
2650
2651 pixman_region32_fini(&r);
2652 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002653
Daniel Stone08d4edf2017-04-04 17:54:34 +01002654 for (i = 0; i < p->count_formats; i++)
2655 if (p->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -05002656 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002657
2658 return 0;
2659}
2660
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002661static struct weston_plane *
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002662drm_output_prepare_overlay_view(struct drm_output_state *output_state,
Jason Ekstranda7af7042013-10-12 22:38:11 -05002663 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002664{
Daniel Stone7b2ddac2016-11-11 19:11:49 +00002665 struct drm_output *output = output_state->output;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002666 struct weston_compositor *ec = output->base.compositor;
Armin Krezović545dba62016-08-05 15:54:18 +02002667 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanen952b6c82014-03-14 14:38:15 +02002668 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002669 struct wl_resource *buffer_resource;
Daniel Stone08d4edf2017-04-04 17:54:34 +01002670 struct drm_plane *p;
Daniel Stonebc15f682016-11-14 16:57:01 +00002671 struct drm_plane_state *state = NULL;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002672 struct linux_dmabuf_buffer *dmabuf;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002673 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002674 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02002675 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002676 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04002677 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002678
Giulio Camuffo954f1832014-10-11 18:27:30 +03002679 if (b->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002680 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -05002681
Daniel Stone296d7a92016-10-21 18:05:37 +01002682 /* Don't import buffers which span multiple outputs. */
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002683 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002684 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +03002685
Daniel Stone296d7a92016-10-21 18:05:37 +01002686 /* We can only import GBM buffers. */
2687 if (b->gbm == NULL)
2688 return NULL;
2689
Jason Ekstranda7af7042013-10-12 22:38:11 -05002690 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002691 return NULL;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002692 buffer_resource = ev->surface->buffer_ref.buffer->resource;
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002693 if (wl_shm_buffer_get(buffer_resource))
Rob Clark702ffae2012-08-09 14:18:27 -05002694 return NULL;
2695
Daniel Stone296d7a92016-10-21 18:05:37 +01002696 if (viewport->buffer.transform != output->base.transform)
2697 return NULL;
2698 if (viewport->buffer.scale != output->base.current_scale)
2699 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05002700 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002701 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002702
Daniel Stone296d7a92016-10-21 18:05:37 +01002703 if (ev->alpha != 1.0f)
2704 return NULL;
2705
Daniel Stone085d2b92015-05-21 00:00:57 +01002706 wl_list_for_each(p, &b->plane_list, link) {
2707 if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2708 continue;
2709
Daniel Stone5ff289a2017-10-07 12:59:02 +01002710 if (!drm_plane_is_available(p, output))
Daniel Stonebc15f682016-11-14 16:57:01 +00002711 continue;
2712
2713 state = drm_output_state_get_plane(output_state, p);
2714 if (state->fb) {
2715 state = NULL;
2716 continue;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002717 }
Daniel Stonebc15f682016-11-14 16:57:01 +00002718
2719 break;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002720 }
2721
2722 /* No sprites available */
Daniel Stonebc15f682016-11-14 16:57:01 +00002723 if (!state)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002724 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002725
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002726 if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) {
Bryce Harringtona3582072015-08-14 12:23:13 -07002727#ifdef HAVE_GBM_FD_IMPORT
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002728 /* XXX: TODO:
2729 *
2730 * Use AddFB2 directly, do not go via GBM.
2731 * Add support for multiplanar formats.
2732 * Both require refactoring in the DRM-backend to
2733 * support a mix of gbm_bos and drmfbs.
2734 */
2735 struct gbm_import_fd_data gbm_dmabuf = {
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +00002736 .fd = dmabuf->attributes.fd[0],
2737 .width = dmabuf->attributes.width,
2738 .height = dmabuf->attributes.height,
2739 .stride = dmabuf->attributes.stride[0],
2740 .format = dmabuf->attributes.format
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002741 };
2742
Micah Fedkec8890122017-02-01 15:28:23 -05002743 /* XXX: TODO:
2744 *
2745 * Currently the buffer is rejected if any dmabuf attribute
2746 * flag is set. This keeps us from passing an inverted /
2747 * interlaced / bottom-first buffer (or any other type that may
2748 * be added in the future) through to an overlay. Ultimately,
2749 * these types of buffers should be handled through buffer
2750 * transforms and not as spot-checks requiring specific
2751 * knowledge. */
2752 if (dmabuf->attributes.n_planes != 1 ||
2753 dmabuf->attributes.offset[0] != 0 ||
2754 dmabuf->attributes.flags)
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002755 return NULL;
2756
2757 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
2758 GBM_BO_USE_SCANOUT);
Bryce Harringtona3582072015-08-14 12:23:13 -07002759#else
Daniel Stonebc15f682016-11-14 16:57:01 +00002760 goto err;
Bryce Harringtona3582072015-08-14 12:23:13 -07002761#endif
Pekka Paalanenbf8cc6f2014-06-12 17:12:12 +03002762 } else {
2763 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
2764 buffer_resource, GBM_BO_USE_SCANOUT);
2765 }
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -04002766 if (!bo)
Daniel Stonebc15f682016-11-14 16:57:01 +00002767 goto err;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -04002768
Daniel Stone08d4edf2017-04-04 17:54:34 +01002769 format = drm_output_check_plane_format(p, ev, bo);
Daniel Stonebc15f682016-11-14 16:57:01 +00002770 if (format == 0)
2771 goto err;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002772
Daniel Stonebc15f682016-11-14 16:57:01 +00002773 state->fb = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
2774 if (!state->fb)
2775 goto err;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002776
Daniel Stonebc15f682016-11-14 16:57:01 +00002777 drm_fb_set_buffer(state->fb, ev->surface->buffer_ref.buffer);
2778
2779 state->output = output;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002780
Jason Ekstranda7af7042013-10-12 22:38:11 -05002781 box = pixman_region32_extents(&ev->transform.boundingbox);
Daniel Stone08d4edf2017-04-04 17:54:34 +01002782 p->base.x = box->x1;
2783 p->base.y = box->y1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002784
Jesse Barnes58ef3792012-02-23 09:45:49 -05002785 /*
2786 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -05002787 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -05002788 * for us already).
2789 */
2790 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002791 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002792 &output->base.region);
2793 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002794 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002795 tbox = weston_transformed_rect(output->base.width,
2796 output->base.height,
2797 output->base.transform,
2798 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002799 *box);
Daniel Stonebc15f682016-11-14 16:57:01 +00002800 state->dest_x = tbox.x1;
2801 state->dest_y = tbox.y1;
2802 state->dest_w = tbox.x2 - tbox.x1;
2803 state->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002804 pixman_region32_fini(&dest_rect);
2805
2806 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05002807 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02002808 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002809 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04002810
Jason Ekstranda7af7042013-10-12 22:38:11 -05002811 weston_view_from_global_fixed(ev,
2812 wl_fixed_from_int(box->x1),
2813 wl_fixed_from_int(box->y1),
2814 &sx1, &sy1);
2815 weston_view_from_global_fixed(ev,
2816 wl_fixed_from_int(box->x2),
2817 wl_fixed_from_int(box->y2),
2818 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04002819
2820 if (sx1 < 0)
2821 sx1 = 0;
2822 if (sy1 < 0)
2823 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002824 if (sx2 > wl_fixed_from_int(ev->surface->width))
2825 sx2 = wl_fixed_from_int(ev->surface->width);
2826 if (sy2 > wl_fixed_from_int(ev->surface->height))
2827 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04002828
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02002829 tbox.x1 = sx1;
2830 tbox.y1 = sy1;
2831 tbox.x2 = sx2;
2832 tbox.y2 = sy2;
2833
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06002834 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
2835 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +02002836 viewport->buffer.transform,
2837 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01002838 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02002839
Daniel Stonebc15f682016-11-14 16:57:01 +00002840 state->src_x = tbox.x1 << 8;
2841 state->src_y = tbox.y1 << 8;
2842 state->src_w = (tbox.x2 - tbox.x1) << 8;
2843 state->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002844 pixman_region32_fini(&src_rect);
2845
Daniel Stone08d4edf2017-04-04 17:54:34 +01002846 return &p->base;
Daniel Stonebc15f682016-11-14 16:57:01 +00002847
2848err:
2849 drm_plane_state_put_back(state);
2850 if (bo)
2851 gbm_bo_destroy(bo);
2852 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002853}
2854
Pekka Paalanend0ead482014-06-16 12:05:40 +03002855/**
2856 * Update the image for the current cursor surface
2857 *
2858 * @param b DRM backend structure
2859 * @param bo GBM buffer object to write into
2860 * @param ev View to use for cursor image
2861 */
2862static void
2863cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
2864 struct weston_view *ev)
2865{
2866 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
2867 uint32_t buf[b->cursor_width * b->cursor_height];
2868 int32_t stride;
2869 uint8_t *s;
2870 int i;
2871
2872 assert(buffer && buffer->shm_buffer);
2873 assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
2874 assert(ev->surface->width <= b->cursor_width);
2875 assert(ev->surface->height <= b->cursor_height);
2876
2877 memset(buf, 0, sizeof buf);
2878 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
2879 s = wl_shm_buffer_get_data(buffer->shm_buffer);
2880
2881 wl_shm_buffer_begin_access(buffer->shm_buffer);
2882 for (i = 0; i < ev->surface->height; i++)
2883 memcpy(buf + i * b->cursor_width,
2884 s + i * stride,
2885 ev->surface->width * 4);
2886 wl_shm_buffer_end_access(buffer->shm_buffer);
2887
2888 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
2889 weston_log("failed update cursor: %m\n");
2890}
2891
Daniel Stone2ba17f42015-05-19 20:02:41 +01002892static struct weston_plane *
2893drm_output_prepare_cursor_view(struct drm_output_state *output_state,
2894 struct weston_view *ev)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04002895{
Daniel Stone2ba17f42015-05-19 20:02:41 +01002896 struct drm_output *output = output_state->output;
Armin Krezović545dba62016-08-05 15:54:18 +02002897 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stone2ba17f42015-05-19 20:02:41 +01002898 struct drm_plane *plane = output->cursor_plane;
2899 struct drm_plane_state *plane_state;
2900 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
2901 struct wl_shm_buffer *shmbuf;
2902 bool needs_update = false;
Derek Foremanbe428b32015-11-24 11:39:38 -06002903 float x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05002904
Daniel Stone2ba17f42015-05-19 20:02:41 +01002905 if (!plane)
2906 return NULL;
2907
2908 if (b->cursors_are_broken)
2909 return NULL;
2910
2911 if (!plane->state_cur->complete)
2912 return NULL;
2913
2914 if (plane->state_cur->output && plane->state_cur->output != output)
2915 return NULL;
2916
2917 /* Don't import buffers which span multiple outputs. */
2918 if (ev->output_mask != (1u << output->base.id))
2919 return NULL;
2920
2921 /* We use GBM to import SHM buffers. */
2922 if (b->gbm == NULL)
2923 return NULL;
2924
2925 if (ev->surface->buffer_ref.buffer == NULL)
2926 return NULL;
2927 shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
2928 if (!shmbuf)
2929 return NULL;
2930 if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)
2931 return NULL;
2932
2933 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
2934 return NULL;
2935 if (ev->transform.enabled &&
2936 (ev->transform.matrix.type > WESTON_MATRIX_TRANSFORM_TRANSLATE))
2937 return NULL;
2938 if (viewport->buffer.scale != output->base.current_scale)
2939 return NULL;
2940 if (ev->geometry.scissor_enabled)
2941 return NULL;
2942
2943 if (ev->surface->width > b->cursor_width ||
2944 ev->surface->height > b->cursor_height)
2945 return NULL;
2946
2947 plane_state =
2948 drm_output_state_get_plane(output_state, output->cursor_plane);
2949
2950 if (plane_state && plane_state->fb)
2951 return NULL;
2952
2953 /* Since we're setting plane state up front, we need to work out
2954 * whether or not we need to upload a new cursor. We can't use the
2955 * plane damage, since the planes haven't actually been calculated
2956 * yet: instead try to figure it out directly. KMS cursor planes are
2957 * pretty unique here, in that they lie partway between a Weston plane
2958 * (direct scanout) and a renderer. */
2959 if (ev != output->cursor_view ||
2960 pixman_region32_not_empty(&ev->surface->damage)) {
2961 output->current_cursor++;
2962 output->current_cursor =
2963 output->current_cursor %
2964 ARRAY_LENGTH(output->gbm_cursor_fb);
2965 needs_update = true;
2966 }
2967
2968 output->cursor_view = ev;
2969 weston_view_to_global_float(ev, 0, 0, &x, &y);
2970 plane->base.x = x;
2971 plane->base.y = y;
2972
2973 plane_state->fb =
2974 drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
2975 plane_state->output = output;
2976 plane_state->src_x = 0;
2977 plane_state->src_y = 0;
2978 plane_state->src_w = b->cursor_width << 16;
2979 plane_state->src_h = b->cursor_height << 16;
2980 plane_state->dest_x = (x - output->base.x) * output->base.current_scale;
2981 plane_state->dest_y = (y - output->base.y) * output->base.current_scale;
2982 plane_state->dest_w = b->cursor_width;
2983 plane_state->dest_h = b->cursor_height;
2984
2985 if (needs_update)
2986 cursor_bo_update(b, plane_state->fb->bo, ev);
2987
2988 return &plane->base;
2989}
2990
2991static void
2992drm_output_set_cursor(struct drm_output_state *output_state)
2993{
2994 struct drm_output *output = output_state->output;
2995 struct drm_backend *b = to_drm_backend(output->base.compositor);
2996 struct drm_plane *plane = output->cursor_plane;
2997 struct drm_plane_state *state;
2998 EGLint handle;
2999 struct gbm_bo *bo;
3000
3001 if (!plane)
3002 return;
3003
3004 state = drm_output_state_get_existing_plane(output_state, plane);
3005 if (!state)
3006 return;
3007
3008 if (!state->fb) {
3009 pixman_region32_fini(&plane->base.damage);
3010 pixman_region32_init(&plane->base.damage);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003011 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04003012 return;
3013 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003014
Daniel Stone2ba17f42015-05-19 20:02:41 +01003015 assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
3016 assert(!plane->state_cur->output || plane->state_cur->output == output);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003017
Daniel Stone2ba17f42015-05-19 20:02:41 +01003018 if (plane->state_cur->fb != state->fb) {
3019 bo = state->fb->bo;
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04003020 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03003021 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
Daniel Stone2ba17f42015-05-19 20:02:41 +01003022 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03003023 weston_log("failed to set cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01003024 goto err;
Rob Clarkab5b1e32012-08-09 13:24:45 -05003025 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003026 }
3027
Daniel Stone2ba17f42015-05-19 20:02:41 +01003028 pixman_region32_fini(&plane->base.damage);
3029 pixman_region32_init(&plane->base.damage);
Pekka Paalanen7eaed402015-11-27 14:20:58 +02003030
Daniel Stone2ba17f42015-05-19 20:02:41 +01003031 if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
3032 state->dest_x, state->dest_y)) {
Daniel Stonea7cba1d2017-04-04 17:54:21 +01003033 weston_log("failed to move cursor: %m\n");
Daniel Stone2ba17f42015-05-19 20:02:41 +01003034 goto err;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04003035 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003036
3037 return;
3038
3039err:
3040 b->cursors_are_broken = 1;
3041 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05003042}
3043
Jesse Barnes58ef3792012-02-23 09:45:49 -05003044static void
Daniel Stoneb1f166d2017-03-01 11:34:10 +00003045drm_assign_planes(struct weston_output *output_base, void *repaint_data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05003046{
Armin Krezović545dba62016-08-05 15:54:18 +02003047 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003048 struct drm_pending_state *pending_state = repaint_data;
Armin Krezović545dba62016-08-05 15:54:18 +02003049 struct drm_output *output = to_drm_output(output_base);
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003050 struct drm_output_state *state;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003051 struct drm_plane_state *plane_state;
Daniel Stonec3fcb5b2016-12-01 12:33:54 +00003052 struct weston_view *ev;
Daniel Stone115ed2c2016-11-08 21:19:22 +00003053 pixman_region32_t surface_overlap, renderer_region;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003054 struct weston_plane *primary, *next_plane;
Matt Hoosierdf573032017-08-24 09:24:20 -05003055 bool picked_scanout = false;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003056
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003057 assert(!output->state_last);
3058 state = drm_output_state_duplicate(output->state_cur,
3059 pending_state,
3060 DRM_OUTPUT_STATE_CLEAR_PLANES);
3061
Jesse Barnes58ef3792012-02-23 09:45:49 -05003062 /*
3063 * Find a surface for each sprite in the output using some heuristics:
3064 * 1) size
3065 * 2) frequency of update
3066 * 3) opacity (though some hw might support alpha blending)
3067 * 4) clipping (this can be fixed with color keys)
3068 *
3069 * The idea is to save on blitting since this should save power.
3070 * If we can get a large video surface on the sprite for example,
3071 * the main display surface may not need to update at all, and
3072 * the client buffer can be used directly for the sprite surface
3073 * as we do for flipping full screen surfaces.
3074 */
Daniel Stone115ed2c2016-11-08 21:19:22 +00003075 pixman_region32_init(&renderer_region);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003076 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05003077
Daniel Stonec3fcb5b2016-12-01 12:33:54 +00003078 wl_list_for_each(ev, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02003079 struct weston_surface *es = ev->surface;
3080
3081 /* Test whether this buffer can ever go into a plane:
3082 * non-shm, or small enough to be a cursor.
3083 *
3084 * Also, keep a reference when using the pixman renderer.
3085 * That makes it possible to do a seamless switch to the GL
3086 * renderer and since the pixman renderer keeps a reference
3087 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02003088 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003089 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02003090 (es->buffer_ref.buffer &&
3091 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Derek Foreman87430472015-10-15 10:24:48 -05003092 (ev->surface->width <= b->cursor_width &&
3093 ev->surface->height <= b->cursor_height))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05003094 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02003095 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05003096 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02003097
Jesse Barnes58ef3792012-02-23 09:45:49 -05003098 pixman_region32_init(&surface_overlap);
Daniel Stone115ed2c2016-11-08 21:19:22 +00003099 pixman_region32_intersect(&surface_overlap, &renderer_region,
Jason Ekstranda7af7042013-10-12 22:38:11 -05003100 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003101
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003102 next_plane = NULL;
Matt Hoosierdf573032017-08-24 09:24:20 -05003103 if (pixman_region32_not_empty(&surface_overlap) || picked_scanout)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003104 next_plane = primary;
3105 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003106 next_plane = drm_output_prepare_cursor_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05003107
3108 /* If a higher-stacked view already got assigned to scanout, it's incorrect to
3109 * assign a subsequent (lower-stacked) view to scanout.
3110 */
3111 if (next_plane == NULL) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003112 next_plane = drm_output_prepare_scanout_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05003113 if (next_plane)
3114 picked_scanout = true;
3115 }
3116
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003117 if (next_plane == NULL)
Daniel Stone7b2ddac2016-11-11 19:11:49 +00003118 next_plane = drm_output_prepare_overlay_view(state, ev);
Matt Hoosierdf573032017-08-24 09:24:20 -05003119
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003120 if (next_plane == NULL)
3121 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003122
Jason Ekstranda7af7042013-10-12 22:38:11 -05003123 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003124
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04003125 if (next_plane == primary)
Daniel Stone115ed2c2016-11-08 21:19:22 +00003126 pixman_region32_union(&renderer_region,
3127 &renderer_region,
Jason Ekstranda7af7042013-10-12 22:38:11 -05003128 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04003129
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003130 if (next_plane == primary ||
Daniel Stone2ba17f42015-05-19 20:02:41 +01003131 (output->cursor_plane &&
3132 next_plane == &output->cursor_plane->base)) {
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003133 /* cursor plane involves a copy */
3134 ev->psf_flags = 0;
3135 } else {
3136 /* All other planes are a direct scanout of a
3137 * single client buffer.
3138 */
Pekka Paalanenb00c79b2016-02-18 16:53:27 +02003139 ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02003140 }
3141
Jesse Barnes58ef3792012-02-23 09:45:49 -05003142 pixman_region32_fini(&surface_overlap);
3143 }
Daniel Stone115ed2c2016-11-08 21:19:22 +00003144 pixman_region32_fini(&renderer_region);
Daniel Stone2ba17f42015-05-19 20:02:41 +01003145
3146 /* We rely on output->cursor_view being both an accurate reflection of
3147 * the cursor plane's state, but also being maintained across repaints
3148 * to avoid unnecessary damage uploads, per the comment in
3149 * drm_output_prepare_cursor_view. In the event that we go from having
3150 * a cursor view to not having a cursor view, we need to clear it. */
3151 if (output->cursor_view) {
3152 plane_state =
3153 drm_output_state_get_existing_plane(state,
3154 output->cursor_plane);
3155 if (!plane_state || !plane_state->fb)
3156 output->cursor_view = NULL;
3157 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05003158}
3159
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003160/**
3161 * Find the closest-matching mode for a given target
3162 *
3163 * Given a target mode, find the most suitable mode amongst the output's
3164 * current mode list to use, preferring the current mode if possible, to
3165 * avoid an expensive mode switch.
3166 *
3167 * @param output DRM output
3168 * @param target_mode Mode to attempt to match
3169 * @returns Pointer to a mode from the output's mode list
3170 */
Alex Wub7b8bda2012-04-17 17:20:48 +08003171static struct drm_mode *
3172choose_mode (struct drm_output *output, struct weston_mode *target_mode)
3173{
3174 struct drm_mode *tmp_mode = NULL, *mode;
3175
Hardeningff39efa2013-09-18 23:56:35 +02003176 if (output->base.current_mode->width == target_mode->width &&
3177 output->base.current_mode->height == target_mode->height &&
3178 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08003179 target_mode->refresh == 0))
Daniel Stonecb04cc42016-11-16 11:51:27 +00003180 return to_drm_mode(output->base.current_mode);
Alex Wub7b8bda2012-04-17 17:20:48 +08003181
3182 wl_list_for_each(mode, &output->base.mode_list, base.link) {
3183 if (mode->mode_info.hdisplay == target_mode->width &&
3184 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02003185 if (mode->base.refresh == target_mode->refresh ||
3186 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08003187 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01003188 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08003189 tmp_mode = mode;
3190 }
3191 }
3192
3193 return tmp_mode;
3194}
3195
3196static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003197drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003198static void
3199drm_output_fini_egl(struct drm_output *output);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003200static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003201drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +00003202static void
3203drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003204
3205static int
Alex Wub7b8bda2012-04-17 17:20:48 +08003206drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
3207{
Daniel Stone02d487a2017-10-07 14:01:45 +01003208 struct drm_output *output = to_drm_output(output_base);
3209 struct drm_backend *b = to_drm_backend(output_base->compositor);
3210 struct drm_mode *drm_mode = choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +08003211
3212 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +01003213 weston_log("%s: invalid resolution %dx%d\n",
3214 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08003215 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003216 }
3217
Hardeningff39efa2013-09-18 23:56:35 +02003218 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08003219 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003220
Hardeningff39efa2013-09-18 23:56:35 +02003221 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003222
Hardeningff39efa2013-09-18 23:56:35 +02003223 output->base.current_mode = &drm_mode->base;
3224 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08003225 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
3226
Daniel Stonef30a18c2017-04-04 17:54:31 +01003227 /* XXX: This drops our current buffer too early, before we've started
3228 * displaying it. Ideally this should be much more atomic and
3229 * integrated with a full repaint cycle, rather than doing a
3230 * sledgehammer modeswitch first, and only later showing new
3231 * content.
3232 */
Daniel Stone6020f472018-02-05 15:46:20 +00003233 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +08003234
Giulio Camuffo954f1832014-10-11 18:27:30 +03003235 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003236 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003237 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003238 weston_log("failed to init output pixman state with "
3239 "new mode\n");
3240 return -1;
3241 }
3242 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +00003243 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003244 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003245 weston_log("failed to init output egl state with "
3246 "new mode");
3247 return -1;
3248 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02003249 }
3250
Alex Wub7b8bda2012-04-17 17:20:48 +08003251 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08003252}
3253
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003254static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003255on_drm_input(int fd, uint32_t mask, void *data)
3256{
Daniel Stone598ee9d2016-11-16 11:55:20 +00003257#ifdef HAVE_DRM_ATOMIC
3258 struct drm_backend *b = data;
3259#endif
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003260 drmEventContext evctx;
3261
3262 memset(&evctx, 0, sizeof evctx);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003263#ifndef HAVE_DRM_ATOMIC
Emil Velikov863e66b2017-04-04 18:07:34 +01003264 evctx.version = 2;
Daniel Stone598ee9d2016-11-16 11:55:20 +00003265#else
3266 evctx.version = 3;
3267 if (b->atomic_modeset)
3268 evctx.page_flip_handler2 = atomic_flip_handler;
3269 else
3270#endif
3271 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05003272 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003273 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04003274
3275 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003276}
3277
3278static int
Daniel Stoneefa504f2016-12-19 16:48:20 +00003279init_kms_caps(struct drm_backend *b)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003280{
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003281 uint64_t cap;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003282 int ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003283 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003284
Daniel Stoneefa504f2016-12-19 16:48:20 +00003285 weston_log("using %s\n", b->drm.filename);
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04003286
Daniel Stoneefa504f2016-12-19 16:48:20 +00003287 ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003288 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003289 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03003290 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003291 clk_id = CLOCK_REALTIME;
3292
Giulio Camuffo954f1832014-10-11 18:27:30 +03003293 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04003294 weston_log("Error: failed to set presentation clock %d.\n",
3295 clk_id);
3296 return -1;
3297 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02003298
Daniel Stoneefa504f2016-12-19 16:48:20 +00003299 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003300 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003301 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003302 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003303 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003304
Daniel Stoneefa504f2016-12-19 16:48:20 +00003305 ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003306 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003307 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003308 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03003309 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03003310
Daniel Stonebe1090b2017-09-06 17:29:57 +01003311 if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
3312 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
3313 b->universal_planes = (ret == 0);
3314 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003315 weston_log("DRM: %s universal planes\n",
3316 b->universal_planes ? "supports" : "does not support");
3317
Pekka Paalanencd011a62016-11-15 22:07:49 +00003318#ifdef HAVE_DRM_ATOMIC
3319 if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
Daniel Stone598ee9d2016-11-16 11:55:20 +00003320 ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
3321 if (ret != 0)
3322 cap = 0;
Pekka Paalanencd011a62016-11-15 22:07:49 +00003323 ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
Daniel Stone598ee9d2016-11-16 11:55:20 +00003324 b->atomic_modeset = ((ret == 0) && (cap == 1));
Pekka Paalanencd011a62016-11-15 22:07:49 +00003325 }
3326#endif
3327 weston_log("DRM: %s atomic modesetting\n",
3328 b->atomic_modeset ? "supports" : "does not support");
3329
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003330 return 0;
3331}
3332
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003333static struct gbm_device *
3334create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003335{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003336 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01003337
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003338 gl_renderer = weston_load_module("gl-renderer.so",
3339 "gl_renderer_interface");
3340 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003341 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003342
3343 /* GBM will load a dri driver, but even though they need symbols from
3344 * libglapi, in some version of Mesa they are not linked to it. Since
3345 * only the gl-renderer module links to it, the call above won't make
3346 * these symbols globally available, and loading the DRI driver fails.
3347 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
3348 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
3349
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003350 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003351
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003352 return gbm;
3353}
3354
Bryce Harringtonc056a982015-05-19 15:25:18 -07003355/* When initializing EGL, if the preferred buffer format isn't available
Bryce Harringtonb9939982016-04-15 20:28:26 -07003356 * we may be able to substitute an ARGB format for an XRGB one.
Derek Foremanc4cfe852015-05-15 12:12:40 -05003357 *
3358 * This returns 0 if substitution isn't possible, but 0 might be a
3359 * legitimate format for other EGL platforms, so the caller is
3360 * responsible for checking for 0 before calling gl_renderer->create().
3361 *
3362 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
3363 * but it's entirely possible we'll see this again on other implementations.
3364 */
3365static int
3366fallback_format_for(uint32_t format)
3367{
3368 switch (format) {
3369 case GBM_FORMAT_XRGB8888:
3370 return GBM_FORMAT_ARGB8888;
3371 case GBM_FORMAT_XRGB2101010:
3372 return GBM_FORMAT_ARGB2101010;
3373 default:
3374 return 0;
3375 }
3376}
3377
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003378static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003379drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003380{
Derek Foreman6d556372015-11-04 14:47:33 -06003381 EGLint format[3] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01003382 b->gbm_format,
3383 fallback_format_for(b->gbm_format),
Derek Foreman6d556372015-11-04 14:47:33 -06003384 0,
Derek Foremanc4cfe852015-05-15 12:12:40 -05003385 };
Derek Foreman6d556372015-11-04 14:47:33 -06003386 int n_formats = 2;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01003387
Derek Foremanc4cfe852015-05-15 12:12:40 -05003388 if (format[1])
Derek Foreman6d556372015-11-04 14:47:33 -06003389 n_formats = 3;
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003390 if (gl_renderer->display_create(b->compositor,
3391 EGL_PLATFORM_GBM_KHR,
3392 (void *)b->gbm,
Miguel A. Vico41700e32016-05-18 17:47:59 +02003393 NULL,
Miguel A. Vicodddc6702016-05-18 17:41:07 +02003394 gl_renderer->opaque_attribs,
3395 format,
3396 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003397 return -1;
3398 }
3399
3400 return 0;
3401}
3402
3403static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003404init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003405{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003406 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003407
Giulio Camuffo954f1832014-10-11 18:27:30 +03003408 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02003409 return -1;
3410
Giulio Camuffo954f1832014-10-11 18:27:30 +03003411 if (drm_backend_create_gl_renderer(b) < 0) {
3412 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04003413 return -1;
3414 }
3415
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003416 return 0;
3417}
3418
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003419static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03003420init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003421{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003422 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003423}
3424
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003425/**
Pekka Paalanenec272712014-06-05 11:22:25 +03003426 * Create a drm_plane for a hardware plane
3427 *
3428 * Creates one drm_plane structure for a hardware plane, and initialises its
3429 * properties and formats.
3430 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003431 * In the absence of universal plane support, where KMS does not explicitly
3432 * expose the primary and cursor planes to userspace, this may also create
3433 * an 'internal' plane for internal management.
3434 *
Pekka Paalanenec272712014-06-05 11:22:25 +03003435 * This function does not add the plane to the list of usable planes in Weston
3436 * itself; the caller is responsible for this.
3437 *
3438 * Call drm_plane_destroy to clean up the plane.
3439 *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003440 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +03003441 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +01003442 * @param kplane DRM plane to create, or NULL if creating internal plane
3443 * @param output Output to create internal plane for, or NULL
3444 * @param type Type to use when creating internal plane, or invalid
3445 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +03003446 */
3447static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +01003448drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
3449 struct drm_output *output, enum wdrm_plane_type type,
3450 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +03003451{
3452 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003453 drmModeObjectProperties *props;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003454 int num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003455
Daniel Stone2ba17f42015-05-19 20:02:41 +01003456 plane = zalloc(sizeof(*plane) +
3457 (sizeof(uint32_t) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +03003458 if (!plane) {
3459 weston_log("%s: out of memory\n", __func__);
3460 return NULL;
3461 }
3462
3463 plane->backend = b;
Daniel Stonebc15f682016-11-14 16:57:01 +00003464 plane->state_cur = drm_plane_state_alloc(NULL, plane);
3465 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +03003466
Daniel Stone2ba17f42015-05-19 20:02:41 +01003467 if (kplane) {
3468 plane->possible_crtcs = kplane->possible_crtcs;
3469 plane->plane_id = kplane->plane_id;
3470 plane->count_formats = kplane->count_formats;
3471 memcpy(plane->formats, kplane->formats,
3472 kplane->count_formats * sizeof(kplane->formats[0]));
3473
3474 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
3475 DRM_MODE_OBJECT_PLANE);
3476 if (!props) {
3477 weston_log("couldn't get plane properties\n");
3478 goto err;
3479 }
3480 drm_property_info_populate(b, plane_props, plane->props,
3481 WDRM_PLANE__COUNT, props);
3482 plane->type =
3483 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
3484 props,
3485 WDRM_PLANE_TYPE__COUNT);
3486 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003487 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01003488 else {
3489 plane->possible_crtcs = (1 << output->pipe);
3490 plane->plane_id = 0;
3491 plane->count_formats = 1;
3492 plane->formats[0] = format;
3493 plane->type = type;
3494 }
3495
3496 if (plane->type == WDRM_PLANE_TYPE__COUNT)
3497 goto err_props;
3498
3499 /* With universal planes, everything is a DRM plane; without
3500 * universal planes, the only DRM planes are overlay planes.
3501 * Everything else is a fake plane. */
3502 if (b->universal_planes) {
3503 assert(kplane);
3504 } else {
3505 if (kplane)
3506 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
3507 else
3508 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
3509 output);
3510 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003511
Pekka Paalanenec272712014-06-05 11:22:25 +03003512 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01003513 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +03003514
3515 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003516
3517err_props:
3518 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
3519err:
3520 drm_plane_state_free(plane->state_cur, true);
3521 free(plane);
3522 return NULL;
3523}
3524
3525/**
3526 * Find, or create, a special-purpose plane
3527 *
3528 * Primary and cursor planes are a special case, in that before universal
3529 * planes, they are driven by non-plane API calls. Without universal plane
3530 * support, the only way to configure a primary plane is via drmModeSetCrtc,
3531 * and the only way to configure a cursor plane is drmModeSetCursor2.
3532 *
3533 * Although they may actually be regular planes in the hardware, without
3534 * universal plane support, these planes are not actually exposed to
3535 * userspace in the regular plane list.
3536 *
3537 * However, for ease of internal tracking, we want to manage all planes
3538 * through the same drm_plane structures. Therefore, when we are running
3539 * without universal plane support, we create fake drm_plane structures
3540 * to track these planes.
3541 *
3542 * @param b DRM backend
3543 * @param output Output to use for plane
3544 * @param type Type of plane
3545 */
3546static struct drm_plane *
3547drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
3548 enum wdrm_plane_type type)
3549{
3550 struct drm_plane *plane;
3551
3552 if (!b->universal_planes) {
3553 uint32_t format;
3554
3555 switch (type) {
3556 case WDRM_PLANE_TYPE_CURSOR:
3557 format = GBM_FORMAT_ARGB8888;
3558 break;
Daniel Stonee2e80132018-01-16 15:37:33 +00003559 case WDRM_PLANE_TYPE_PRIMARY:
3560 /* We don't know what formats the primary plane supports
3561 * before universal planes, so we just assume that the
3562 * GBM format works; however, this isn't set until after
3563 * the output is created. */
3564 format = 0;
3565 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +01003566 default:
3567 assert(!"invalid type in drm_output_find_special_plane");
3568 break;
3569 }
3570
3571 return drm_plane_create(b, NULL, output, type, format);
3572 }
3573
3574 wl_list_for_each(plane, &b->plane_list, link) {
3575 struct drm_output *tmp;
3576 bool found_elsewhere = false;
3577
3578 if (plane->type != type)
3579 continue;
3580 if (!drm_plane_is_available(plane, output))
3581 continue;
3582
3583 /* On some platforms, primary/cursor planes can roam
3584 * between different CRTCs, so make sure we don't claim the
3585 * same plane for two outputs. */
Daniel Stone2ba17f42015-05-19 20:02:41 +01003586 wl_list_for_each(tmp, &b->compositor->output_list,
3587 base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +00003588 if (tmp->cursor_plane == plane ||
3589 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +01003590 found_elsewhere = true;
3591 break;
3592 }
3593 }
3594
3595 if (found_elsewhere)
3596 continue;
3597
3598 plane->possible_crtcs = (1 << output->pipe);
3599 return plane;
3600 }
3601
3602 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +03003603}
3604
3605/**
3606 * Destroy one DRM plane
3607 *
3608 * Destroy a DRM plane, removing it from screen and releasing its retained
3609 * buffers in the process. The counterpart to drm_plane_create.
3610 *
3611 * @param plane Plane to deallocate (will be freed)
3612 */
3613static void
3614drm_plane_destroy(struct drm_plane *plane)
3615{
Daniel Stone2ba17f42015-05-19 20:02:41 +01003616 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
3617 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
3618 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +00003619 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +01003620 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +03003621 weston_plane_release(&plane->base);
3622 wl_list_remove(&plane->link);
3623 free(plane);
3624}
3625
3626/**
3627 * Initialise sprites (overlay planes)
3628 *
3629 * Walk the list of provided DRM planes, and add overlay planes.
3630 *
3631 * Call destroy_sprites to free these planes.
3632 *
3633 * @param b DRM compositor backend
3634 */
3635static void
3636create_sprites(struct drm_backend *b)
3637{
3638 drmModePlaneRes *kplane_res;
3639 drmModePlane *kplane;
3640 struct drm_plane *drm_plane;
3641 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +03003642 kplane_res = drmModeGetPlaneResources(b->drm.fd);
3643 if (!kplane_res) {
3644 weston_log("failed to get plane resources: %s\n",
3645 strerror(errno));
3646 return;
3647 }
3648
3649 for (i = 0; i < kplane_res->count_planes; i++) {
3650 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
3651 if (!kplane)
3652 continue;
3653
Daniel Stone2ba17f42015-05-19 20:02:41 +01003654 drm_plane = drm_plane_create(b, kplane, NULL,
3655 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +03003656 drmModeFreePlane(kplane);
3657 if (!drm_plane)
3658 continue;
3659
Daniel Stone085d2b92015-05-21 00:00:57 +01003660 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
3661 weston_compositor_stack_plane(b->compositor,
3662 &drm_plane->base,
3663 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +03003664 }
3665
3666 drmModeFreePlaneResources(kplane_res);
3667}
3668
3669/**
3670 * Clean up sprites (overlay planes)
3671 *
3672 * The counterpart to create_sprites.
3673 *
3674 * @param b DRM compositor backend
3675 */
3676static void
3677destroy_sprites(struct drm_backend *b)
3678{
3679 struct drm_plane *plane, *next;
3680
Daniel Stone085d2b92015-05-21 00:00:57 +01003681 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03003682 drm_plane_destroy(plane);
3683}
3684
Pekka Paalanendc14fd42017-11-10 15:31:39 +02003685static uint32_t
3686drm_refresh_rate_mHz(const drmModeModeInfo *info)
3687{
3688 uint64_t refresh;
3689
3690 /* Calculate higher precision (mHz) refresh rate */
3691 refresh = (info->clock * 1000000LL / info->htotal +
3692 info->vtotal / 2) / info->vtotal;
3693
3694 if (info->flags & DRM_MODE_FLAG_INTERLACE)
3695 refresh *= 2;
3696 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
3697 refresh /= 2;
3698 if (info->vscan > 1)
3699 refresh /= info->vscan;
3700
3701 return refresh;
3702}
3703
Pekka Paalanenec272712014-06-05 11:22:25 +03003704/**
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003705 * Add a mode to output's mode list
3706 *
3707 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
3708 * output's mode list.
3709 *
3710 * @param output DRM output to add mode to
3711 * @param info DRM mode structure to add
3712 * @returns Newly-allocated Weston/DRM mode structure
3713 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003714static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03003715drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003716{
3717 struct drm_mode *mode;
3718
3719 mode = malloc(sizeof *mode);
3720 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003721 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003722
3723 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02003724 mode->base.width = info->hdisplay;
3725 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04003726
Pekka Paalanendc14fd42017-11-10 15:31:39 +02003727 mode->base.refresh = drm_refresh_rate_mHz(info);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003728 mode->mode_info = *info;
Daniel Stoned5526cb2016-11-16 10:54:10 +00003729 mode->blob_id = 0;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003730
3731 if (info->type & DRM_MODE_TYPE_PREFERRED)
3732 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
3733
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003734 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
3735
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03003736 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003737}
3738
Daniel Stoned5526cb2016-11-16 10:54:10 +00003739/**
3740 * Destroys a mode, and removes it from the list.
3741 */
3742static void
3743drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
3744{
3745 if (mode->blob_id)
3746 drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
3747 wl_list_remove(&mode->base.link);
3748 free(mode);
3749}
3750
Pekka Paalanen383b3af2017-09-11 14:40:48 +03003751/** Destroy a list of drm_modes
3752 *
3753 * @param backend The backend for releasing mode property blobs.
3754 * @param mode_list The list linked by drm_mode::base.link.
3755 */
3756static void
3757drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
3758{
3759 struct drm_mode *mode, *next;
3760
3761 wl_list_for_each_safe(mode, next, mode_list, base.link)
3762 drm_output_destroy_mode(backend, mode);
3763}
3764
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04003765static int
3766drm_subpixel_to_wayland(int drm_value)
3767{
3768 switch (drm_value) {
3769 default:
3770 case DRM_MODE_SUBPIXEL_UNKNOWN:
3771 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
3772 case DRM_MODE_SUBPIXEL_NONE:
3773 return WL_OUTPUT_SUBPIXEL_NONE;
3774 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
3775 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
3776 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
3777 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
3778 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
3779 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
3780 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
3781 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
3782 }
3783}
3784
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003785/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003786static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +03003787drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003788{
3789 long brightness, max_brightness, norm;
3790
Pekka Paalanence724242017-09-04 12:21:24 +03003791 brightness = backlight_get_brightness(head->backlight);
3792 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003793
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003794 /* convert it on a scale of 0 to 255 */
3795 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003796
3797 return (uint32_t) norm;
3798}
3799
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03003800/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003801static void
3802drm_set_backlight(struct weston_output *output_base, uint32_t value)
3803{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03003804 struct drm_output *output = to_drm_output(output_base);
3805 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003806 long max_brightness, new_brightness;
3807
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04003808 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003809 return;
3810
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03003811 wl_list_for_each(head, &output->base.head_list, base.output_link) {
3812 if (!head->backlight)
3813 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003814
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03003815 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003816
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03003817 /* get denormalized value */
3818 new_brightness = (value * max_brightness) / 255;
3819
3820 backlight_set_brightness(head->backlight, new_brightness);
3821 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003822}
3823
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02003824static void
3825drm_output_init_backlight(struct drm_output *output)
3826{
3827 struct weston_head *base;
3828 struct drm_head *head;
3829
3830 output->base.set_backlight = NULL;
3831
3832 wl_list_for_each(base, &output->base.head_list, output_link) {
3833 head = to_drm_head(base);
3834
3835 if (head->backlight) {
3836 weston_log("Initialized backlight for head '%s', device %s\n",
3837 head->base.name, head->backlight->path);
3838
3839 if (!output->base.set_backlight) {
3840 output->base.set_backlight = drm_set_backlight;
3841 output->base.backlight_current =
3842 drm_get_backlight(head);
3843 }
3844 }
3845 }
3846
3847 if (!output->base.set_backlight) {
3848 weston_log("No backlight control for output '%s'\n",
3849 output->base.name);
3850 }
3851}
3852
Daniel Stonea08512f2016-11-08 17:46:10 +00003853/**
3854 * Power output on or off
3855 *
3856 * The DPMS/power level of an output is used to switch it on or off. This
3857 * is DRM's hook for doing so, which can called either as part of repaint,
3858 * or independently of the repaint loop.
3859 *
3860 * If we are called as part of repaint, we simply set the relevant bit in
3861 * state and return.
3862 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003863static void
3864drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
3865{
Armin Krezović545dba62016-08-05 15:54:18 +02003866 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00003867 struct drm_backend *b = to_drm_backend(output_base->compositor);
3868 struct drm_pending_state *pending_state = b->repaint_data;
3869 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01003870 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003871
Daniel Stonea08512f2016-11-08 17:46:10 +00003872 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003873 return;
3874
Daniel Stonea08512f2016-11-08 17:46:10 +00003875 /* If we're being called during the repaint loop, then this is
3876 * simple: discard any previously-generated state, and create a new
3877 * state where we disable everything. When we come to flush, this
3878 * will be applied.
3879 *
3880 * However, we need to be careful: we can be called whilst another
3881 * output is in its repaint cycle (pending_state exists), but our
3882 * output still has an incomplete state application outstanding.
3883 * In that case, we need to wait until that completes. */
3884 if (pending_state && !output->state_last) {
3885 /* The repaint loop already sets DPMS on; we don't need to
3886 * explicitly set it on here, as it will already happen
3887 * whilst applying the repaint state. */
3888 if (level == WESTON_DPMS_ON)
3889 return;
3890
3891 state = drm_pending_state_get_output(pending_state, output);
3892 if (state)
3893 drm_output_state_free(state);
3894 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01003895 return;
3896 }
3897
Daniel Stonea08512f2016-11-08 17:46:10 +00003898 /* As we throw everything away when disabling, just send us back through
3899 * a repaint cycle. */
3900 if (level == WESTON_DPMS_ON) {
3901 if (output->dpms_off_pending)
3902 output->dpms_off_pending = 0;
3903 weston_output_schedule_repaint(output_base);
3904 return;
3905 }
3906
3907 /* If we've already got a request in the pipeline, then we need to
3908 * park our DPMS request until that request has quiesced. */
3909 if (output->state_last) {
3910 output->dpms_off_pending = 1;
3911 return;
3912 }
3913
3914 pending_state = drm_pending_state_alloc(b);
3915 drm_output_get_disable_state(pending_state, output);
3916 ret = drm_pending_state_apply_sync(pending_state);
3917 if (ret != 0)
3918 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02003919}
3920
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003921static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03003922 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
3923 [DRM_MODE_CONNECTOR_VGA] = "VGA",
3924 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
3925 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
3926 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
3927 [DRM_MODE_CONNECTOR_Composite] = "Composite",
3928 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
3929 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
3930 [DRM_MODE_CONNECTOR_Component] = "Component",
3931 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
3932 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
3933 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
3934 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
3935 [DRM_MODE_CONNECTOR_TV] = "TV",
3936 [DRM_MODE_CONNECTOR_eDP] = "eDP",
Pekka Paalanenab81f152015-08-24 14:27:07 +03003937#ifdef DRM_MODE_CONNECTOR_DSI
Pekka Paalanen89c49b32015-08-19 15:25:57 +03003938 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
3939 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Pekka Paalanenab81f152015-08-24 14:27:07 +03003940#endif
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04003941};
3942
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003943/** Create a name given a DRM connector
3944 *
3945 * \param con The DRM connector whose type and id form the name.
3946 * \return A newly allocate string, or NULL on error. Must be free()'d
3947 * after use.
3948 *
3949 * The name does not identify the DRM display device.
3950 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003951static char *
3952make_connector_name(const drmModeConnector *con)
3953{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003954 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03003955 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003956 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003957
3958 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
3959 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03003960
3961 if (!type_name)
3962 type_name = "UNNAMED";
3963
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003964 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
3965 if (ret < 0)
3966 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003967
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03003968 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03003969}
3970
Daniel Stonee4256832017-04-04 17:54:27 +01003971static void drm_output_fini_cursor_egl(struct drm_output *output)
3972{
3973 unsigned int i;
3974
3975 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
3976 drm_fb_unref(output->gbm_cursor_fb[i]);
3977 output->gbm_cursor_fb[i] = NULL;
3978 }
3979}
3980
3981static int
3982drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
3983{
3984 unsigned int i;
3985
Daniel Stone2ba17f42015-05-19 20:02:41 +01003986 /* No point creating cursors if we don't have a plane for them. */
3987 if (!output->cursor_plane)
3988 return 0;
3989
Daniel Stonee4256832017-04-04 17:54:27 +01003990 for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
3991 struct gbm_bo *bo;
3992
3993 bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
3994 GBM_FORMAT_ARGB8888,
3995 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
3996 if (!bo)
3997 goto err;
3998
3999 output->gbm_cursor_fb[i] =
4000 drm_fb_get_from_bo(bo, b, GBM_FORMAT_ARGB8888,
4001 BUFFER_CURSOR);
4002 if (!output->gbm_cursor_fb[i]) {
4003 gbm_bo_destroy(bo);
4004 goto err;
4005 }
4006 }
4007
4008 return 0;
4009
4010err:
4011 weston_log("cursor buffers unavailable, using gl cursors\n");
4012 b->cursors_are_broken = 1;
4013 drm_output_fini_cursor_egl(output);
4014 return -1;
4015}
4016
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004017/* Init output state that depends on gl or gbm */
4018static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004019drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004020{
Derek Foremanc4cfe852015-05-15 12:12:40 -05004021 EGLint format[2] = {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004022 output->gbm_format,
4023 fallback_format_for(output->gbm_format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05004024 };
Daniel Stonee4256832017-04-04 17:54:27 +01004025 int n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004026
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004027 output->gbm_surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02004028 output->base.current_mode->width,
4029 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05004030 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004031 GBM_BO_USE_SCANOUT |
4032 GBM_BO_USE_RENDERING);
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004033 if (!output->gbm_surface) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004034 weston_log("failed to create gbm surface\n");
4035 return -1;
4036 }
4037
Derek Foremanc4cfe852015-05-15 12:12:40 -05004038 if (format[1])
4039 n_formats = 2;
Miguel A. Vicoc095cde2016-05-18 17:43:00 +02004040 if (gl_renderer->output_window_create(&output->base,
4041 (EGLNativeWindowType)output->gbm_surface,
4042 output->gbm_surface,
4043 gl_renderer->opaque_attribs,
4044 format,
4045 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02004046 weston_log("failed to create gl renderer output state\n");
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01004047 gbm_surface_destroy(output->gbm_surface);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004048 return -1;
4049 }
4050
Daniel Stonee4256832017-04-04 17:54:27 +01004051 drm_output_init_cursor_egl(output, b);
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02004052
4053 return 0;
4054}
4055
Daniel Stone3e661f72016-11-04 17:24:06 +00004056static void
4057drm_output_fini_egl(struct drm_output *output)
4058{
Daniel Stonee2e80132018-01-16 15:37:33 +00004059 struct drm_backend *b = to_drm_backend(output->base.compositor);
4060
4061 /* Destroying the GBM surface will destroy all our GBM buffers,
4062 * regardless of refcount. Ensure we destroy them here. */
4063 if (!b->shutting_down &&
4064 output->scanout_plane->state_cur->fb &&
4065 output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
4066 drm_plane_state_free(output->scanout_plane->state_cur, true);
4067 output->scanout_plane->state_cur =
4068 drm_plane_state_alloc(NULL, output->scanout_plane);
4069 output->scanout_plane->state_cur->complete = true;
4070 }
4071
Daniel Stone3e661f72016-11-04 17:24:06 +00004072 gl_renderer->output_destroy(&output->base);
4073 gbm_surface_destroy(output->gbm_surface);
Daniel Stonee4256832017-04-04 17:54:27 +01004074 drm_output_fini_cursor_egl(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00004075}
4076
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04004077static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03004078drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004079{
Hardeningff39efa2013-09-18 23:56:35 +02004080 int w = output->base.current_mode->width;
4081 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004082 uint32_t format = output->gbm_format;
4083 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004084 unsigned int i;
4085
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004086 switch (format) {
4087 case GBM_FORMAT_XRGB8888:
4088 pixman_format = PIXMAN_x8r8g8b8;
4089 break;
4090 case GBM_FORMAT_RGB565:
4091 pixman_format = PIXMAN_r5g6b5;
4092 break;
4093 default:
4094 weston_log("Unsupported pixman format 0x%x\n", format);
4095 return -1;
4096 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004097
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004098 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004099 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004100 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004101 if (!output->dumb[i])
4102 goto err;
4103
4104 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03004105 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004106 output->dumb[i]->map,
4107 output->dumb[i]->stride);
4108 if (!output->image[i])
4109 goto err;
4110 }
4111
4112 if (pixman_renderer_output_create(&output->base) < 0)
4113 goto err;
4114
4115 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02004116 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004117
4118 return 0;
4119
4120err:
4121 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
4122 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01004123 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004124 if (output->image[i])
4125 pixman_image_unref(output->image[i]);
4126
4127 output->dumb[i] = NULL;
4128 output->image[i] = NULL;
4129 }
4130
4131 return -1;
4132}
4133
4134static void
4135drm_output_fini_pixman(struct drm_output *output)
4136{
Daniel Stonee2e80132018-01-16 15:37:33 +00004137 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004138 unsigned int i;
4139
Daniel Stonee2e80132018-01-16 15:37:33 +00004140 /* Destroying the Pixman surface will destroy all our buffers,
4141 * regardless of refcount. Ensure we destroy them here. */
4142 if (!b->shutting_down &&
4143 output->scanout_plane->state_cur->fb &&
4144 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
4145 drm_plane_state_free(output->scanout_plane->state_cur, true);
4146 output->scanout_plane->state_cur =
4147 drm_plane_state_alloc(NULL, output->scanout_plane);
4148 output->scanout_plane->state_cur->complete = true;
4149 }
4150
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004151 pixman_renderer_output_destroy(&output->base);
4152 pixman_region32_fini(&output->previous_damage);
4153
4154 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004155 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01004156 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004157 output->dumb[i] = NULL;
4158 output->image[i] = NULL;
4159 }
4160}
4161
Richard Hughes2b2092a2013-04-24 14:58:02 +01004162static void
4163edid_parse_string(const uint8_t *data, char text[])
4164{
4165 int i;
4166 int replaced = 0;
4167
4168 /* this is always 12 bytes, but we can't guarantee it's null
4169 * terminated or not junk. */
4170 strncpy(text, (const char *) data, 12);
4171
Bryce Harrington9c7de162015-08-28 13:04:26 -07004172 /* guarantee our new string is null-terminated */
4173 text[12] = '\0';
4174
Richard Hughes2b2092a2013-04-24 14:58:02 +01004175 /* remove insane chars */
4176 for (i = 0; text[i] != '\0'; i++) {
4177 if (text[i] == '\n' ||
4178 text[i] == '\r') {
4179 text[i] = '\0';
4180 break;
4181 }
4182 }
4183
4184 /* ensure string is printable */
4185 for (i = 0; text[i] != '\0'; i++) {
4186 if (!isprint(text[i])) {
4187 text[i] = '-';
4188 replaced++;
4189 }
4190 }
4191
4192 /* if the string is random junk, ignore the string */
4193 if (replaced > 4)
4194 text[0] = '\0';
4195}
4196
4197#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
4198#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
4199#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
4200#define EDID_OFFSET_DATA_BLOCKS 0x36
4201#define EDID_OFFSET_LAST_BLOCK 0x6c
4202#define EDID_OFFSET_PNPID 0x08
4203#define EDID_OFFSET_SERIAL 0x0c
4204
4205static int
4206edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
4207{
4208 int i;
4209 uint32_t serial_number;
4210
4211 /* check header */
4212 if (length < 128)
4213 return -1;
4214 if (data[0] != 0x00 || data[1] != 0xff)
4215 return -1;
4216
4217 /* decode the PNP ID from three 5 bit words packed into 2 bytes
4218 * /--08--\/--09--\
4219 * 7654321076543210
4220 * |\---/\---/\---/
4221 * R C1 C2 C3 */
4222 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
4223 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
4224 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
4225 edid->pnp_id[3] = '\0';
4226
4227 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
4228 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
4229 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
4230 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
4231 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
4232 if (serial_number > 0)
4233 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
4234
4235 /* parse EDID data */
4236 for (i = EDID_OFFSET_DATA_BLOCKS;
4237 i <= EDID_OFFSET_LAST_BLOCK;
4238 i += 18) {
4239 /* ignore pixel clock data */
4240 if (data[i] != 0)
4241 continue;
4242 if (data[i+2] != 0)
4243 continue;
4244
4245 /* any useful blocks? */
4246 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
4247 edid_parse_string(&data[i+5],
4248 edid->monitor_name);
4249 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
4250 edid_parse_string(&data[i+5],
4251 edid->serial_number);
4252 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
4253 edid_parse_string(&data[i+5],
4254 edid->eisa_id);
4255 }
4256 }
4257 return 0;
4258}
4259
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004260/** Parse monitor make, model and serial from EDID
4261 *
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004262 * \param head The head whose \c drm_edid to fill in.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004263 * \param props The DRM connector properties to get the EDID from.
4264 * \param make[out] The monitor make (PNP ID).
4265 * \param model[out] The monitor model (name).
4266 * \param serial_number[out] The monitor serial number.
4267 *
4268 * Each of \c *make, \c *model and \c *serial_number are set only if the
4269 * information is found in the EDID. The pointers they are set to must not
4270 * be free()'d explicitly, instead they get implicitly freed when the
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004271 * \c drm_head is destroyed.
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004272 */
Richard Hughes2b2092a2013-04-24 14:58:02 +01004273static void
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004274find_and_parse_output_edid(struct drm_head *head,
Pekka Paalanen6f1866b2017-04-03 14:22:51 +03004275 drmModeObjectPropertiesPtr props,
4276 const char **make,
4277 const char **model,
4278 const char **serial_number)
Richard Hughes2b2092a2013-04-24 14:58:02 +01004279{
4280 drmModePropertyBlobPtr edid_blob = NULL;
Daniel Stone02cf4662017-03-03 16:19:39 +00004281 uint32_t blob_id;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004282 int rc;
4283
Daniel Stone02cf4662017-03-03 16:19:39 +00004284 blob_id =
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004285 drm_property_get_value(&head->props_conn[WDRM_CONNECTOR_EDID],
Daniel Stone02cf4662017-03-03 16:19:39 +00004286 props, 0);
4287 if (!blob_id)
4288 return;
4289
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004290 edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id);
Richard Hughes2b2092a2013-04-24 14:58:02 +01004291 if (!edid_blob)
4292 return;
4293
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004294 rc = edid_parse(&head->edid,
Richard Hughes2b2092a2013-04-24 14:58:02 +01004295 edid_blob->data,
4296 edid_blob->length);
4297 if (!rc) {
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004298 if (head->edid.pnp_id[0] != '\0')
4299 *make = head->edid.pnp_id;
4300 if (head->edid.monitor_name[0] != '\0')
4301 *model = head->edid.monitor_name;
4302 if (head->edid.serial_number[0] != '\0')
4303 *serial_number = head->edid.serial_number;
Richard Hughes2b2092a2013-04-24 14:58:02 +01004304 }
4305 drmModeFreePropertyBlob(edid_blob);
4306}
4307
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004308static int
4309parse_modeline(const char *s, drmModeModeInfo *mode)
4310{
4311 char hsync[16];
4312 char vsync[16];
4313 float fclock;
4314
Pekka Paalanendc4e3c62017-12-05 15:37:41 +02004315 memset(mode, 0, sizeof *mode);
4316
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004317 mode->type = DRM_MODE_TYPE_USERDEF;
4318 mode->hskew = 0;
4319 mode->vscan = 0;
4320 mode->vrefresh = 0;
4321 mode->flags = 0;
4322
Rob Bradford307e09e2013-07-26 16:29:40 +01004323 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004324 &fclock,
4325 &mode->hdisplay,
4326 &mode->hsync_start,
4327 &mode->hsync_end,
4328 &mode->htotal,
4329 &mode->vdisplay,
4330 &mode->vsync_start,
4331 &mode->vsync_end,
4332 &mode->vtotal, hsync, vsync) != 11)
4333 return -1;
4334
4335 mode->clock = fclock * 1000;
4336 if (strcmp(hsync, "+hsync") == 0)
4337 mode->flags |= DRM_MODE_FLAG_PHSYNC;
4338 else if (strcmp(hsync, "-hsync") == 0)
4339 mode->flags |= DRM_MODE_FLAG_NHSYNC;
4340 else
4341 return -1;
4342
4343 if (strcmp(vsync, "+vsync") == 0)
4344 mode->flags |= DRM_MODE_FLAG_PVSYNC;
4345 else if (strcmp(vsync, "-vsync") == 0)
4346 mode->flags |= DRM_MODE_FLAG_NVSYNC;
4347 else
4348 return -1;
4349
Emmanuel Gil Peyrota62138b2016-05-02 22:40:11 +01004350 snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
4351 mode->hdisplay, mode->vdisplay, fclock);
4352
Kristian Høgsberga30989a2013-05-23 17:23:15 -04004353 return 0;
4354}
4355
Rob Bradford66bd9f52013-06-25 18:56:42 +01004356static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03004357setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01004358 struct weston_output *output,
4359 const char *s)
4360{
4361 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05004362 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004363 struct udev_seat *seat;
4364
Giulio Camuffo954f1832014-10-11 18:27:30 +03004365 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05004366 if (!seat)
4367 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01004368
Derek Foreman0720ea32015-07-15 13:00:35 -05004369 seat->base.output = output;
4370
Derek Foreman1281a362015-07-31 16:55:32 -05004371 pointer = weston_seat_get_pointer(&seat->base);
4372 if (pointer)
4373 weston_pointer_clamp(pointer,
4374 &pointer->x,
4375 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01004376 }
4377}
4378
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02004379static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03004380drm_output_attach_head(struct weston_output *output_base,
4381 struct weston_head *head_base)
4382{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004383 struct drm_backend *b = to_drm_backend(output_base->compositor);
4384
Pekka Paalanenc112f002017-08-28 16:27:20 +03004385 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
4386 return -1;
4387
Pekka Paalanend5f98d82017-12-08 14:45:00 +02004388 if (!output_base->enabled)
4389 return 0;
4390
4391 /* XXX: ensure the configuration will work.
4392 * This is actually impossible without major infrastructure
4393 * work. */
4394
4395 /* Need to go through modeset to add connectors. */
4396 /* XXX: Ideally we'd do this per-output, not globally. */
4397 /* XXX: Doing it globally, what guarantees another output's update
4398 * will not clear the flag before this output is updated?
4399 */
4400 b->state_invalid = true;
4401
4402 weston_output_schedule_repaint(output_base);
4403
Pekka Paalanenc112f002017-08-28 16:27:20 +03004404 return 0;
4405}
4406
Pekka Paalanen7f853792017-11-29 14:33:33 +02004407static void
4408drm_output_detach_head(struct weston_output *output_base,
4409 struct weston_head *head_base)
4410{
4411 struct drm_backend *b = to_drm_backend(output_base->compositor);
4412
4413 if (!output_base->enabled)
4414 return;
4415
4416 /* Need to go through modeset to drop connectors that should no longer
4417 * be driven. */
4418 /* XXX: Ideally we'd do this per-output, not globally. */
4419 b->state_invalid = true;
4420
4421 weston_output_schedule_repaint(output_base);
4422}
4423
Pekka Paalanenc112f002017-08-28 16:27:20 +03004424static int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004425parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004426{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004427 int ret = 0;
4428
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004429 if (s == NULL)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004430 *gbm_format = default_value;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004431 else if (strcmp(s, "xrgb8888") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004432 *gbm_format = GBM_FORMAT_XRGB8888;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004433 else if (strcmp(s, "rgb565") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004434 *gbm_format = GBM_FORMAT_RGB565;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004435 else if (strcmp(s, "xrgb2101010") == 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004436 *gbm_format = GBM_FORMAT_XRGB2101010;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004437 else {
4438 weston_log("fatal: unrecognized pixel format: %s\n", s);
4439 ret = -1;
4440 }
4441
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004442 return ret;
4443}
4444
Pekka Paalanenf005f252017-11-10 16:34:39 +02004445static uint32_t
4446u32distance(uint32_t a, uint32_t b)
4447{
4448 if (a < b)
4449 return b - a;
4450 else
4451 return a - b;
4452}
4453
4454/** Choose equivalent mode
4455 *
4456 * If the two modes are not equivalent, return NULL.
4457 * Otherwise return the mode that is more likely to work in place of both.
4458 *
4459 * None of the fuzzy matching criteria in this function have any justification.
4460 *
4461 * typedef struct _drmModeModeInfo {
4462 * uint32_t clock;
4463 * uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
4464 * uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
4465 *
4466 * uint32_t vrefresh;
4467 *
4468 * uint32_t flags;
4469 * uint32_t type;
4470 * char name[DRM_DISPLAY_MODE_LEN];
4471 * } drmModeModeInfo, *drmModeModeInfoPtr;
4472 */
4473static const drmModeModeInfo *
4474drm_mode_pick_equivalent(const drmModeModeInfo *a, const drmModeModeInfo *b)
4475{
4476 uint32_t refresh_a, refresh_b;
4477
4478 if (a->hdisplay != b->hdisplay || a->vdisplay != b->vdisplay)
4479 return NULL;
4480
4481 if (a->flags != b->flags)
4482 return NULL;
4483
4484 /* kHz */
4485 if (u32distance(a->clock, b->clock) > 500)
4486 return NULL;
4487
4488 refresh_a = drm_refresh_rate_mHz(a);
4489 refresh_b = drm_refresh_rate_mHz(b);
4490 if (u32distance(refresh_a, refresh_b) > 50)
4491 return NULL;
4492
4493 if ((a->type ^ b->type) & DRM_MODE_TYPE_PREFERRED) {
4494 if (a->type & DRM_MODE_TYPE_PREFERRED)
4495 return a;
4496 else
4497 return b;
4498 }
4499
4500 return a;
4501}
4502
4503/* If the given mode info is not already in the list, add it.
4504 * If it is in the list, either keep the existing or replace it,
4505 * depending on which one is "better".
4506 */
4507static int
4508drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
4509{
4510 struct weston_mode *base;
4511 struct drm_mode *mode;
4512 struct drm_backend *backend;
4513 const drmModeModeInfo *chosen = NULL;
4514
4515 assert(info);
4516
4517 wl_list_for_each(base, &output->base.mode_list, link) {
4518 mode = to_drm_mode(base);
4519 chosen = drm_mode_pick_equivalent(&mode->mode_info, info);
4520 if (chosen)
4521 break;
4522 }
4523
4524 if (chosen == info) {
4525 backend = to_drm_backend(output->base.compositor);
4526 drm_output_destroy_mode(backend, mode);
4527 chosen = NULL;
4528 }
4529
4530 if (!chosen) {
4531 mode = drm_output_add_mode(output, info);
4532 if (!mode)
4533 return -1;
4534 }
4535 /* else { the equivalent mode is already in the list } */
4536
4537 return 0;
4538}
4539
Pekka Paalanen4be24852017-09-11 15:01:12 +03004540/** Rewrite the output's mode list
4541 *
4542 * @param output The output.
4543 * @return 0 on success, -1 on failure.
4544 *
4545 * Destroy all existing modes in the list, and reconstruct a new list from
4546 * scratch, based on the currently attached heads.
4547 *
4548 * On failure the output's mode list may contain some modes.
4549 */
4550static int
4551drm_output_update_modelist_from_heads(struct drm_output *output)
4552{
4553 struct drm_backend *backend = to_drm_backend(output->base.compositor);
4554 struct weston_head *head_base;
4555 struct drm_head *head;
Pekka Paalanen4be24852017-09-11 15:01:12 +03004556 int i;
Pekka Paalanenf005f252017-11-10 16:34:39 +02004557 int ret;
Pekka Paalanen4be24852017-09-11 15:01:12 +03004558
4559 assert(!output->base.enabled);
4560
4561 drm_mode_list_destroy(backend, &output->base.mode_list);
4562
Pekka Paalanenf005f252017-11-10 16:34:39 +02004563 wl_list_for_each(head_base, &output->base.head_list, output_link) {
4564 head = to_drm_head(head_base);
4565 for (i = 0; i < head->connector->count_modes; i++) {
4566 ret = drm_output_try_add_mode(output,
4567 &head->connector->modes[i]);
4568 if (ret < 0)
4569 return -1;
4570 }
Pekka Paalanen4be24852017-09-11 15:01:12 +03004571 }
4572
4573 return 0;
4574}
4575
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004576/**
4577 * Choose suitable mode for an output
4578 *
4579 * Find the most suitable mode to use for initial setup (or reconfiguration on
4580 * hotplug etc) for a DRM output.
4581 *
4582 * @param output DRM output to choose mode for
4583 * @param kind Strategy and preference to use when choosing mode
4584 * @param width Desired width for this output
4585 * @param height Desired height for this output
4586 * @param current_mode Mode currently being displayed on this output
4587 * @param modeline Manually-entered mode (may be NULL)
4588 * @returns A mode from the output's mode list, or NULL if none available
4589 */
4590static struct drm_mode *
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004591drm_output_choose_initial_mode(struct drm_backend *backend,
4592 struct drm_output *output,
4593 enum weston_drm_backend_output_mode mode,
Armin Krezović08368132016-09-30 14:11:05 +02004594 const char *modeline,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004595 const drmModeModeInfo *current_mode)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004596{
4597 struct drm_mode *preferred = NULL;
4598 struct drm_mode *current = NULL;
4599 struct drm_mode *configured = NULL;
4600 struct drm_mode *best = NULL;
4601 struct drm_mode *drm_mode;
Armin Krezović08368132016-09-30 14:11:05 +02004602 drmModeModeInfo drm_modeline;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004603 int32_t width = 0;
4604 int32_t height = 0;
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01004605 uint32_t refresh = 0;
4606 int n;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004607
Armin Krezović08368132016-09-30 14:11:05 +02004608 if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01004609 n = sscanf(modeline, "%dx%d@%d", &width, &height, &refresh);
4610 if (n != 2 && n != 3) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004611 width = -1;
4612
Armin Krezović08368132016-09-30 14:11:05 +02004613 if (parse_modeline(modeline, &drm_modeline) == 0) {
4614 configured = drm_output_add_mode(output, &drm_modeline);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004615 if (!configured)
4616 return NULL;
4617 } else {
4618 weston_log("Invalid modeline \"%s\" for output %s\n",
Armin Krezović08368132016-09-30 14:11:05 +02004619 modeline, output->base.name);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004620 }
4621 }
4622 }
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004623
4624 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004625 if (width == drm_mode->base.width &&
Fabien Dessenne2d66a7d2017-01-17 17:17:21 +01004626 height == drm_mode->base.height &&
4627 (refresh == 0 || refresh == drm_mode->mode_info.vrefresh))
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004628 configured = drm_mode;
4629
comic fans7a5c5622016-03-17 14:29:27 +02004630 if (memcmp(current_mode, &drm_mode->mode_info,
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004631 sizeof *current_mode) == 0)
4632 current = drm_mode;
4633
4634 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
4635 preferred = drm_mode;
4636
4637 best = drm_mode;
4638 }
4639
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004640 if (current == NULL && current_mode->clock != 0) {
4641 current = drm_output_add_mode(output, current_mode);
4642 if (!current)
4643 return NULL;
4644 }
4645
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004646 if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004647 configured = current;
4648
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004649 if (configured)
4650 return configured;
4651
4652 if (preferred)
4653 return preferred;
4654
4655 if (current)
4656 return current;
4657
4658 if (best)
4659 return best;
4660
4661 weston_log("no available modes for %s\n", output->base.name);
4662 return NULL;
4663}
4664
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004665static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02004666drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004667{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02004668 int drm_fd = backend->drm.fd;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004669 drmModeEncoder *encoder;
4670 drmModeCrtc *crtc;
4671
4672 /* Get the current mode on the crtc that's currently driving
4673 * this connector. */
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02004674 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004675 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004676 head->inherited_crtc_id = encoder->crtc_id;
4677
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004678 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
4679 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004680
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004681 if (crtc == NULL)
4682 return -1;
4683 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02004684 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03004685 drmModeFreeCrtc(crtc);
4686 }
4687
4688 return 0;
4689}
4690
Neil Roberts77c1a5b2014-03-07 18:05:50 +00004691static int
Armin Krezović08368132016-09-30 14:11:05 +02004692drm_output_set_mode(struct weston_output *base,
4693 enum weston_drm_backend_output_mode mode,
4694 const char *modeline)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004695{
Armin Krezović08368132016-09-30 14:11:05 +02004696 struct drm_output *output = to_drm_output(base);
4697 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03004698 struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07004699
Armin Krezović445b41b2016-10-09 23:48:16 +02004700 struct drm_mode *current;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004701
Pekka Paalanen4be24852017-09-11 15:01:12 +03004702 if (drm_output_update_modelist_from_heads(output) < 0)
4703 return -1;
4704
Pekka Paalanen13d233e2017-09-11 14:06:11 +03004705 current = drm_output_choose_initial_mode(b, output, mode, modeline,
4706 &head->inherited_mode);
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004707 if (!current)
Armin Krezović445b41b2016-10-09 23:48:16 +02004708 return -1;
Armin Krezović08368132016-09-30 14:11:05 +02004709
Pekka Paalanen7b36b422014-06-04 14:00:53 +03004710 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02004711 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04004712
Armin Krezović08368132016-09-30 14:11:05 +02004713 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
4714 output->base.native_mode = output->base.current_mode;
4715 output->base.native_scale = output->base.current_scale;
4716
Armin Krezović08368132016-09-30 14:11:05 +02004717 return 0;
Armin Krezović08368132016-09-30 14:11:05 +02004718}
4719
4720static void
4721drm_output_set_gbm_format(struct weston_output *base,
4722 const char *gbm_format)
4723{
4724 struct drm_output *output = to_drm_output(base);
4725 struct drm_backend *b = to_drm_backend(base->compositor);
4726
4727 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
4728 output->gbm_format = b->gbm_format;
Daniel Stonee2e80132018-01-16 15:37:33 +00004729
4730 /* Without universal planes, we can't discover which formats are
4731 * supported by the primary plane; we just hope that the GBM format
4732 * works. */
4733 if (!b->universal_planes)
4734 output->scanout_plane->formats[0] = output->gbm_format;
Armin Krezović08368132016-09-30 14:11:05 +02004735}
4736
4737static void
4738drm_output_set_seat(struct weston_output *base,
4739 const char *seat)
4740{
4741 struct drm_output *output = to_drm_output(base);
4742 struct drm_backend *b = to_drm_backend(base->compositor);
4743
4744 setup_output_seat_constraint(b, &output->base,
4745 seat ? seat : "");
4746}
4747
4748static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03004749drm_output_init_gamma_size(struct drm_output *output)
4750{
4751 struct drm_backend *backend = to_drm_backend(output->base.compositor);
4752 drmModeCrtc *crtc;
4753
4754 assert(output->base.compositor);
4755 assert(output->crtc_id != 0);
4756 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
4757 if (!crtc)
4758 return -1;
4759
4760 output->base.gamma_size = crtc->gamma_size;
4761
4762 drmModeFreeCrtc(crtc);
4763
4764 return 0;
4765}
4766
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004767static uint32_t
4768drm_head_get_possible_crtcs_mask(struct drm_head *head)
4769{
4770 uint32_t possible_crtcs = 0;
4771 drmModeEncoder *encoder;
4772 int i;
4773
4774 for (i = 0; i < head->connector->count_encoders; i++) {
4775 encoder = drmModeGetEncoder(head->backend->drm.fd,
4776 head->connector->encoders[i]);
4777 if (!encoder)
4778 continue;
4779
4780 possible_crtcs |= encoder->possible_crtcs;
4781 drmModeFreeEncoder(encoder);
4782 }
4783
4784 return possible_crtcs;
4785}
4786
4787static int
4788drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
4789{
4790 int i;
4791
4792 for (i = 0; i < resources->count_crtcs; i++) {
4793 if (resources->crtcs[i] == crtc_id)
4794 return i;
4795 }
4796
4797 assert(0 && "unknown crtc id");
4798 return -1;
4799}
4800
4801/** Pick a CRTC that might be able to drive all attached connectors
4802 *
4803 * @param output The output whose attached heads to include.
4804 * @param resources The DRM KMS resources.
4805 * @return CRTC index, or -1 on failure or not found.
4806 */
4807static int
4808drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
4809{
4810 struct drm_backend *backend;
4811 struct weston_head *base;
4812 struct drm_head *head;
4813 uint32_t possible_crtcs = 0xffffffff;
4814 int existing_crtc[32];
4815 unsigned j, n = 0;
4816 uint32_t crtc_id;
4817 int best_crtc_index = -1;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02004818 int fallback_crtc_index = -1;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004819 int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02004820 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004821
4822 backend = to_drm_backend(output->base.compositor);
4823
4824 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
4825 * because it is more often set wrong than not in the kernel. */
4826
4827 /* Accumulate a mask of possible crtcs and find existing routings. */
4828 wl_list_for_each(base, &output->base.head_list, output_link) {
4829 head = to_drm_head(base);
4830
4831 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
4832
4833 crtc_id = head->inherited_crtc_id;
4834 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
4835 existing_crtc[n++] = drm_crtc_get_index(resources,
4836 crtc_id);
4837 }
4838
4839 /* Find a crtc that could drive each connector individually at least,
4840 * and prefer existing routings. */
4841 for (i = 0; i < resources->count_crtcs; i++) {
4842 crtc_id = resources->crtcs[i];
4843
4844 /* Could the crtc not drive each connector? */
4845 if (!(possible_crtcs & (1 << i)))
4846 continue;
4847
4848 /* Is the crtc already in use? */
4849 if (drm_output_find_by_crtc(backend, crtc_id))
4850 continue;
4851
4852 /* Try to preserve the existing CRTC -> connector routing;
4853 * it makes initialisation faster, and also since we have a
4854 * very dumb picking algorithm, may preserve a better
4855 * choice. */
4856 for (j = 0; j < n; j++) {
4857 if (existing_crtc[j] == i)
4858 return i;
4859 }
4860
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02004861 /* Check if any other head had existing routing to this CRTC.
4862 * If they did, this is not the best CRTC as it might be needed
4863 * for another output we haven't enabled yet. */
4864 match = false;
4865 wl_list_for_each(base, &backend->compositor->head_list,
4866 compositor_link) {
4867 head = to_drm_head(base);
4868
4869 if (head->base.output == &output->base)
4870 continue;
4871
4872 if (weston_head_is_enabled(&head->base))
4873 continue;
4874
4875 if (head->inherited_crtc_id == crtc_id) {
4876 match = true;
4877 break;
4878 }
4879 }
4880 if (!match)
4881 best_crtc_index = i;
4882
4883 fallback_crtc_index = i;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004884 }
4885
4886 if (best_crtc_index != -1)
4887 return best_crtc_index;
4888
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02004889 if (fallback_crtc_index != -1)
4890 return fallback_crtc_index;
4891
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004892 /* Likely possible_crtcs was empty due to asking for clones,
4893 * but since the DRM documentation says the kernel lies, let's
4894 * pick one crtc anyway. Trial and error is the only way to
4895 * be sure if something doesn't work. */
4896
4897 /* First pick any existing assignment. */
4898 for (j = 0; j < n; j++) {
4899 crtc_id = resources->crtcs[existing_crtc[j]];
4900 if (!drm_output_find_by_crtc(backend, crtc_id))
4901 return existing_crtc[j];
4902 }
4903
4904 /* Otherwise pick any available crtc. */
4905 for (i = 0; i < resources->count_crtcs; i++) {
4906 crtc_id = resources->crtcs[i];
4907
4908 if (!drm_output_find_by_crtc(backend, crtc_id))
4909 return i;
4910 }
4911
4912 return -1;
4913}
4914
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03004915/** Allocate a CRTC for the output
4916 *
4917 * @param output The output with no allocated CRTC.
4918 * @param resources DRM KMS resources.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03004919 * @return 0 on success, -1 on failure.
4920 *
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004921 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03004922 * for the output, and loads the CRTC properties.
4923 *
4924 * Populates the cursor and scanout planes.
4925 *
4926 * On failure, the output remains without a CRTC.
4927 */
4928static int
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004929drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03004930{
4931 struct drm_backend *b = to_drm_backend(output->base.compositor);
4932 drmModeObjectPropertiesPtr props;
4933 int i;
4934
4935 assert(output->crtc_id == 0);
4936
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004937 i = drm_output_pick_crtc(output, resources);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03004938 if (i < 0) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02004939 weston_log("Output '%s': No available CRTCs.\n",
4940 output->base.name);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03004941 return -1;
4942 }
4943
4944 output->crtc_id = resources->crtcs[i];
4945 output->pipe = i;
4946
4947 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
4948 DRM_MODE_OBJECT_CRTC);
4949 if (!props) {
4950 weston_log("failed to get CRTC properties\n");
4951 goto err_crtc;
4952 }
4953 drm_property_info_populate(b, crtc_props, output->props_crtc,
4954 WDRM_CRTC__COUNT, props);
4955 drmModeFreeObjectProperties(props);
4956
4957 output->scanout_plane =
4958 drm_output_find_special_plane(b, output,
4959 WDRM_PLANE_TYPE_PRIMARY);
4960 if (!output->scanout_plane) {
4961 weston_log("Failed to find primary plane for output %s\n",
4962 output->base.name);
4963 goto err_crtc;
4964 }
4965
4966 /* Failing to find a cursor plane is not fatal, as we'll fall back
4967 * to software cursor. */
4968 output->cursor_plane =
4969 drm_output_find_special_plane(b, output,
4970 WDRM_PLANE_TYPE_CURSOR);
4971
Pekka Paalanen663d5e92017-09-08 13:32:40 +03004972 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
4973
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03004974 return 0;
4975
4976err_crtc:
4977 output->crtc_id = 0;
4978 output->pipe = 0;
4979
4980 return -1;
4981}
4982
4983/** Free the CRTC from the output
4984 *
4985 * @param output The output whose CRTC to deallocate.
4986 *
4987 * The CRTC reserved for the given output becomes free to use again.
4988 */
4989static void
4990drm_output_fini_crtc(struct drm_output *output)
4991{
4992 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03004993 uint32_t *unused;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03004994
4995 if (!b->universal_planes && !b->shutting_down) {
4996 /* With universal planes, the 'special' planes are allocated at
4997 * startup, freed at shutdown, and live on the plane list in
4998 * between. We want the planes to continue to exist and be freed
4999 * up for other outputs.
5000 *
5001 * Without universal planes, our special planes are
5002 * pseudo-planes allocated at output creation, freed at output
5003 * destruction, and not usable by other outputs.
5004 *
5005 * On the other hand, if the compositor is already shutting down,
5006 * the plane has already been destroyed.
5007 */
5008 if (output->cursor_plane)
5009 drm_plane_destroy(output->cursor_plane);
5010 if (output->scanout_plane)
5011 drm_plane_destroy(output->scanout_plane);
5012 }
5013
5014 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005015
5016 assert(output->crtc_id != 0);
5017
5018 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
5019 *unused = output->crtc_id;
5020
5021 /* Force resetting unused CRTCs */
5022 b->state_invalid = true;
5023
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03005024 output->crtc_id = 0;
5025 output->cursor_plane = NULL;
5026 output->scanout_plane = NULL;
5027}
5028
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005029static void
5030drm_output_print_modes(struct drm_output *output)
5031{
5032 struct weston_mode *m;
5033 struct drm_mode *dm;
5034
5035 wl_list_for_each(m, &output->base.mode_list, link) {
5036 dm = to_drm_mode(m);
5037
5038 weston_log_continue(STAMP_SPACE "%dx%d@%.1f%s%s, %.1f MHz\n",
5039 m->width, m->height, m->refresh / 1000.0,
5040 m->flags & WL_OUTPUT_MODE_PREFERRED ?
5041 ", preferred" : "",
5042 m->flags & WL_OUTPUT_MODE_CURRENT ?
5043 ", current" : "",
5044 dm->mode_info.clock / 1000.0);
5045 }
5046}
5047
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03005048static int
Armin Krezović08368132016-09-30 14:11:05 +02005049drm_output_enable(struct weston_output *base)
5050{
5051 struct drm_output *output = to_drm_output(base);
5052 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005053 drmModeRes *resources;
5054 int ret;
5055
5056 resources = drmModeGetResources(b->drm.fd);
5057 if (!resources) {
5058 weston_log("drmModeGetResources failed\n");
5059 return -1;
5060 }
Pekka Paalanen27cc4812017-11-20 13:31:06 +02005061 ret = drm_output_init_crtc(output, resources);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005062 drmModeFreeResources(resources);
5063 if (ret < 0)
5064 return -1;
5065
5066 if (drm_output_init_gamma_size(output) < 0)
5067 goto err;
Armin Krezović08368132016-09-30 14:11:05 +02005068
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005069 if (b->pageflip_timeout)
5070 drm_output_pageflip_timer_create(output);
5071
Giulio Camuffo954f1832014-10-11 18:27:30 +03005072 if (b->use_pixman) {
5073 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005074 weston_log("Failed to init output pixman state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005075 goto err;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005076 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03005077 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02005078 weston_log("Failed to init output gl state\n");
Daniel Stone02cf4662017-03-03 16:19:39 +00005079 goto err;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04005080 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04005081
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02005082 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005083
Jonas Ådahle5a12252013-04-05 23:07:11 +02005084 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05005085 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05005086 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02005087 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08005088 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01005089 output->base.set_gamma = drm_output_set_gamma;
5090
Daniel Stone2ba17f42015-05-19 20:02:41 +01005091 if (output->cursor_plane)
5092 weston_compositor_stack_plane(b->compositor,
5093 &output->cursor_plane->base,
5094 NULL);
5095 else
5096 b->cursors_are_broken = 1;
5097
Daniel Stonee2e80132018-01-16 15:37:33 +00005098 weston_compositor_stack_plane(b->compositor,
5099 &output->scanout_plane->base,
Giulio Camuffo954f1832014-10-11 18:27:30 +03005100 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02005101
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02005102 weston_log("Output %s (crtc %d) video modes:\n",
5103 output->base.name, output->crtc_id);
5104 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04005105
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005106 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01005107
Daniel Stone02cf4662017-03-03 16:19:39 +00005108err:
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005109 drm_output_fini_crtc(output);
5110
David Herrmann0f0d54e2011-12-08 17:05:45 +01005111 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005112}
5113
Jesse Barnes58ef3792012-02-23 09:45:49 -05005114static void
Armin Krezović08368132016-09-30 14:11:05 +02005115drm_output_deinit(struct weston_output *base)
5116{
5117 struct drm_output *output = to_drm_output(base);
5118 struct drm_backend *b = to_drm_backend(base->compositor);
5119
Daniel Stone3e661f72016-11-04 17:24:06 +00005120 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02005121 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00005122 else
5123 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02005124
Daniel Stone2ba17f42015-05-19 20:02:41 +01005125 /* Since our planes are no longer in use anywhere, remove their base
5126 * weston_plane's link from the plane stacking list, unless we're
5127 * shutting down, in which case the plane has already been
5128 * destroyed. */
Daniel Stonee2e80132018-01-16 15:37:33 +00005129 if (!b->shutting_down) {
5130 wl_list_remove(&output->scanout_plane->base.link);
5131 wl_list_init(&output->scanout_plane->base.link);
5132
5133 if (output->cursor_plane) {
5134 wl_list_remove(&output->cursor_plane->base.link);
5135 wl_list_init(&output->cursor_plane->base.link);
5136 /* Turn off hardware cursor */
5137 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
5138 }
Daniel Stone2ba17f42015-05-19 20:02:41 +01005139 }
Daniel Stone087ddf02017-02-14 17:51:30 +00005140
Pekka Paalanen663d5e92017-09-08 13:32:40 +03005141 drm_output_fini_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02005142}
5143
5144static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03005145drm_head_destroy(struct drm_head *head);
5146
5147static void
Armin Krezović08368132016-09-30 14:11:05 +02005148drm_output_destroy(struct weston_output *base)
5149{
5150 struct drm_output *output = to_drm_output(base);
5151 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02005152
Daniel Stone598ee9d2016-11-16 11:55:20 +00005153 if (output->page_flip_pending || output->vblank_pending ||
5154 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005155 output->destroy_pending = 1;
5156 weston_log("destroy output while page flip pending\n");
5157 return;
5158 }
5159
5160 if (output->base.enabled)
5161 drm_output_deinit(&output->base);
5162
Pekka Paalanen383b3af2017-09-11 14:40:48 +03005163 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02005164
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00005165 if (output->pageflip_timer)
5166 wl_event_source_remove(output->pageflip_timer);
5167
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03005168 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02005169
Daniel Stone7b2ddac2016-11-11 19:11:49 +00005170 assert(!output->state_last);
5171 drm_output_state_free(output->state_cur);
5172
Armin Krezović08368132016-09-30 14:11:05 +02005173 free(output);
5174}
5175
5176static int
5177drm_output_disable(struct weston_output *base)
5178{
5179 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02005180
Daniel Stone598ee9d2016-11-16 11:55:20 +00005181 if (output->page_flip_pending || output->vblank_pending ||
5182 output->atomic_complete_pending) {
Armin Krezović08368132016-09-30 14:11:05 +02005183 output->disable_pending = 1;
5184 return -1;
5185 }
5186
Daniel Stonea08512f2016-11-08 17:46:10 +00005187 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00005188
Armin Krezović08368132016-09-30 14:11:05 +02005189 if (output->base.enabled)
5190 drm_output_deinit(&output->base);
5191
5192 output->disable_pending = 0;
5193
Armin Krezović08368132016-09-30 14:11:05 +02005194 return 0;
5195}
5196
5197/**
Daniel Stone087ddf02017-02-14 17:51:30 +00005198 * Update the list of unused connectors and CRTCs
5199 *
Pekka Paalaneneacec812017-09-12 13:43:51 +03005200 * This keeps the unused_crtc arrays up to date.
Daniel Stone087ddf02017-02-14 17:51:30 +00005201 *
5202 * @param b Weston backend structure
5203 * @param resources DRM resources for this device
5204 */
5205static void
5206drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
5207{
5208 int i;
5209
Daniel Stone087ddf02017-02-14 17:51:30 +00005210 wl_array_release(&b->unused_crtcs);
5211 wl_array_init(&b->unused_crtcs);
5212
5213 for (i = 0; i < resources->count_crtcs; i++) {
5214 struct drm_output *output;
5215 uint32_t *crtc_id;
5216
5217 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
5218 if (output && output->base.enabled)
5219 continue;
5220
5221 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
5222 *crtc_id = resources->crtcs[i];
5223 }
5224}
5225
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005226/** Replace connector data and monitor information
5227 *
5228 * @param head The head to update.
5229 * @param connector The connector data to be owned by the head, must match
5230 * the head's connector ID.
5231 * @return 0 on success, -1 on failure.
5232 *
5233 * Takes ownership of @c connector on success, not on failure.
5234 *
5235 * May schedule a heads changed call.
5236 */
5237static int
5238drm_head_assign_connector_info(struct drm_head *head,
5239 drmModeConnector *connector)
5240{
5241 drmModeObjectProperties *props;
5242 const char *make = "unknown";
5243 const char *model = "unknown";
5244 const char *serial_number = "unknown";
5245
5246 assert(connector);
5247 assert(head->connector_id == connector->connector_id);
5248
5249 props = drmModeObjectGetProperties(head->backend->drm.fd,
5250 head->connector_id,
5251 DRM_MODE_OBJECT_CONNECTOR);
5252 if (!props) {
5253 weston_log("Error: failed to get connector '%s' properties\n",
5254 head->base.name);
5255 return -1;
5256 }
5257
5258 if (head->connector)
5259 drmModeFreeConnector(head->connector);
5260 head->connector = connector;
5261
5262 drm_property_info_populate(head->backend, connector_props,
5263 head->props_conn,
5264 WDRM_CONNECTOR__COUNT, props);
5265 find_and_parse_output_edid(head, props, &make, &model, &serial_number);
5266 weston_head_set_monitor_strings(&head->base, make, model, serial_number);
5267 weston_head_set_subpixel(&head->base,
5268 drm_subpixel_to_wayland(head->connector->subpixel));
5269
5270 weston_head_set_physical_size(&head->base, head->connector->mmWidth,
5271 head->connector->mmHeight);
5272
5273 drmModeFreeObjectProperties(props);
5274
5275 /* Unknown connection status is assumed disconnected. */
5276 weston_head_set_connection_status(&head->base,
5277 head->connector->connection == DRM_MODE_CONNECTED);
5278
5279 return 0;
5280}
5281
Pekka Paalanen456dc732017-11-09 15:10:11 +02005282static void
5283drm_head_log_info(struct drm_head *head, const char *msg)
5284{
5285 if (head->base.connected) {
5286 weston_log("DRM: head '%s' %s, connector %d is connected, "
5287 "EDID make '%s', model '%s', serial '%s'\n",
5288 head->base.name, msg, head->connector_id,
5289 head->base.make, head->base.model,
5290 head->base.serial_number ?: "");
5291 } else {
5292 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
5293 head->base.name, msg, head->connector_id);
5294 }
5295}
5296
Pekka Paalanend2e62422017-09-08 15:48:07 +03005297/** Update connector and monitor information
5298 *
5299 * @param head The head to update.
5300 *
5301 * Re-reads the DRM property lists for the connector and updates monitor
5302 * information and connection status. This may schedule a heads changed call
5303 * to the user.
5304 */
5305static void
5306drm_head_update_info(struct drm_head *head)
5307{
5308 drmModeConnector *connector;
5309
5310 connector = drmModeGetConnector(head->backend->drm.fd,
5311 head->connector_id);
5312 if (!connector) {
5313 weston_log("DRM: getting connector info for '%s' failed.\n",
5314 head->base.name);
5315 return;
5316 }
5317
5318 if (drm_head_assign_connector_info(head, connector) < 0)
5319 drmModeFreeConnector(connector);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005320
5321 if (head->base.device_changed)
5322 drm_head_log_info(head, "updated");
Pekka Paalanend2e62422017-09-08 15:48:07 +03005323}
5324
Daniel Stone087ddf02017-02-14 17:51:30 +00005325/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03005326 * Create a Weston head for a connector
5327 *
5328 * Given a DRM connector, create a matching drm_head structure and add it
5329 * to Weston's head list.
5330 *
5331 * @param b Weston backend structure
5332 * @param connector_id DRM connector ID for the head
5333 * @param drm_device udev device pointer
5334 * @returns The new head, or NULL on failure.
5335 */
5336static struct drm_head *
5337drm_head_create(struct drm_backend *backend, uint32_t connector_id,
5338 struct udev_device *drm_device)
5339{
5340 struct drm_head *head;
5341 drmModeConnector *connector;
5342 char *name;
5343
5344 head = zalloc(sizeof *head);
5345 if (!head)
5346 return NULL;
5347
5348 connector = drmModeGetConnector(backend->drm.fd, connector_id);
5349 if (!connector)
5350 goto err_alloc;
5351
5352 name = make_connector_name(connector);
5353 if (!name)
5354 goto err_alloc;
5355
5356 weston_head_init(&head->base, name);
5357 free(name);
5358
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005359 head->connector_id = connector_id;
Pekka Paalanenc112f002017-08-28 16:27:20 +03005360 head->backend = backend;
5361
Pekka Paalanence724242017-09-04 12:21:24 +03005362 head->backlight = backlight_init(drm_device, connector->connector_type);
5363
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005364 if (drm_head_assign_connector_info(head, connector) < 0)
5365 goto err_init;
5366
5367 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
5368 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
5369 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03005370
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02005371 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005372 weston_log("Failed to retrieve current mode from connector %d.\n",
5373 head->connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02005374 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03005375 }
5376
Pekka Paalanenc112f002017-08-28 16:27:20 +03005377 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02005378 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03005379
5380 return head;
5381
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005382err_init:
5383 weston_head_release(&head->base);
5384
Pekka Paalanenc112f002017-08-28 16:27:20 +03005385err_alloc:
5386 if (connector)
5387 drmModeFreeConnector(connector);
5388
5389 free(head);
5390
5391 return NULL;
5392}
5393
5394static void
5395drm_head_destroy(struct drm_head *head)
5396{
5397 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03005398
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005399 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
5400 drmModeFreeConnector(head->connector);
5401
Pekka Paalanence724242017-09-04 12:21:24 +03005402 if (head->backlight)
5403 backlight_destroy(head->backlight);
5404
Pekka Paalanenc112f002017-08-28 16:27:20 +03005405 free(head);
5406}
5407
5408/**
Armin Krezović08368132016-09-30 14:11:05 +02005409 * Create a Weston output structure
5410 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03005411 * Create an "empty" drm_output. This is the implementation of
5412 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02005413 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03005414 * Creating an output is usually followed by drm_output_attach_head()
5415 * and drm_output_enable() to make use of it.
5416 *
5417 * @param compositor The compositor instance.
5418 * @param name Name for the new output.
5419 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02005420 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03005421static struct weston_output *
5422drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02005423{
Pekka Paalanend2e62422017-09-08 15:48:07 +03005424 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02005425 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02005426
Armin Krezović08368132016-09-30 14:11:05 +02005427 output = zalloc(sizeof *output);
5428 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03005429 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02005430
Pekka Paalanend2e62422017-09-08 15:48:07 +03005431 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03005432
Armin Krezović08368132016-09-30 14:11:05 +02005433 output->base.enable = drm_output_enable;
5434 output->base.destroy = drm_output_destroy;
5435 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03005436 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02005437 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02005438
5439 output->destroy_pending = 0;
5440 output->disable_pending = 0;
Armin Krezović08368132016-09-30 14:11:05 +02005441
Pekka Paalanen01f60212017-03-24 15:39:24 +02005442 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03005443
Armin Krezović08368132016-09-30 14:11:05 +02005444 weston_compositor_add_pending_output(&output->base, b->compositor);
5445
Pekka Paalanend2e62422017-09-08 15:48:07 +03005446 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02005447}
5448
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005449static int
Pekka Paalanend2e62422017-09-08 15:48:07 +03005450drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005451{
Pekka Paalanend2e62422017-09-08 15:48:07 +03005452 struct drm_head *head;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005453 drmModeRes *resources;
5454 int i;
5455
Giulio Camuffo954f1832014-10-11 18:27:30 +03005456 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005457 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02005458 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005459 return -1;
5460 }
5461
Giulio Camuffo954f1832014-10-11 18:27:30 +03005462 b->min_width = resources->min_width;
5463 b->max_width = resources->max_width;
5464 b->min_height = resources->min_height;
5465 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05005466
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005467 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005468 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00005469
Pekka Paalanend2e62422017-09-08 15:48:07 +03005470 head = drm_head_create(b, connector_id, drm_device);
5471 if (!head) {
5472 weston_log("DRM: failed to create head for connector %d.\n",
5473 connector_id);
Benjamin Franzke9eaee352011-08-02 13:03:54 +02005474 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005475 }
5476
Daniel Stone087ddf02017-02-14 17:51:30 +00005477 drm_backend_update_unused_outputs(b, resources);
5478
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04005479 drmModeFreeResources(resources);
5480
5481 return 0;
5482}
5483
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005484static void
Pekka Paalanend2e62422017-09-08 15:48:07 +03005485drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005486{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005487 drmModeRes *resources;
Pekka Paalanena0a37462017-08-31 15:41:57 +03005488 struct weston_head *base, *next;
5489 struct drm_head *head;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005490 int i;
5491
Giulio Camuffo954f1832014-10-11 18:27:30 +03005492 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005493 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02005494 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005495 return;
5496 }
5497
Pekka Paalanend2e62422017-09-08 15:48:07 +03005498 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005499 for (i = 0; i < resources->count_connectors; i++) {
Ucan, Emre (ADITG/SW1)21e49442017-02-02 14:06:55 +00005500 uint32_t connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02005501
Pekka Paalanend2e62422017-09-08 15:48:07 +03005502 head = drm_head_find_by_connector(b, connector_id);
5503 if (head) {
5504 drm_head_update_info(head);
5505 } else {
5506 head = drm_head_create(b, connector_id, drm_device);
5507 if (!head)
5508 weston_log("DRM: failed to create head for hot-added connector %d.\n",
5509 connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01005510 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005511 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005512
Pekka Paalanend2e62422017-09-08 15:48:07 +03005513 /* Remove connectors that have disappeared. */
Pekka Paalanena0a37462017-08-31 15:41:57 +03005514 wl_list_for_each_safe(base, next,
5515 &b->compositor->head_list, compositor_link) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005516 bool removed = true;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005517
Pekka Paalanena0a37462017-08-31 15:41:57 +03005518 head = to_drm_head(base);
5519
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005520 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03005521 if (resources->connectors[i] == head->connector_id) {
5522 removed = false;
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005523 break;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005524 }
5525 }
Armin Krezović08368132016-09-30 14:11:05 +02005526
Pekka Paalanend2e62422017-09-08 15:48:07 +03005527 if (!removed)
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005528 continue;
5529
Pekka Paalanend2e62422017-09-08 15:48:07 +03005530 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
5531 head->base.name, head->connector_id);
5532 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005533 }
5534
Daniel Stone087ddf02017-02-14 17:51:30 +00005535 drm_backend_update_unused_outputs(b, resources);
5536
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00005537 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005538}
5539
5540static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03005541udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005542{
David Herrmannd7488c22012-03-11 20:05:21 +01005543 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01005544 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01005545
5546 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005547 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01005548 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02005549
David Herrmann6ac52db2012-03-11 20:05:22 +01005550 val = udev_device_get_property_value(device, "HOTPLUG");
5551 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005552 return 0;
5553
David Herrmann6ac52db2012-03-11 20:05:22 +01005554 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005555}
5556
Kristian Høgsbergb1868472011-04-22 12:27:57 -04005557static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005558udev_drm_event(int fd, uint32_t mask, void *data)
5559{
Giulio Camuffo954f1832014-10-11 18:27:30 +03005560 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005561 struct udev_device *event;
5562
Giulio Camuffo954f1832014-10-11 18:27:30 +03005563 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02005564
Giulio Camuffo954f1832014-10-11 18:27:30 +03005565 if (udev_event_is_hotplug(b, event))
Pekka Paalanend2e62422017-09-08 15:48:07 +03005566 drm_backend_update_heads(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005567
5568 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04005569
5570 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01005571}
5572
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005573static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005574drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005575{
Armin Krezović545dba62016-08-05 15:54:18 +02005576 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03005577 struct weston_head *base, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005578
Giulio Camuffo954f1832014-10-11 18:27:30 +03005579 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02005580
Giulio Camuffo954f1832014-10-11 18:27:30 +03005581 wl_event_source_remove(b->udev_drm_source);
5582 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02005583
Daniel Stoneb57c6a02017-10-05 16:27:21 +01005584 b->shutting_down = true;
5585
Giulio Camuffo954f1832014-10-11 18:27:30 +03005586 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04005587
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03005588 weston_compositor_shutdown(ec);
5589
Pekka Paalanenc112f002017-08-28 16:27:20 +03005590 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
5591 drm_head_destroy(to_drm_head(base));
5592
Giulio Camuffo954f1832014-10-11 18:27:30 +03005593 if (b->gbm)
5594 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02005595
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02005596 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03005597 udev_unref(b->udev);
5598
Giulio Camuffo954f1832014-10-11 18:27:30 +03005599 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005600
Daniel Stone087ddf02017-02-14 17:51:30 +00005601 wl_array_release(&b->unused_crtcs);
Daniel Stone087ddf02017-02-14 17:51:30 +00005602
Giulio Camuffo954f1832014-10-11 18:27:30 +03005603 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02005604 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005605 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05005606}
5607
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005608static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005609session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005610{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005611 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02005612 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01005613 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04005614 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005615
Giulio Camuffo954f1832014-10-11 18:27:30 +03005616 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005617 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00005618 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05005619 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00005620 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03005621 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07005622 } else {
5623 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03005624 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04005625
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01005626 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04005627
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05005628 /* If we have a repaint scheduled (either from a
5629 * pending pageflip or the idle handler), make sure we
5630 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01005631 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05005632 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05005633 * back, we schedule a repaint, which will process
5634 * pending frame callbacks. */
5635
Giulio Camuffo954f1832014-10-11 18:27:30 +03005636 wl_list_for_each(output, &compositor->output_list, base.link) {
Daniel Stone09a97e22017-03-01 11:34:06 +00005637 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01005638 if (output->cursor_plane)
5639 drmModeSetCursor(b->drm.fd, output->crtc_id,
5640 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05005641 }
5642
Giulio Camuffo954f1832014-10-11 18:27:30 +03005643 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04005644 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05005645
Daniel Stone085d2b92015-05-21 00:00:57 +01005646 wl_list_for_each(plane, &b->plane_list, link) {
5647 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
5648 continue;
5649
Giulio Camuffo954f1832014-10-11 18:27:30 +03005650 drmModeSetPlane(b->drm.fd,
Daniel Stone085d2b92015-05-21 00:00:57 +01005651 plane->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04005652 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05005653 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01005654 }
5655 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04005656}
5657
Daniel Stoneefa504f2016-12-19 16:48:20 +00005658/**
5659 * Determines whether or not a device is capable of modesetting. If successful,
5660 * sets b->drm.fd and b->drm.filename to the opened device.
5661 */
5662static bool
5663drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
5664{
5665 const char *filename = udev_device_get_devnode(device);
5666 const char *sysnum = udev_device_get_sysnum(device);
5667 drmModeRes *res;
5668 int id, fd;
5669
5670 if (!filename)
5671 return false;
5672
5673 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
5674 if (fd < 0)
5675 return false;
5676
5677 res = drmModeGetResources(fd);
5678 if (!res)
5679 goto out_fd;
5680
5681 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
5682 res->count_encoders <= 0)
5683 goto out_res;
5684
5685 if (sysnum)
5686 id = atoi(sysnum);
5687 if (!sysnum || id < 0) {
5688 weston_log("couldn't get sysnum for device %s\n", filename);
5689 goto out_res;
5690 }
5691
5692 /* We can be called successfully on multiple devices; if we have,
5693 * clean up old entries. */
5694 if (b->drm.fd >= 0)
5695 weston_launcher_close(b->compositor->launcher, b->drm.fd);
5696 free(b->drm.filename);
5697
5698 b->drm.fd = fd;
5699 b->drm.id = id;
5700 b->drm.filename = strdup(filename);
5701
Sergi Granellceb59812017-03-28 12:44:04 +02005702 drmModeFreeResources(res);
5703
Daniel Stoneefa504f2016-12-19 16:48:20 +00005704 return true;
5705
5706out_res:
5707 drmModeFreeResources(res);
5708out_fd:
5709 weston_launcher_close(b->compositor->launcher, fd);
5710 return false;
5711}
5712
David Herrmann0af066f2012-10-29 19:21:16 +01005713/*
5714 * Find primary GPU
5715 * Some systems may have multiple DRM devices attached to a single seat. This
5716 * function loops over all devices and tries to find a PCI device with the
5717 * boot_vga sysfs attribute set to 1.
5718 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00005719 * Devices are also vetted to make sure they are are capable of modesetting,
5720 * rather than pure render nodes (GPU with no display), or pure
5721 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01005722 */
5723static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03005724find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01005725{
5726 struct udev_enumerate *e;
5727 struct udev_list_entry *entry;
5728 const char *path, *device_seat, *id;
5729 struct udev_device *device, *drm_device, *pci;
5730
Giulio Camuffo954f1832014-10-11 18:27:30 +03005731 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01005732 udev_enumerate_add_match_subsystem(e, "drm");
5733 udev_enumerate_add_match_sysname(e, "card[0-9]*");
5734
5735 udev_enumerate_scan_devices(e);
5736 drm_device = NULL;
5737 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00005738 bool is_boot_vga = false;
5739
David Herrmann0af066f2012-10-29 19:21:16 +01005740 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005741 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01005742 if (!device)
5743 continue;
5744 device_seat = udev_device_get_property_value(device, "ID_SEAT");
5745 if (!device_seat)
5746 device_seat = default_seat;
5747 if (strcmp(device_seat, seat)) {
5748 udev_device_unref(device);
5749 continue;
5750 }
5751
5752 pci = udev_device_get_parent_with_subsystem_devtype(device,
5753 "pci", NULL);
5754 if (pci) {
5755 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00005756 if (id && !strcmp(id, "1"))
5757 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01005758 }
5759
Daniel Stoneefa504f2016-12-19 16:48:20 +00005760 /* If we already have a modesetting-capable device, and this
5761 * device isn't our boot-VGA device, we aren't going to use
5762 * it. */
5763 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01005764 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00005765 continue;
5766 }
5767
5768 /* Make sure this device is actually capable of modesetting;
5769 * if this call succeeds, b->drm.{fd,filename} will be set,
5770 * and any old values freed. */
5771 if (!drm_device_is_kms(b, device)) {
5772 udev_device_unref(device);
5773 continue;
5774 }
5775
5776 /* There can only be one boot_vga device, and we try to use it
5777 * at all costs. */
5778 if (is_boot_vga) {
5779 if (drm_device)
5780 udev_device_unref(drm_device);
5781 drm_device = device;
5782 break;
5783 }
5784
5785 /* Per the (!is_boot_vga && drm_device) test above, we only
5786 * trump existing saved devices with boot-VGA devices, so if
5787 * we end up here, this must be the first device we've seen. */
5788 assert(!drm_device);
5789 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01005790 }
5791
Daniel Stoneefa504f2016-12-19 16:48:20 +00005792 /* If we're returning a device to use, we must have an open FD for
5793 * it. */
5794 assert(!!drm_device == (b->drm.fd >= 0));
5795
David Herrmann0af066f2012-10-29 19:21:16 +01005796 udev_enumerate_unref(e);
5797 return drm_device;
5798}
5799
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03005800static struct udev_device *
5801open_specific_drm_device(struct drm_backend *b, const char *name)
5802{
5803 struct udev_device *device;
5804
5805 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
5806 if (!device) {
5807 weston_log("ERROR: could not open DRM device '%s'\n", name);
5808 return NULL;
5809 }
5810
5811 if (!drm_device_is_kms(b, device)) {
5812 udev_device_unref(device);
5813 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
5814 return NULL;
5815 }
5816
5817 /* If we're returning a device to use, we must have an open FD for
5818 * it. */
5819 assert(b->drm.fd >= 0);
5820
5821 return device;
5822}
5823
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02005824static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02005825planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
5826 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02005827{
Giulio Camuffo954f1832014-10-11 18:27:30 +03005828 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02005829
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02005830 switch (key) {
5831 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005832 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02005833 break;
5834 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005835 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02005836 break;
5837 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03005838 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02005839 break;
5840 default:
5841 break;
5842 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02005843}
5844
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07005845#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005846static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03005847recorder_destroy(struct drm_output *output)
5848{
5849 vaapi_recorder_destroy(output->recorder);
5850 output->recorder = NULL;
5851
5852 output->base.disable_planes--;
5853
5854 wl_list_remove(&output->recorder_frame_listener.link);
5855 weston_log("[libva recorder] done\n");
5856}
5857
5858static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005859recorder_frame_notify(struct wl_listener *listener, void *data)
5860{
5861 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03005862 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005863 int fd, ret;
5864
5865 output = container_of(listener, struct drm_output,
5866 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02005867 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005868
5869 if (!output->recorder)
5870 return;
5871
Daniel Stonee2e80132018-01-16 15:37:33 +00005872 ret = drmPrimeHandleToFD(b->drm.fd,
5873 output->scanout_plane->state_cur->fb->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005874 DRM_CLOEXEC, &fd);
5875 if (ret) {
5876 weston_log("[libva recorder] "
5877 "failed to create prime fd for front buffer\n");
5878 return;
5879 }
5880
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03005881 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stonee2e80132018-01-16 15:37:33 +00005882 output->scanout_plane->state_cur->fb->stride);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03005883 if (ret < 0) {
5884 weston_log("[libva recorder] aborted: %m\n");
5885 recorder_destroy(output);
5886 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005887}
5888
5889static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03005890create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005891 const char *filename)
5892{
5893 int fd;
5894 drm_magic_t magic;
5895
Giulio Camuffo954f1832014-10-11 18:27:30 +03005896 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005897 if (fd < 0)
5898 return NULL;
5899
5900 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03005901 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005902
5903 return vaapi_recorder_create(fd, width, height, filename);
5904}
5905
5906static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02005907recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
5908 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005909{
Giulio Camuffo954f1832014-10-11 18:27:30 +03005910 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005911 struct drm_output *output;
5912 int width, height;
5913
Giulio Camuffo954f1832014-10-11 18:27:30 +03005914 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005915 struct drm_output, base.link);
5916
5917 if (!output->recorder) {
Miguel A. Vicofcf4b6c2016-03-21 17:41:03 +01005918 if (output->gbm_format != GBM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03005919 weston_log("failed to start vaapi recorder: "
5920 "output format not supported\n");
5921 return;
5922 }
5923
Hardeningff39efa2013-09-18 23:56:35 +02005924 width = output->base.current_mode->width;
5925 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005926
5927 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03005928 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005929 if (!output->recorder) {
5930 weston_log("failed to create vaapi recorder\n");
5931 return;
5932 }
5933
5934 output->base.disable_planes++;
5935
5936 output->recorder_frame_listener.notify = recorder_frame_notify;
5937 wl_signal_add(&output->base.frame_signal,
5938 &output->recorder_frame_listener);
5939
5940 weston_output_schedule_repaint(&output->base);
5941
5942 weston_log("[libva recorder] initialized\n");
5943 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03005944 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005945 }
5946}
5947#else
5948static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02005949recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
5950 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03005951{
5952 weston_log("Compiled without libva support\n");
5953}
5954#endif
5955
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005956static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03005957switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005958{
5959 struct drm_output *output;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03005960 bool dmabuf_support_inited;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005961
Giulio Camuffo954f1832014-10-11 18:27:30 +03005962 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005963 return;
5964
Pekka Paalanene4d231e2014-06-12 15:12:48 +03005965 dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
5966
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005967 weston_log("Switching to GL renderer\n");
5968
Giulio Camuffo954f1832014-10-11 18:27:30 +03005969 b->gbm = create_gbm_device(b->drm.fd);
5970 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005971 weston_log("Failed to create gbm device. "
5972 "Aborting renderer switch\n");
5973 return;
5974 }
5975
Giulio Camuffo954f1832014-10-11 18:27:30 +03005976 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005977 pixman_renderer_output_destroy(&output->base);
5978
Giulio Camuffo954f1832014-10-11 18:27:30 +03005979 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005980
Giulio Camuffo954f1832014-10-11 18:27:30 +03005981 if (drm_backend_create_gl_renderer(b) < 0) {
5982 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005983 weston_log("Failed to create GL renderer. Quitting.\n");
5984 /* FIXME: we need a function to shutdown cleanly */
5985 assert(0);
5986 }
5987
Giulio Camuffo954f1832014-10-11 18:27:30 +03005988 wl_list_for_each(output, &b->compositor->output_list, base.link)
5989 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005990
Giulio Camuffo954f1832014-10-11 18:27:30 +03005991 b->use_pixman = 0;
Pekka Paalanene4d231e2014-06-12 15:12:48 +03005992
5993 if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
5994 if (linux_dmabuf_setup(b->compositor) < 0)
5995 weston_log("Error: initializing dmabuf "
5996 "support failed.\n");
5997 }
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02005998}
5999
6000static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02006001renderer_switch_binding(struct weston_keyboard *keyboard,
6002 const struct timespec *time, uint32_t key, void *data)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006003{
Derek Foreman8ae2db52015-07-15 13:00:36 -05006004 struct drm_backend *b =
Armin Krezović545dba62016-08-05 15:54:18 +02006005 to_drm_backend(keyboard->seat->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006006
Giulio Camuffo954f1832014-10-11 18:27:30 +03006007 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02006008}
6009
Armin Krezović08368132016-09-30 14:11:05 +02006010static const struct weston_drm_output_api api = {
6011 drm_output_set_mode,
6012 drm_output_set_gbm_format,
6013 drm_output_set_seat,
6014};
6015
Giulio Camuffo954f1832014-10-11 18:27:30 +03006016static struct drm_backend *
6017drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006018 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006019{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006020 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01006021 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006022 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006023 const char *seat_id = default_seat;
Armin Krezović08368132016-09-30 14:11:05 +02006024 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006025
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04006026 weston_log("initializing drm backend\n");
6027
Giulio Camuffo954f1832014-10-11 18:27:30 +03006028 b = zalloc(sizeof *b);
6029 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006030 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01006031
Daniel Stone6020f472018-02-05 15:46:20 +00006032 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00006033 b->drm.fd = -1;
Daniel Stone087ddf02017-02-14 17:51:30 +00006034 wl_array_init(&b->unused_crtcs);
Daniel Stoneefa504f2016-12-19 16:48:20 +00006035
Pekka Paalanen68583832015-05-19 09:53:16 +03006036 /*
6037 * KMS support for hardware planes cannot properly synchronize
6038 * without nuclear page flip. Without nuclear/atomic, hw plane
6039 * and cursor plane updates would either tear or cause extra
6040 * waits for vblanks which means dropping the compositor framerate
Pekka Paalanen3f32a132015-09-07 15:38:43 +03006041 * to a fraction. For cursors, it's not so bad, so they are
6042 * enabled.
Pekka Paalanen68583832015-05-19 09:53:16 +03006043 *
6044 * These can be enabled again when nuclear/atomic support lands.
6045 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03006046 b->sprites_are_broken = 1;
Giulio Camuffo954f1832014-10-11 18:27:30 +03006047 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006048 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00006049 b->pageflip_timeout = config->pageflip_timeout;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006050
Pekka Paalanen7da9a382017-08-30 11:29:49 +03006051 compositor->backend = &b->base;
6052
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006053 if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
6054 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07006055
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006056 if (config->seat_id)
6057 seat_id = config->seat_id;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006058
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006059 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006060 compositor->launcher = weston_launcher_connect(compositor, config->tty,
6061 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006062 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02006063 weston_log("fatal: drm backend should be run using "
6064 "weston-launch binary, or your system should "
6065 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01006066 goto err_compositor;
6067 }
6068
Giulio Camuffo954f1832014-10-11 18:27:30 +03006069 b->udev = udev_new();
6070 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006071 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006072 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006073 }
6074
Giulio Camuffo954f1832014-10-11 18:27:30 +03006075 b->session_listener.notify = session_notify;
6076 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05006077
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03006078 if (config->specific_device)
6079 drm_device = open_specific_drm_device(b, config->specific_device);
6080 else
6081 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04006082 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02006083 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006084 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006085 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006086
Daniel Stoneefa504f2016-12-19 16:48:20 +00006087 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02006088 weston_log("failed to initialize kms\n");
6089 goto err_udev_dev;
6090 }
6091
Giulio Camuffo954f1832014-10-11 18:27:30 +03006092 if (b->use_pixman) {
6093 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006094 weston_log("failed to initialize pixman renderer\n");
6095 goto err_udev_dev;
6096 }
6097 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03006098 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02006099 weston_log("failed to initialize egl\n");
6100 goto err_udev_dev;
6101 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006102 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05006103
Giulio Camuffo954f1832014-10-11 18:27:30 +03006104 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00006105 b->base.repaint_begin = drm_repaint_begin;
6106 b->base.repaint_flush = drm_repaint_flush;
6107 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03006108 b->base.create_output = drm_output_create;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02006109
Bob Ham91880f12016-01-12 10:21:47 +00006110 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04006111
Daniel Stone085d2b92015-05-21 00:00:57 +01006112 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006113 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05006114
Giulio Camuffo954f1832014-10-11 18:27:30 +03006115 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03006116 compositor, b->udev, seat_id,
6117 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006118 weston_log("failed to create input devices\n");
6119 goto err_sprite;
6120 }
6121
Pekka Paalanend2e62422017-09-08 15:48:07 +03006122 if (drm_backend_create_heads(b, drm_device) < 0) {
6123 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006124 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006125 }
6126
Jason Ekstrand9fc71512014-04-02 19:53:46 -05006127 /* A this point we have some idea of whether or not we have a working
6128 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03006129 if (!b->cursors_are_broken)
6130 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05006131
Giulio Camuffo954f1832014-10-11 18:27:30 +03006132 loop = wl_display_get_event_loop(compositor->wl_display);
6133 b->drm_source =
6134 wl_event_loop_add_fd(loop, b->drm.fd,
6135 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04006136
Giulio Camuffo954f1832014-10-11 18:27:30 +03006137 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
6138 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05006139 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01006140 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006141 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03006142 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006143 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006144 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02006145 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03006146 udev_monitor_get_fd(b->udev_monitor),
6147 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006148
Giulio Camuffo954f1832014-10-11 18:27:30 +03006149 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02006150 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01006151 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01006152 }
6153
Daniel Stonea96b93c2012-06-22 14:04:37 +01006154 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006155
Giulio Camuffo954f1832014-10-11 18:27:30 +03006156 weston_compositor_add_debug_binding(compositor, KEY_O,
6157 planes_binding, b);
6158 weston_compositor_add_debug_binding(compositor, KEY_C,
6159 planes_binding, b);
6160 weston_compositor_add_debug_binding(compositor, KEY_V,
6161 planes_binding, b);
6162 weston_compositor_add_debug_binding(compositor, KEY_Q,
6163 recorder_binding, b);
6164 weston_compositor_add_debug_binding(compositor, KEY_W,
6165 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02006166
Pekka Paalanene4d231e2014-06-12 15:12:48 +03006167 if (compositor->renderer->import_dmabuf) {
6168 if (linux_dmabuf_setup(compositor) < 0)
6169 weston_log("Error: initializing dmabuf "
6170 "support failed.\n");
6171 }
6172
Armin Krezović08368132016-09-30 14:11:05 +02006173 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
6174 &api, sizeof(api));
6175
6176 if (ret < 0) {
6177 weston_log("Failed to register output API.\n");
6178 goto err_udev_monitor;
6179 }
6180
Giulio Camuffo954f1832014-10-11 18:27:30 +03006181 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01006182
6183err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006184 wl_event_source_remove(b->udev_drm_source);
6185 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006186err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006187 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03006188err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006189 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04006190err_sprite:
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01006191 if (b->gbm)
6192 gbm_device_destroy(b->gbm);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006193 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006194err_udev_dev:
6195 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07006196err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006197 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006198err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006199 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006200err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03006201 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006202 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01006203 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04006204}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006205
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006206static void
6207config_init_to_defaults(struct weston_drm_backend_config *config)
6208{
6209}
6210
Giulio Camuffo954f1832014-10-11 18:27:30 +03006211WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01006212weston_backend_init(struct weston_compositor *compositor,
6213 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006214{
Giulio Camuffo954f1832014-10-11 18:27:30 +03006215 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006216 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006217
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006218 if (config_base == NULL ||
6219 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
6220 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
6221 weston_log("drm backend config structure is invalid\n");
6222 return -1;
6223 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02006224
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006225 config_init_to_defaults(&config);
6226 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07006227
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006228 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03006229 if (b == NULL)
6230 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07006231
Giulio Camuffo954f1832014-10-11 18:27:30 +03006232 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04006233}