blob: 1ddf4f7f386a6e090f8ab5cd2c8ba3d221c7481d [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Pekka Paalanen925788f2018-04-19 14:20:01 +03004 * Copyright © 2017, 2018 Collabora, Ltd.
5 * Copyright © 2017, 2018 General Electric Company
Pekka Paalanen62a94362018-09-26 14:33:36 +03006 * Copyright (c) 2018 DisplayLink (UK) Ltd.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04007 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07008 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040015 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070016 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial
18 * portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040028 */
29
Daniel Stonec228e232013-05-22 18:03:19 +030030#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040031
Jesse Barnes58ef3792012-02-23 09:45:49 -050032#include <errno.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030033#include <stdint.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040034#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010035#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040036#include <string.h>
37#include <fcntl.h>
38#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040039#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070040#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030041#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020042#include <sys/mman.h>
Ander Conselvan de 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
Pekka Paalanen33156972012-08-03 13:30:30 -040049#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020050
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020051#include <libweston/libweston.h>
Pekka Paalanen75710272019-03-29 16:39:12 +020052#include <libweston/backend-drm.h>
Marius Vladc901e892019-06-21 22:49:18 +030053#include <libweston/weston-log.h>
Daniel Stonedd1bc502019-06-17 12:13:46 +010054#include "drm-internal.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070055#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020056#include "shared/timespec-util.h"
Ankit Nautiyala344fe32019-05-14 18:36:08 +053057#include "shared/string-helpers.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"
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030067#include "linux-explicit-synchronization.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040068
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050069static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -040070
Daniel Stone087ddf02017-02-14 17:51:30 +000071static void
Marius Vlade83e7502019-10-29 17:29:37 +020072drm_backend_create_faked_zpos(struct drm_backend *b)
73{
74 struct drm_plane *plane;
75 uint64_t zpos = 0ULL;
76 uint64_t zpos_min_primary;
77 uint64_t zpos_min_overlay;
78 uint64_t zpos_min_cursor;
79
80 zpos_min_primary = zpos;
81 wl_list_for_each(plane, &b->plane_list, link) {
82 /* if the property is there, bail out sooner */
83 if (plane->props[WDRM_PLANE_ZPOS].prop_id != 0)
84 return;
85
86 if (plane->type != WDRM_PLANE_TYPE_PRIMARY)
87 continue;
88 zpos++;
89 }
90
91 zpos_min_overlay = zpos;
92 wl_list_for_each(plane, &b->plane_list, link) {
93 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
94 continue;
95 zpos++;
96 }
97
98 zpos_min_cursor = zpos;
99 wl_list_for_each(plane, &b->plane_list, link) {
100 if (plane->type != WDRM_PLANE_TYPE_CURSOR)
101 continue;
102 zpos++;
103 }
104
105 drm_debug(b, "[drm-backend] zpos property not found. "
106 "Using invented immutable zpos values:\n");
107 /* assume that invented zpos values are immutable */
108 wl_list_for_each(plane, &b->plane_list, link) {
109 if (plane->type == WDRM_PLANE_TYPE_PRIMARY) {
110 plane->zpos_min = zpos_min_primary;
111 plane->zpos_max = zpos_min_primary;
112 } else if (plane->type == WDRM_PLANE_TYPE_OVERLAY) {
113 plane->zpos_min = zpos_min_overlay;
114 plane->zpos_max = zpos_min_overlay;
115 } else if (plane->type == WDRM_PLANE_TYPE_CURSOR) {
116 plane->zpos_min = zpos_min_cursor;
117 plane->zpos_max = zpos_min_cursor;
118 }
119 drm_debug(b, "\t[plane] %s plane %d, zpos_min %"PRIu64", "
120 "zpos_max %"PRIu64"\n",
121 drm_output_get_plane_type_name(plane),
122 plane->plane_id, plane->zpos_min, plane->zpos_max);
123 }
124}
125
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000126static int
127pageflip_timeout(void *data) {
128 /*
129 * Our timer just went off, that means we're not receiving drm
130 * page flip events anymore for that output. Let's gracefully exit
131 * weston with a return value so devs can debug what's going on.
132 */
133 struct drm_output *output = data;
134 struct weston_compositor *compositor = output->base.compositor;
135
136 weston_log("Pageflip timeout reached on output %s, your "
137 "driver is probably buggy! Exiting.\n",
138 output->base.name);
139 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
140
141 return 0;
142}
143
144/* Creates the pageflip timer. Note that it isn't armed by default */
145static int
146drm_output_pageflip_timer_create(struct drm_output *output)
147{
148 struct wl_event_loop *loop = NULL;
149 struct weston_compositor *ec = output->base.compositor;
150
151 loop = wl_display_get_event_loop(ec->wl_display);
152 assert(loop);
153 output->pageflip_timer = wl_event_loop_add_timer(loop,
154 pageflip_timeout,
155 output);
156
157 if (output->pageflip_timer == NULL) {
Antonio Borneo39578632019-04-26 23:57:31 +0200158 weston_log("creating drm pageflip timer failed: %s\n",
159 strerror(errno));
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +0000160 return -1;
161 }
162
163 return 0;
164}
165
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000166static void
167drm_output_destroy(struct weston_output *output_base);
168
Daniel Stone5ff289a2017-10-07 12:59:02 +0100169/**
170 * Returns true if the plane can be used on the given output for its current
171 * repaint cycle.
172 */
Daniel Stonee404b722019-06-22 18:40:31 +0100173bool
Daniel Stone5ff289a2017-10-07 12:59:02 +0100174drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500175{
Daniel Stone5ff289a2017-10-07 12:59:02 +0100176 assert(plane->state_cur);
177
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900178 if (output->virtual)
179 return false;
180
Daniel Stone5ff289a2017-10-07 12:59:02 +0100181 /* The plane still has a request not yet completed by the kernel. */
182 if (!plane->state_cur->complete)
183 return false;
184
185 /* The plane is still active on another output. */
186 if (plane->state_cur->output && plane->state_cur->output != output)
187 return false;
188
189 /* Check whether the plane can be used with this CRTC; possible_crtcs
190 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300191 return !!(plane->possible_crtcs & (1 << output->crtc->pipe));
Jesse Barnes58ef3792012-02-23 09:45:49 -0500192}
193
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300194struct drm_crtc *
195drm_crtc_find(struct drm_backend *b, uint32_t crtc_id)
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000196{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300197 struct drm_crtc *crtc;
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000198
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300199 wl_list_for_each(crtc, &b->crtc_list, link) {
200 if (crtc->crtc_id == crtc_id)
201 return crtc;
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000202 }
203
Daniel Stone72c0e1b2017-02-09 13:49:15 +0000204 return NULL;
205}
206
Daniel Stone4c2fc702019-06-18 11:12:07 +0100207struct drm_head *
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300208drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
209{
210 struct weston_head *base;
211 struct drm_head *head;
212
213 wl_list_for_each(base,
214 &backend->compositor->head_list, compositor_link) {
215 head = to_drm_head(base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -0300216 if (head->connector.connector_id == connector_id)
Pekka Paalanen54cc47c2017-08-31 11:58:41 +0300217 return head;
218 }
219
220 return NULL;
221}
222
Leandro Ribeiro96bef052020-09-09 15:23:49 -0300223static struct drm_writeback *
224drm_writeback_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
225{
226 struct drm_writeback *writeback;
227
228 wl_list_for_each(writeback, &backend->writeback_connector_list, link) {
229 if (writeback->connector.connector_id == connector_id)
230 return writeback;
231 }
232
233 return NULL;
234}
235
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000236/**
Daniel Stonea08512f2016-11-08 17:46:10 +0000237 * Get output state to disable output
238 *
239 * Returns a pointer to an output_state object which can be used to disable
240 * an output (e.g. DPMS off).
241 *
242 * @param pending_state The pending state object owning this update
243 * @param output The output to disable
244 * @returns A drm_output_state to disable the output
245 */
246static struct drm_output_state *
247drm_output_get_disable_state(struct drm_pending_state *pending_state,
248 struct drm_output *output)
249{
250 struct drm_output_state *output_state;
251
252 output_state = drm_output_state_duplicate(output->state_cur,
253 pending_state,
254 DRM_OUTPUT_STATE_CLEAR_PLANES);
255 output_state->dpms = WESTON_DPMS_OFF;
256
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530257 output_state->protection = WESTON_HDCP_DISABLE;
258
Daniel Stonea08512f2016-11-08 17:46:10 +0000259 return output_state;
260}
261
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000262
263/**
264 * Mark a drm_output_state (the output's last state) as complete. This handles
265 * any post-completion actions such as updating the repaint timer, disabling the
266 * output, and finally freeing the state.
267 */
Daniel Stone4c2fc702019-06-18 11:12:07 +0100268void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000269drm_output_update_complete(struct drm_output *output, uint32_t flags,
270 unsigned int sec, unsigned int usec)
271{
Daniel Stonea08512f2016-11-08 17:46:10 +0000272 struct drm_backend *b = to_drm_backend(output->base.compositor);
Daniel Stonebc15f682016-11-14 16:57:01 +0000273 struct drm_plane_state *ps;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000274 struct timespec ts;
275
276 /* Stop the pageflip timer instead of rearming it here */
277 if (output->pageflip_timer)
278 wl_event_source_timer_update(output->pageflip_timer, 0);
279
Daniel Stonebc15f682016-11-14 16:57:01 +0000280 wl_list_for_each(ps, &output->state_cur->plane_list, link)
281 ps->complete = true;
282
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000283 drm_output_state_free(output->state_last);
284 output->state_last = NULL;
285
286 if (output->destroy_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100287 output->destroy_pending = false;
288 output->disable_pending = false;
289 output->dpms_off_pending = false;
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000290 drm_output_destroy(&output->base);
291 return;
292 } else if (output->disable_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100293 output->disable_pending = false;
294 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +0000295 weston_output_disable(&output->base);
296 return;
297 } else if (output->dpms_off_pending) {
298 struct drm_pending_state *pending = drm_pending_state_alloc(b);
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +0100299 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +0000300 drm_output_get_disable_state(pending, output);
301 drm_pending_state_apply_sync(pending);
Michael Olbrichd70e7122020-08-06 09:57:54 +0200302 }
303 if (output->state_cur->dpms == WESTON_DPMS_OFF &&
304 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
Daniel Stonea08512f2016-11-08 17:46:10 +0000305 /* DPMS can happen to us either in the middle of a repaint
306 * cycle (when we have painted fresh content, only to throw it
307 * away for DPMS off), or at any other random point. If the
308 * latter is true, then we cannot go through finish_frame,
309 * because the repaint machinery does not expect this. */
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000310 return;
311 }
312
313 ts.tv_sec = sec;
314 ts.tv_nsec = usec * 1000;
315 weston_output_finish_frame(&output->base, &ts, flags);
316
317 /* We can't call this from frame_notify, because the output's
318 * repaint needed flag is cleared just after that */
319 if (output->recorder)
320 weston_output_schedule_repaint(&output->base);
321}
322
Daniel Stone95d48a22017-04-04 17:54:30 +0100323static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000324drm_output_render_pixman(struct drm_output_state *state,
325 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200326{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000327 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200328 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200329
330 output->current_image ^= 1;
331
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200332 pixman_renderer_output_set_buffer(&output->base,
333 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200334 pixman_renderer_output_set_hw_extra_damage(&output->base,
335 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200336
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200337 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200338
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200339 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +0100340
341 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200342}
343
Stefan Agner3654c672019-07-09 00:50:30 +0200344void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000345drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200346{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000347 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300348 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +0000349 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +0000350 struct drm_plane *scanout_plane = output->scanout_plane;
Scott Anderson15c603c2020-06-02 17:39:43 +1200351 struct drm_property_info *damage_info =
352 &scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
Armin Krezović545dba62016-08-05 15:54:18 +0200353 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +0100354 struct drm_fb *fb;
Scott Anderson15c603c2020-06-02 17:39:43 +1200355 pixman_region32_t scanout_damage;
356 pixman_box32_t *rects;
357 int n_rects;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200358
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100359 /* If we already have a client buffer promoted to scanout, then we don't
360 * want to render. */
Leandro Ribeiro05cecc82020-08-13 17:34:58 -0300361 scanout_state = drm_output_state_get_plane(state, scanout_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +0000362 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100363 return;
364
Daniel Stone98d75e12020-03-06 11:03:14 +0000365 /*
366 * If we don't have any damage on the primary plane, and we already
367 * have a renderer buffer active, we can reuse it; else we pass
368 * the damaged region into the renderer to re-render the affected
Pekka Paalanen7f1a1132020-12-07 14:59:44 +0200369 * area. But, we still have to call the renderer anyway if any screen
370 * capture is pending, otherwise the capture will not complete.
Daniel Stone98d75e12020-03-06 11:03:14 +0000371 */
Daniel Stonee95169b2016-11-14 17:46:59 +0000372 if (!pixman_region32_not_empty(damage) &&
Pekka Paalanen7f1a1132020-12-07 14:59:44 +0200373 wl_list_empty(&output->base.frame_signal.listener_list) &&
Daniel Stonee95169b2016-11-14 17:46:59 +0000374 scanout_plane->state_cur->fb &&
375 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
Daniel Stone98d75e12020-03-06 11:03:14 +0000376 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
Daniel Stonee95169b2016-11-14 17:46:59 +0000377 fb = drm_fb_ref(scanout_plane->state_cur->fb);
378 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000379 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000380 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000381 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000382 }
Daniel Stone95d48a22017-04-04 17:54:30 +0100383
Daniel Stonee2e80132018-01-16 15:37:33 +0000384 if (!fb) {
385 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +0100386 return;
Daniel Stonee2e80132018-01-16 15:37:33 +0000387 }
388
389 scanout_state->fb = fb;
390 scanout_state->output = output;
391
392 scanout_state->src_x = 0;
393 scanout_state->src_y = 0;
Daniel Stonef9a61622020-03-06 11:07:15 +0000394 scanout_state->src_w = fb->width << 16;
395 scanout_state->src_h = fb->height << 16;
Daniel Stonee2e80132018-01-16 15:37:33 +0000396
397 scanout_state->dest_x = 0;
398 scanout_state->dest_y = 0;
Daniel Stonef9a61622020-03-06 11:07:15 +0000399 scanout_state->dest_w = output->base.current_mode->width;
400 scanout_state->dest_h = output->base.current_mode->height;
Daniel Stonee2e80132018-01-16 15:37:33 +0000401
Scott Anderson15c603c2020-06-02 17:39:43 +1200402 pixman_region32_subtract(&c->primary_plane.damage,
403 &c->primary_plane.damage, damage);
404
405 /* Don't bother calculating plane damage if the plane doesn't support it */
406 if (damage_info->prop_id == 0)
407 return;
408
409 pixman_region32_init(&scanout_damage);
410 pixman_region32_copy(&scanout_damage, damage);
411
Deepak Rawat46a1c722018-07-24 14:13:34 -0700412 if (output->base.zoom.active) {
Scott Anderson15c603c2020-06-02 17:39:43 +1200413 weston_matrix_transform_region(&scanout_damage,
Deepak Rawat46a1c722018-07-24 14:13:34 -0700414 &output->base.matrix,
Scott Anderson15c603c2020-06-02 17:39:43 +1200415 &scanout_damage);
Deepak Rawat46a1c722018-07-24 14:13:34 -0700416 } else {
Scott Anderson15c603c2020-06-02 17:39:43 +1200417 pixman_region32_translate(&scanout_damage,
Deepak Rawat46a1c722018-07-24 14:13:34 -0700418 -output->base.x, -output->base.y);
419 weston_transformed_region(output->base.width,
420 output->base.height,
421 output->base.transform,
422 output->base.current_scale,
Scott Anderson15c603c2020-06-02 17:39:43 +1200423 &scanout_damage,
424 &scanout_damage);
Deepak Rawat46a1c722018-07-24 14:13:34 -0700425 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200426
Scott Anderson15c603c2020-06-02 17:39:43 +1200427 assert(scanout_state->damage_blob_id == 0);
428
429 rects = pixman_region32_rectangles(&scanout_damage, &n_rects);
430
431 /*
432 * If this function fails, the blob id should still be 0.
433 * This tells the kernel there is no damage information, which means
434 * that it will consider the whole plane damaged. While this may
435 * affect efficiency, it should still produce correct results.
436 */
437 drmModeCreatePropertyBlob(b->drm.fd, rects,
438 sizeof(*rects) * n_rects,
439 &scanout_state->damage_blob_id);
440
441 pixman_region32_fini(&scanout_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200442}
443
Daniel Stonea08512f2016-11-08 17:46:10 +0000444static int
445drm_output_repaint(struct weston_output *output_base,
446 pixman_region32_t *damage,
447 void *repaint_data)
448{
449 struct drm_pending_state *pending_state = repaint_data;
450 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +0000451 struct drm_output_state *state = NULL;
452 struct drm_plane_state *scanout_state;
453
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900454 assert(!output->virtual);
455
Daniel Stonea08512f2016-11-08 17:46:10 +0000456 if (output->disable_pending || output->destroy_pending)
457 goto err;
458
459 assert(!output->state_last);
460
461 /* If planes have been disabled in the core, we might not have
462 * hit assign_planes at all, so might not have valid output state
463 * here. */
464 state = drm_pending_state_get_output(pending_state, output);
465 if (!state)
466 state = drm_output_state_duplicate(output->state_cur,
467 pending_state,
468 DRM_OUTPUT_STATE_CLEAR_PLANES);
469 state->dpms = WESTON_DPMS_ON;
470
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530471 if (output_base->allow_protection)
472 state->protection = output_base->desired_protection;
473 else
474 state->protection = WESTON_HDCP_DISABLE;
475
Daniel Stonea08512f2016-11-08 17:46:10 +0000476 drm_output_render(state, damage);
477 scanout_state = drm_output_state_get_plane(state,
478 output->scanout_plane);
479 if (!scanout_state || !scanout_state->fb)
480 goto err;
481
Daniel Stonea08512f2016-11-08 17:46:10 +0000482 return 0;
483
484err:
485 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +0200486 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400487}
488
Daniel Stone4c2fc702019-06-18 11:12:07 +0100489/* Determine the type of vblank synchronization to use for the output.
490 *
491 * The pipe parameter indicates which CRTC is in use. Knowing this, we
492 * can determine which vblank sequence type to use for it. Traditional
493 * cards had only two CRTCs, with CRTC 0 using no special flags, and
494 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
495 * parameter indicates this.
496 *
497 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
498 * 0-31. If this is non-zero it indicates we're dealing with a
499 * multi-gpu situation and we need to calculate the vblank sync
500 * using DRM_BLANK_HIGH_CRTC_MASK.
501 */
502static unsigned int
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300503drm_waitvblank_pipe(struct drm_crtc *crtc)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100504{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300505 if (crtc->pipe > 1)
506 return (crtc->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
Daniel Stone4c2fc702019-06-18 11:12:07 +0100507 DRM_VBLANK_HIGH_CRTC_MASK;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300508 else if (crtc->pipe > 0)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100509 return DRM_VBLANK_SECONDARY;
510 else
511 return 0;
512}
513
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200514static int
Jonas Ådahle5a12252013-04-05 23:07:11 +0200515drm_output_start_repaint_loop(struct weston_output *output_base)
516{
Armin Krezović545dba62016-08-05 15:54:18 +0200517 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +0000518 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +0000519 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +0200520 struct drm_backend *backend =
521 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200522 struct timespec ts, tnow;
523 struct timespec vbl2now;
524 int64_t refresh_nsec;
525 int ret;
526 drmVBlank vbl = {
527 .request.type = DRM_VBLANK_RELATIVE,
528 .request.sequence = 0,
529 .request.signal = 0,
530 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300531
Armin Krezović08368132016-09-30 14:11:05 +0200532 if (output->disable_pending || output->destroy_pending)
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200533 return 0;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800534
Leandro Ribeiro05cecc82020-08-13 17:34:58 -0300535 if (!scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300536 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200537 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300538 }
539
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300540 /* Need to smash all state in from scratch; current timings might not
541 * be what we want, page flip might not work, etc.
542 */
Daniel Stone6020f472018-02-05 15:46:20 +0000543 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300544 goto finish_frame;
545
Daniel Stonee2e80132018-01-16 15:37:33 +0000546 assert(scanout_plane->state_cur->output == output);
547
Mario Kleinerf507ec32015-06-21 21:25:14 +0200548 /* Try to get current msc and timestamp via instant query */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300549 vbl.request.type |= drm_waitvblank_pipe(output->crtc);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200550 ret = drmWaitVBlank(backend->drm.fd, &vbl);
551
552 /* Error ret or zero timestamp means failure to get valid timestamp */
553 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
554 ts.tv_sec = vbl.reply.tval_sec;
555 ts.tv_nsec = vbl.reply.tval_usec * 1000;
556
557 /* Valid timestamp for most recent vblank - not stale?
558 * Stale ts could happen on Linux 3.17+, so make sure it
559 * is not older than 1 refresh duration since now.
560 */
561 weston_compositor_read_presentation_clock(backend->compositor,
562 &tnow);
563 timespec_sub(&vbl2now, &tnow, &ts);
564 refresh_nsec =
565 millihz_to_nsec(output->base.current_mode->refresh);
566 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
567 drm_output_update_msc(output, vbl.reply.sequence);
568 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200569 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200570 return 0;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200571 }
572 }
573
574 /* Immediate query didn't provide valid timestamp.
575 * Use pageflip fallback.
576 */
Jonas Ådahle5a12252013-04-05 23:07:11 +0200577
Daniel Stone205c0a02017-04-04 17:54:33 +0100578 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000579 assert(!output->state_last);
580
581 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +0000582 drm_output_state_duplicate(output->state_cur, pending_state,
583 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +0100584
Daniel Stone8747f952016-11-29 20:17:32 +0000585 ret = drm_pending_state_apply(pending_state);
586 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200587 weston_log("applying repaint-start state failed: %s\n",
588 strerror(errno));
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200589 if (ret == -EACCES)
590 return -1;
David Herrmann3c688c52013-10-22 17:11:25 +0200591 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200592 }
David Herrmann3c688c52013-10-22 17:11:25 +0200593
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200594 return 0;
David Herrmann3c688c52013-10-22 17:11:25 +0200595
596finish_frame:
597 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +0000598 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200599 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200600 return 0;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200601}
602
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000603/**
604 * Begin a new repaint cycle
605 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000606 * Called by the core compositor at the beginning of a repaint cycle. Creates
607 * a new pending_state structure to own any output state created by individual
608 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000609 */
610static void *
611drm_repaint_begin(struct weston_compositor *compositor)
612{
613 struct drm_backend *b = to_drm_backend(compositor);
614 struct drm_pending_state *ret;
615
616 ret = drm_pending_state_alloc(b);
617 b->repaint_data = ret;
618
Marius Vlad7e4db952019-04-17 13:47:06 +0300619 if (weston_log_scope_is_enabled(b->debug)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100620 char *dbg = weston_compositor_print_scene_graph(compositor);
621 drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
622 ret);
623 drm_debug(b, "%s", dbg);
624 free(dbg);
625 }
626
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000627 return ret;
628}
629
630/**
631 * Flush a repaint set
632 *
633 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000634 * and should be flushed. Frees the pending state, transitioning ownership
635 * of the output state from the pending state, to the update itself. When
636 * the update completes (see drm_output_update_complete), the output
637 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000638 */
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200639static int
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000640drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
641{
642 struct drm_backend *b = to_drm_backend(compositor);
643 struct drm_pending_state *pending_state = repaint_data;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200644 int ret;
Daniel Stone6020f472018-02-05 15:46:20 +0000645
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200646 ret = drm_pending_state_apply(pending_state);
647 if (ret != 0)
648 weston_log("repaint-flush failed: %s\n", strerror(errno));
649
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100650 drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000651 b->repaint_data = NULL;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200652
653 return (ret == -EACCES) ? -1 : 0;
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000654}
655
656/**
657 * Cancel a repaint set
658 *
659 * Called by the core compositor when a repaint has finished, so the data
660 * held across the repaint cycle should be discarded.
661 */
662static void
663drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
664{
665 struct drm_backend *b = to_drm_backend(compositor);
666 struct drm_pending_state *pending_state = repaint_data;
667
668 drm_pending_state_free(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100669 drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000670 b->repaint_data = NULL;
671}
672
Alex Wub7b8bda2012-04-17 17:20:48 +0800673static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300674drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +0000675static void
676drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200677
678static int
Alex Wub7b8bda2012-04-17 17:20:48 +0800679drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
680{
Daniel Stone02d487a2017-10-07 14:01:45 +0100681 struct drm_output *output = to_drm_output(output_base);
682 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stonefbe6c1d2019-06-17 16:04:26 +0100683 struct drm_mode *drm_mode = drm_output_choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +0800684
685 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +0100686 weston_log("%s: invalid resolution %dx%d\n",
687 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800688 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200689 }
690
Hardeningff39efa2013-09-18 23:56:35 +0200691 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +0800692 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800693
Hardeningff39efa2013-09-18 23:56:35 +0200694 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800695
Hardeningff39efa2013-09-18 23:56:35 +0200696 output->base.current_mode = &drm_mode->base;
697 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +0800698 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
699
Daniel Stonef30a18c2017-04-04 17:54:31 +0100700 /* XXX: This drops our current buffer too early, before we've started
701 * displaying it. Ideally this should be much more atomic and
702 * integrated with a full repaint cycle, rather than doing a
703 * sledgehammer modeswitch first, and only later showing new
704 * content.
705 */
Daniel Stone6020f472018-02-05 15:46:20 +0000706 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +0800707
Giulio Camuffo954f1832014-10-11 18:27:30 +0300708 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200709 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300710 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200711 weston_log("failed to init output pixman state with "
712 "new mode\n");
713 return -1;
714 }
715 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +0000716 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300717 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200718 weston_log("failed to init output egl state with "
719 "new mode");
720 return -1;
721 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200722 }
723
Alex Wub7b8bda2012-04-17 17:20:48 +0800724 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800725}
726
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200727static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300728init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200729{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300730 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200731}
732
Pekka Paalanen7b36b422014-06-04 14:00:53 +0300733/**
Pekka Paalanenec272712014-06-05 11:22:25 +0300734 * Create a drm_plane for a hardware plane
735 *
736 * Creates one drm_plane structure for a hardware plane, and initialises its
737 * properties and formats.
738 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100739 * In the absence of universal plane support, where KMS does not explicitly
740 * expose the primary and cursor planes to userspace, this may also create
741 * an 'internal' plane for internal management.
742 *
Pekka Paalanenec272712014-06-05 11:22:25 +0300743 * This function does not add the plane to the list of usable planes in Weston
744 * itself; the caller is responsible for this.
745 *
746 * Call drm_plane_destroy to clean up the plane.
747 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100748 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +0300749 * @param b DRM compositor backend
Daniel Stone2ba17f42015-05-19 20:02:41 +0100750 * @param kplane DRM plane to create, or NULL if creating internal plane
751 * @param output Output to create internal plane for, or NULL
752 * @param type Type to use when creating internal plane, or invalid
753 * @param format Format to use for internal planes, or 0
Pekka Paalanenec272712014-06-05 11:22:25 +0300754 */
755static struct drm_plane *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100756drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
757 struct drm_output *output, enum wdrm_plane_type type,
758 uint32_t format)
Pekka Paalanenec272712014-06-05 11:22:25 +0300759{
760 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100761 drmModeObjectProperties *props;
Marius Vladcdd6fa22019-08-29 20:42:00 +0300762 uint64_t *zpos_range_values;
Sergi Granellf4456222017-01-12 17:17:32 +0000763 uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100764
Daniel Stone2ba17f42015-05-19 20:02:41 +0100765 plane = zalloc(sizeof(*plane) +
Sergi Granellf4456222017-01-12 17:17:32 +0000766 (sizeof(plane->formats[0]) * num_formats));
Pekka Paalanenec272712014-06-05 11:22:25 +0300767 if (!plane) {
768 weston_log("%s: out of memory\n", __func__);
769 return NULL;
770 }
771
772 plane->backend = b;
Sergi Granellf4456222017-01-12 17:17:32 +0000773 plane->count_formats = num_formats;
Daniel Stonebc15f682016-11-14 16:57:01 +0000774 plane->state_cur = drm_plane_state_alloc(NULL, plane);
775 plane->state_cur->complete = true;
Pekka Paalanenec272712014-06-05 11:22:25 +0300776
Daniel Stone2ba17f42015-05-19 20:02:41 +0100777 if (kplane) {
778 plane->possible_crtcs = kplane->possible_crtcs;
779 plane->plane_id = kplane->plane_id;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100780
781 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
782 DRM_MODE_OBJECT_PLANE);
783 if (!props) {
784 weston_log("couldn't get plane properties\n");
785 goto err;
786 }
787 drm_property_info_populate(b, plane_props, plane->props,
788 WDRM_PLANE__COUNT, props);
789 plane->type =
790 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
791 props,
792 WDRM_PLANE_TYPE__COUNT);
Sergi Granellf4456222017-01-12 17:17:32 +0000793
Marius Vladcdd6fa22019-08-29 20:42:00 +0300794 zpos_range_values =
Daniel Stone7fa97e62020-03-06 11:03:01 +0000795 drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
Marius Vladcdd6fa22019-08-29 20:42:00 +0300796 props);
797
798 if (zpos_range_values) {
799 plane->zpos_min = zpos_range_values[0];
800 plane->zpos_max = zpos_range_values[1];
801 } else {
802 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
803 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
804 }
805
Stefan Agner465ab2c2020-06-17 23:36:44 +0200806 if (drm_plane_populate_formats(plane, kplane, props,
807 b->fb_modifiers) < 0) {
Sergi Granellf4456222017-01-12 17:17:32 +0000808 drmModeFreeObjectProperties(props);
809 goto err;
810 }
811
Daniel Stone2ba17f42015-05-19 20:02:41 +0100812 drmModeFreeObjectProperties(props);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100813 }
Daniel Stone2ba17f42015-05-19 20:02:41 +0100814 else {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300815 plane->possible_crtcs = (1 << output->crtc->pipe);
Daniel Stone2ba17f42015-05-19 20:02:41 +0100816 plane->plane_id = 0;
817 plane->count_formats = 1;
Sergi Granellf4456222017-01-12 17:17:32 +0000818 plane->formats[0].format = format;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100819 plane->type = type;
Marius Vladcdd6fa22019-08-29 20:42:00 +0300820 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
821 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100822 }
823
824 if (plane->type == WDRM_PLANE_TYPE__COUNT)
825 goto err_props;
826
827 /* With universal planes, everything is a DRM plane; without
828 * universal planes, the only DRM planes are overlay planes.
829 * Everything else is a fake plane. */
830 if (b->universal_planes) {
831 assert(kplane);
832 } else {
833 if (kplane)
834 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
835 else
836 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
837 output);
838 }
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100839
Pekka Paalanenec272712014-06-05 11:22:25 +0300840 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +0100841 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +0300842
843 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100844
845err_props:
846 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
847err:
848 drm_plane_state_free(plane->state_cur, true);
849 free(plane);
850 return NULL;
851}
852
853/**
854 * Find, or create, a special-purpose plane
855 *
856 * Primary and cursor planes are a special case, in that before universal
857 * planes, they are driven by non-plane API calls. Without universal plane
858 * support, the only way to configure a primary plane is via drmModeSetCrtc,
859 * and the only way to configure a cursor plane is drmModeSetCursor2.
860 *
861 * Although they may actually be regular planes in the hardware, without
862 * universal plane support, these planes are not actually exposed to
863 * userspace in the regular plane list.
864 *
865 * However, for ease of internal tracking, we want to manage all planes
866 * through the same drm_plane structures. Therefore, when we are running
867 * without universal plane support, we create fake drm_plane structures
868 * to track these planes.
869 *
870 * @param b DRM backend
871 * @param output Output to use for plane
872 * @param type Type of plane
873 */
874static struct drm_plane *
875drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
876 enum wdrm_plane_type type)
877{
878 struct drm_plane *plane;
879
880 if (!b->universal_planes) {
881 uint32_t format;
882
883 switch (type) {
884 case WDRM_PLANE_TYPE_CURSOR:
Stefan Agner0bfebeb2019-07-08 00:30:44 +0200885 format = DRM_FORMAT_ARGB8888;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100886 break;
Daniel Stonee2e80132018-01-16 15:37:33 +0000887 case WDRM_PLANE_TYPE_PRIMARY:
888 /* We don't know what formats the primary plane supports
889 * before universal planes, so we just assume that the
890 * GBM format works; however, this isn't set until after
891 * the output is created. */
892 format = 0;
893 break;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100894 default:
895 assert(!"invalid type in drm_output_find_special_plane");
896 break;
897 }
898
899 return drm_plane_create(b, NULL, output, type, format);
900 }
901
902 wl_list_for_each(plane, &b->plane_list, link) {
903 struct drm_output *tmp;
904 bool found_elsewhere = false;
905
906 if (plane->type != type)
907 continue;
908 if (!drm_plane_is_available(plane, output))
909 continue;
910
911 /* On some platforms, primary/cursor planes can roam
912 * between different CRTCs, so make sure we don't claim the
913 * same plane for two outputs. */
Leandro Ribeiro05cecc82020-08-13 17:34:58 -0300914 wl_list_for_each(tmp, &b->compositor->output_list, base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +0000915 if (tmp->cursor_plane == plane ||
916 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +0100917 found_elsewhere = true;
918 break;
919 }
920 }
921
922 if (found_elsewhere)
923 continue;
924
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300925 plane->possible_crtcs = (1 << output->crtc->pipe);
Daniel Stone2ba17f42015-05-19 20:02:41 +0100926 return plane;
927 }
928
929 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +0300930}
931
932/**
933 * Destroy one DRM plane
934 *
935 * Destroy a DRM plane, removing it from screen and releasing its retained
936 * buffers in the process. The counterpart to drm_plane_create.
937 *
938 * @param plane Plane to deallocate (will be freed)
939 */
940static void
941drm_plane_destroy(struct drm_plane *plane)
942{
Daniel Stone2ba17f42015-05-19 20:02:41 +0100943 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
944 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
945 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +0000946 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100947 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +0300948 weston_plane_release(&plane->base);
949 wl_list_remove(&plane->link);
950 free(plane);
951}
952
953/**
954 * Initialise sprites (overlay planes)
955 *
956 * Walk the list of provided DRM planes, and add overlay planes.
957 *
958 * Call destroy_sprites to free these planes.
959 *
960 * @param b DRM compositor backend
961 */
962static void
963create_sprites(struct drm_backend *b)
964{
965 drmModePlaneRes *kplane_res;
966 drmModePlane *kplane;
967 struct drm_plane *drm_plane;
968 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +0300969 kplane_res = drmModeGetPlaneResources(b->drm.fd);
970 if (!kplane_res) {
971 weston_log("failed to get plane resources: %s\n",
972 strerror(errno));
973 return;
974 }
975
976 for (i = 0; i < kplane_res->count_planes; i++) {
977 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
978 if (!kplane)
979 continue;
980
Daniel Stone2ba17f42015-05-19 20:02:41 +0100981 drm_plane = drm_plane_create(b, kplane, NULL,
982 WDRM_PLANE_TYPE__COUNT, 0);
Pekka Paalanenec272712014-06-05 11:22:25 +0300983 drmModeFreePlane(kplane);
984 if (!drm_plane)
985 continue;
986
Daniel Stone085d2b92015-05-21 00:00:57 +0100987 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
988 weston_compositor_stack_plane(b->compositor,
989 &drm_plane->base,
990 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +0300991 }
992
993 drmModeFreePlaneResources(kplane_res);
994}
995
996/**
997 * Clean up sprites (overlay planes)
998 *
999 * The counterpart to create_sprites.
1000 *
1001 * @param b DRM compositor backend
1002 */
1003static void
1004destroy_sprites(struct drm_backend *b)
1005{
1006 struct drm_plane *plane, *next;
1007
Daniel Stone085d2b92015-05-21 00:00:57 +01001008 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +03001009 drm_plane_destroy(plane);
1010}
1011
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001012/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001013static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +03001014drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001015{
1016 long brightness, max_brightness, norm;
1017
Pekka Paalanence724242017-09-04 12:21:24 +03001018 brightness = backlight_get_brightness(head->backlight);
1019 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001020
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001021 /* convert it on a scale of 0 to 255 */
1022 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001023
1024 return (uint32_t) norm;
1025}
1026
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001027/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001028static void
1029drm_set_backlight(struct weston_output *output_base, uint32_t value)
1030{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001031 struct drm_output *output = to_drm_output(output_base);
1032 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001033 long max_brightness, new_brightness;
1034
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001035 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001036 return;
1037
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001038 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1039 if (!head->backlight)
1040 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001041
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001042 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001043
Pekka Paalanenecc8cce2017-09-12 16:14:31 +03001044 /* get denormalized value */
1045 new_brightness = (value * max_brightness) / 255;
1046
1047 backlight_set_brightness(head->backlight, new_brightness);
1048 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001049}
1050
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001051static void
1052drm_output_init_backlight(struct drm_output *output)
1053{
1054 struct weston_head *base;
1055 struct drm_head *head;
1056
1057 output->base.set_backlight = NULL;
1058
1059 wl_list_for_each(base, &output->base.head_list, output_link) {
1060 head = to_drm_head(base);
1061
1062 if (head->backlight) {
1063 weston_log("Initialized backlight for head '%s', device %s\n",
1064 head->base.name, head->backlight->path);
1065
1066 if (!output->base.set_backlight) {
1067 output->base.set_backlight = drm_set_backlight;
1068 output->base.backlight_current =
1069 drm_get_backlight(head);
1070 }
1071 }
1072 }
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001073}
1074
Daniel Stonea08512f2016-11-08 17:46:10 +00001075/**
1076 * Power output on or off
1077 *
1078 * The DPMS/power level of an output is used to switch it on or off. This
1079 * is DRM's hook for doing so, which can called either as part of repaint,
1080 * or independently of the repaint loop.
1081 *
1082 * If we are called as part of repaint, we simply set the relevant bit in
1083 * state and return.
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001084 *
1085 * This function is never called on a virtual output.
Daniel Stonea08512f2016-11-08 17:46:10 +00001086 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001087static void
1088drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1089{
Armin Krezović545dba62016-08-05 15:54:18 +02001090 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00001091 struct drm_backend *b = to_drm_backend(output_base->compositor);
1092 struct drm_pending_state *pending_state = b->repaint_data;
1093 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01001094 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001095
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001096 assert(!output->virtual);
1097
Daniel Stonea08512f2016-11-08 17:46:10 +00001098 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001099 return;
1100
Daniel Stonea08512f2016-11-08 17:46:10 +00001101 /* If we're being called during the repaint loop, then this is
1102 * simple: discard any previously-generated state, and create a new
1103 * state where we disable everything. When we come to flush, this
1104 * will be applied.
1105 *
1106 * However, we need to be careful: we can be called whilst another
1107 * output is in its repaint cycle (pending_state exists), but our
1108 * output still has an incomplete state application outstanding.
1109 * In that case, we need to wait until that completes. */
1110 if (pending_state && !output->state_last) {
1111 /* The repaint loop already sets DPMS on; we don't need to
1112 * explicitly set it on here, as it will already happen
1113 * whilst applying the repaint state. */
1114 if (level == WESTON_DPMS_ON)
1115 return;
1116
1117 state = drm_pending_state_get_output(pending_state, output);
1118 if (state)
1119 drm_output_state_free(state);
1120 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01001121 return;
1122 }
1123
Daniel Stonea08512f2016-11-08 17:46:10 +00001124 /* As we throw everything away when disabling, just send us back through
1125 * a repaint cycle. */
1126 if (level == WESTON_DPMS_ON) {
1127 if (output->dpms_off_pending)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001128 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +00001129 weston_output_schedule_repaint(output_base);
1130 return;
1131 }
1132
1133 /* If we've already got a request in the pipeline, then we need to
1134 * park our DPMS request until that request has quiesced. */
1135 if (output->state_last) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001136 output->dpms_off_pending = true;
Daniel Stonea08512f2016-11-08 17:46:10 +00001137 return;
1138 }
1139
1140 pending_state = drm_pending_state_alloc(b);
1141 drm_output_get_disable_state(pending_state, output);
1142 ret = drm_pending_state_apply_sync(pending_state);
1143 if (ret != 0)
1144 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001145}
1146
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001147static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001148 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
1149 [DRM_MODE_CONNECTOR_VGA] = "VGA",
1150 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
1151 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
1152 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
1153 [DRM_MODE_CONNECTOR_Composite] = "Composite",
1154 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
1155 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
1156 [DRM_MODE_CONNECTOR_Component] = "Component",
1157 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
1158 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
1159 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
1160 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
1161 [DRM_MODE_CONNECTOR_TV] = "TV",
1162 [DRM_MODE_CONNECTOR_eDP] = "eDP",
1163 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
1164 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Stefan Agner30e283d2018-08-20 17:11:38 +02001165 [DRM_MODE_CONNECTOR_DPI] = "DPI",
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001166};
1167
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001168/** Create a name given a DRM connector
1169 *
1170 * \param con The DRM connector whose type and id form the name.
1171 * \return A newly allocate string, or NULL on error. Must be free()'d
1172 * after use.
1173 *
1174 * The name does not identify the DRM display device.
1175 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001176static char *
1177make_connector_name(const drmModeConnector *con)
1178{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001179 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001180 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001181 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001182
1183 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1184 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001185
1186 if (!type_name)
1187 type_name = "UNNAMED";
1188
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001189 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
1190 if (ret < 0)
1191 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001192
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001193 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001194}
1195
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001196static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001197drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001198{
Hardeningff39efa2013-09-18 23:56:35 +02001199 int w = output->base.current_mode->width;
1200 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001201 uint32_t format = output->gbm_format;
1202 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001203 unsigned int i;
Daniel Stone61abf352020-03-06 12:46:30 +00001204 const struct pixman_renderer_output_options options = {
1205 .use_shadow = b->use_pixman_shadow,
1206 };
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001207
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001208 switch (format) {
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001209 case DRM_FORMAT_XRGB8888:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001210 pixman_format = PIXMAN_x8r8g8b8;
1211 break;
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001212 case DRM_FORMAT_RGB565:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001213 pixman_format = PIXMAN_r5g6b5;
1214 break;
1215 default:
1216 weston_log("Unsupported pixman format 0x%x\n", format);
1217 return -1;
1218 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001219
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001220 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001221 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001222 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001223 if (!output->dumb[i])
1224 goto err;
1225
1226 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001227 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001228 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00001229 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001230 if (!output->image[i])
1231 goto err;
1232 }
1233
Daniel Stone61abf352020-03-06 12:46:30 +00001234 if (pixman_renderer_output_create(&output->base, &options) < 0)
Pekka Paalanendee412d2018-04-23 11:44:58 +02001235 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05301236
Pekka Paalanendee412d2018-04-23 11:44:58 +02001237 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
1238 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001239
1240 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001241 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001242
1243 return 0;
1244
1245err:
1246 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1247 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01001248 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001249 if (output->image[i])
1250 pixman_image_unref(output->image[i]);
1251
1252 output->dumb[i] = NULL;
1253 output->image[i] = NULL;
1254 }
1255
1256 return -1;
1257}
1258
1259static void
1260drm_output_fini_pixman(struct drm_output *output)
1261{
Daniel Stonee2e80132018-01-16 15:37:33 +00001262 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001263 unsigned int i;
1264
Daniel Stonee2e80132018-01-16 15:37:33 +00001265 /* Destroying the Pixman surface will destroy all our buffers,
1266 * regardless of refcount. Ensure we destroy them here. */
1267 if (!b->shutting_down &&
1268 output->scanout_plane->state_cur->fb &&
1269 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
Alexandros Frantzis99751342020-05-18 15:22:49 +03001270 drm_plane_reset_state(output->scanout_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +00001271 }
1272
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001273 pixman_renderer_output_destroy(&output->base);
1274 pixman_region32_fini(&output->previous_damage);
1275
1276 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001277 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01001278 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001279 output->dumb[i] = NULL;
1280 output->image[i] = NULL;
1281 }
1282}
1283
Richard Hughes2b2092a2013-04-24 14:58:02 +01001284static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001285setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01001286 struct weston_output *output,
1287 const char *s)
1288{
1289 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05001290 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001291 struct udev_seat *seat;
1292
Giulio Camuffo954f1832014-10-11 18:27:30 +03001293 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05001294 if (!seat)
1295 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001296
Derek Foreman0720ea32015-07-15 13:00:35 -05001297 seat->base.output = output;
1298
Derek Foreman1281a362015-07-31 16:55:32 -05001299 pointer = weston_seat_get_pointer(&seat->base);
1300 if (pointer)
1301 weston_pointer_clamp(pointer,
1302 &pointer->x,
1303 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001304 }
1305}
1306
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001307static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03001308drm_output_attach_head(struct weston_output *output_base,
1309 struct weston_head *head_base)
1310{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001311 struct drm_backend *b = to_drm_backend(output_base->compositor);
1312
Pekka Paalanenc112f002017-08-28 16:27:20 +03001313 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
1314 return -1;
1315
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001316 if (!output_base->enabled)
1317 return 0;
1318
1319 /* XXX: ensure the configuration will work.
1320 * This is actually impossible without major infrastructure
1321 * work. */
1322
1323 /* Need to go through modeset to add connectors. */
1324 /* XXX: Ideally we'd do this per-output, not globally. */
1325 /* XXX: Doing it globally, what guarantees another output's update
1326 * will not clear the flag before this output is updated?
1327 */
1328 b->state_invalid = true;
1329
1330 weston_output_schedule_repaint(output_base);
1331
Pekka Paalanenc112f002017-08-28 16:27:20 +03001332 return 0;
1333}
1334
Pekka Paalanen7f853792017-11-29 14:33:33 +02001335static void
1336drm_output_detach_head(struct weston_output *output_base,
1337 struct weston_head *head_base)
1338{
1339 struct drm_backend *b = to_drm_backend(output_base->compositor);
1340
1341 if (!output_base->enabled)
1342 return;
1343
1344 /* Need to go through modeset to drop connectors that should no longer
1345 * be driven. */
1346 /* XXX: Ideally we'd do this per-output, not globally. */
1347 b->state_invalid = true;
1348
1349 weston_output_schedule_repaint(output_base);
1350}
1351
Stefan Agner3654c672019-07-09 00:50:30 +02001352int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001353parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001354{
Pekka Paalanen62a94362018-09-26 14:33:36 +03001355 const struct pixel_format_info *pinfo;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001356
Pekka Paalanen62a94362018-09-26 14:33:36 +03001357 if (s == NULL) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001358 *gbm_format = default_value;
Pekka Paalanen62a94362018-09-26 14:33:36 +03001359
1360 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001361 }
1362
Pekka Paalanen62a94362018-09-26 14:33:36 +03001363 pinfo = pixel_format_get_info_by_drm_name(s);
1364 if (!pinfo) {
1365 weston_log("fatal: unrecognized pixel format: %s\n", s);
1366
1367 return -1;
1368 }
1369
1370 /* GBM formats and DRM formats are identical. */
1371 *gbm_format = pinfo->format;
1372
1373 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001374}
1375
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001376static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001377drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001378{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001379 int drm_fd = backend->drm.fd;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001380 drmModeConnector *conn = head->connector.conn;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001381 drmModeEncoder *encoder;
1382 drmModeCrtc *crtc;
1383
1384 /* Get the current mode on the crtc that's currently driving
1385 * this connector. */
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001386 encoder = drmModeGetEncoder(drm_fd, conn->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001387 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001388 head->inherited_crtc_id = encoder->crtc_id;
1389
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001390 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
1391 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001392
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001393 if (crtc == NULL)
1394 return -1;
1395 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02001396 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001397 drmModeFreeCrtc(crtc);
1398 }
1399
1400 return 0;
1401}
1402
Armin Krezović08368132016-09-30 14:11:05 +02001403static void
1404drm_output_set_gbm_format(struct weston_output *base,
1405 const char *gbm_format)
1406{
1407 struct drm_output *output = to_drm_output(base);
1408 struct drm_backend *b = to_drm_backend(base->compositor);
1409
1410 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
1411 output->gbm_format = b->gbm_format;
1412}
1413
1414static void
1415drm_output_set_seat(struct weston_output *base,
1416 const char *seat)
1417{
1418 struct drm_output *output = to_drm_output(base);
1419 struct drm_backend *b = to_drm_backend(base->compositor);
1420
1421 setup_output_seat_constraint(b, &output->base,
1422 seat ? seat : "");
1423}
1424
1425static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001426drm_output_init_gamma_size(struct drm_output *output)
1427{
1428 struct drm_backend *backend = to_drm_backend(output->base.compositor);
1429 drmModeCrtc *crtc;
1430
1431 assert(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001432 assert(output->crtc);
1433 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc->crtc_id);
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001434 if (!crtc)
1435 return -1;
1436
1437 output->base.gamma_size = crtc->gamma_size;
1438
1439 drmModeFreeCrtc(crtc);
1440
1441 return 0;
1442}
1443
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001444static uint32_t
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001445drm_connector_get_possible_crtcs_mask(struct drm_connector *connector)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001446{
1447 uint32_t possible_crtcs = 0;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001448 drmModeConnector *conn = connector->conn;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001449 drmModeEncoder *encoder;
1450 int i;
1451
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001452 for (i = 0; i < conn->count_encoders; i++) {
1453 encoder = drmModeGetEncoder(connector->backend->drm.fd,
1454 conn->encoders[i]);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001455 if (!encoder)
1456 continue;
1457
1458 possible_crtcs |= encoder->possible_crtcs;
1459 drmModeFreeEncoder(encoder);
1460 }
1461
1462 return possible_crtcs;
1463}
1464
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001465/** Pick a CRTC that might be able to drive all attached connectors
1466 *
1467 * @param output The output whose attached heads to include.
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001468 * @return CRTC object to pick, or NULL on failure or not found.
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001469 */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001470static struct drm_crtc *
1471drm_output_pick_crtc(struct drm_output *output)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001472{
1473 struct drm_backend *backend;
1474 struct weston_head *base;
1475 struct drm_head *head;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001476 struct drm_crtc *crtc;
1477 struct drm_crtc *best_crtc = NULL;
1478 struct drm_crtc *fallback_crtc = NULL;
1479 struct drm_crtc *existing_crtc[32];
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001480 uint32_t possible_crtcs = 0xffffffff;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001481 unsigned n = 0;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001482 uint32_t crtc_id;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001483 unsigned int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001484 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001485
1486 backend = to_drm_backend(output->base.compositor);
1487
1488 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
1489 * because it is more often set wrong than not in the kernel. */
1490
1491 /* Accumulate a mask of possible crtcs and find existing routings. */
1492 wl_list_for_each(base, &output->base.head_list, output_link) {
1493 head = to_drm_head(base);
1494
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001495 possible_crtcs &=
1496 drm_connector_get_possible_crtcs_mask(&head->connector);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001497
1498 crtc_id = head->inherited_crtc_id;
1499 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001500 existing_crtc[n++] = drm_crtc_find(backend, crtc_id);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001501 }
1502
1503 /* Find a crtc that could drive each connector individually at least,
1504 * and prefer existing routings. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001505 wl_list_for_each(crtc, &backend->crtc_list, link) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001506
1507 /* Could the crtc not drive each connector? */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001508 if (!(possible_crtcs & (1 << crtc->pipe)))
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001509 continue;
1510
1511 /* Is the crtc already in use? */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001512 if (crtc->output)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001513 continue;
1514
1515 /* Try to preserve the existing CRTC -> connector routing;
1516 * it makes initialisation faster, and also since we have a
1517 * very dumb picking algorithm, may preserve a better
1518 * choice. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001519 for (i = 0; i < n; i++) {
1520 if (existing_crtc[i] == crtc)
1521 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001522 }
1523
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001524 /* Check if any other head had existing routing to this CRTC.
1525 * If they did, this is not the best CRTC as it might be needed
1526 * for another output we haven't enabled yet. */
1527 match = false;
1528 wl_list_for_each(base, &backend->compositor->head_list,
1529 compositor_link) {
1530 head = to_drm_head(base);
1531
1532 if (head->base.output == &output->base)
1533 continue;
1534
1535 if (weston_head_is_enabled(&head->base))
1536 continue;
1537
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001538 if (head->inherited_crtc_id == crtc->crtc_id) {
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001539 match = true;
1540 break;
1541 }
1542 }
1543 if (!match)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001544 best_crtc = crtc;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001545
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001546 fallback_crtc = crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001547 }
1548
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001549 if (best_crtc)
1550 return best_crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001551
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001552 if (fallback_crtc)
1553 return fallback_crtc;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001554
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001555 /* Likely possible_crtcs was empty due to asking for clones,
1556 * but since the DRM documentation says the kernel lies, let's
1557 * pick one crtc anyway. Trial and error is the only way to
1558 * be sure if something doesn't work. */
1559
1560 /* First pick any existing assignment. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001561 for (i = 0; i < n; i++) {
1562 crtc = existing_crtc[i];
1563 if (!crtc->output)
1564 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001565 }
1566
1567 /* Otherwise pick any available crtc. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001568 wl_list_for_each(crtc, &backend->crtc_list, link) {
1569 if (!crtc->output)
1570 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001571 }
1572
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001573 return NULL;
1574}
1575
1576/** Create an "empty" drm_crtc. It will only set its ID, pipe and props. After
1577 * all, it adds the object to the DRM-backend CRTC list.
1578 */
1579static struct drm_crtc *
1580drm_crtc_create(struct drm_backend *b, uint32_t crtc_id, uint32_t pipe)
1581{
1582 struct drm_crtc *crtc;
1583 drmModeObjectPropertiesPtr props;
1584
1585 props = drmModeObjectGetProperties(b->drm.fd, crtc_id,
1586 DRM_MODE_OBJECT_CRTC);
1587 if (!props) {
1588 weston_log("failed to get CRTC properties\n");
1589 return NULL;
1590 }
1591
1592 crtc = zalloc(sizeof(*crtc));
1593 if (!crtc)
1594 goto ret;
1595
1596 drm_property_info_populate(b, crtc_props, crtc->props_crtc,
1597 WDRM_CRTC__COUNT, props);
1598 crtc->backend = b;
1599 crtc->crtc_id = crtc_id;
1600 crtc->pipe = pipe;
1601 crtc->output = NULL;
1602
1603 /* Add it to the last position of the DRM-backend CRTC list */
1604 wl_list_insert(b->crtc_list.prev, &crtc->link);
1605
1606ret:
1607 drmModeFreeObjectProperties(props);
1608 return crtc;
1609}
1610
1611/** Destroy a drm_crtc object that was created with drm_crtc_create(). It will
1612 * also remove it from the DRM-backend CRTC list.
1613 */
1614static void
1615drm_crtc_destroy(struct drm_crtc *crtc)
1616{
1617 /* TODO: address the issue below to be able to remove the comment
1618 * from the assert.
1619 *
1620 * https://gitlab.freedesktop.org/wayland/weston/-/issues/421
1621 */
1622
1623 //assert(!crtc->output);
1624
1625 wl_list_remove(&crtc->link);
1626 drm_property_info_free(crtc->props_crtc, WDRM_CRTC__COUNT);
1627 free(crtc);
1628}
1629
1630/** Find all CRTCs of the fd and create drm_crtc objects for them.
1631 *
1632 * The CRTCs are saved in a list of the drm_backend and will keep there until
1633 * the fd gets closed.
1634 *
1635 * @param b The DRM-backend structure.
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03001636 * @param resources The DRM resources, it is taken with drmModeGetResources
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001637 * @return 0 on success (at least one CRTC in the list), -1 on failure.
1638 */
1639static int
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03001640drm_backend_create_crtc_list(struct drm_backend *b, drmModeRes *resources)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001641{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001642 struct drm_crtc *crtc, *crtc_tmp;
1643 int i;
1644
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001645 /* Iterate through all CRTCs */
1646 for (i = 0; i < resources->count_crtcs; i++) {
1647
1648 /* Let's create an object for the CRTC and add it to the list */
1649 crtc = drm_crtc_create(b, resources->crtcs[i], i);
1650 if (!crtc)
1651 goto err;
1652 }
1653
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001654 return 0;
1655
1656err:
1657 wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
1658 drm_crtc_destroy(crtc);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001659 return -1;
1660}
1661
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001662
1663/** Populates scanout and cursor planes for the output. Also sets the topology
1664 * of the planes by adding them to the plane stacking list.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001665 */
1666static int
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001667drm_output_init_planes(struct drm_output *output)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001668{
1669 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001670
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001671 output->scanout_plane =
1672 drm_output_find_special_plane(b, output,
1673 WDRM_PLANE_TYPE_PRIMARY);
1674 if (!output->scanout_plane) {
1675 weston_log("Failed to find primary plane for output %s\n",
1676 output->base.name);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001677 return -1;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001678 }
1679
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001680 weston_compositor_stack_plane(b->compositor,
1681 &output->scanout_plane->base,
1682 &b->compositor->primary_plane);
1683
Tomohito Esaki51048462020-03-30 17:10:54 +09001684 /* Without universal planes, we can't discover which formats are
1685 * supported by the primary plane; we just hope that the GBM format
1686 * works. */
1687 if (!b->universal_planes)
1688 output->scanout_plane->formats[0].format = output->gbm_format;
1689
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001690 /* Failing to find a cursor plane is not fatal, as we'll fall back
1691 * to software cursor. */
1692 output->cursor_plane =
1693 drm_output_find_special_plane(b, output,
1694 WDRM_PLANE_TYPE_CURSOR);
1695
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001696 if (output->cursor_plane)
1697 weston_compositor_stack_plane(b->compositor,
1698 &output->cursor_plane->base,
1699 NULL);
1700 else
1701 b->cursors_are_broken = true;
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001702
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001703 return 0;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001704}
1705
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001706/** The opposite of drm_output_init_planes(). First of all it removes the planes
1707 * from the plane stacking list. Then, in case we don't have support for
1708 * universal planes it destroys the planes. After all it sets the planes of the
1709 * output as NULL.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001710 */
1711static void
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001712drm_output_deinit_planes(struct drm_output *output)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001713{
1714 struct drm_backend *b = to_drm_backend(output->base.compositor);
1715
Alexandros Frantzis53a71cb2020-05-18 15:26:01 +03001716 /* If the compositor is already shutting down, the planes have already
1717 * been destroyed. */
1718 if (!b->shutting_down) {
Pekka Paalanen3d6721e2020-09-16 15:04:04 +03001719 wl_list_remove(&output->scanout_plane->base.link);
1720 wl_list_init(&output->scanout_plane->base.link);
1721
1722 if (output->cursor_plane) {
1723 wl_list_remove(&output->cursor_plane->base.link);
1724 wl_list_init(&output->cursor_plane->base.link);
1725 /* Turn off hardware cursor */
1726 drmModeSetCursor(b->drm.fd, output->crtc->crtc_id, 0, 0, 0);
1727 }
1728
Alexandros Frantzis53a71cb2020-05-18 15:26:01 +03001729 if (!b->universal_planes) {
1730 /* Without universal planes, our special planes are
1731 * pseudo-planes allocated at output creation, freed at
1732 * output destruction, and not usable by other outputs.
1733 */
1734 if (output->cursor_plane)
1735 drm_plane_destroy(output->cursor_plane);
1736 if (output->scanout_plane)
1737 drm_plane_destroy(output->scanout_plane);
1738 } else {
1739 /* With universal planes, the 'special' planes are
1740 * allocated at startup, freed at shutdown, and live on
1741 * the plane list in between. We want the planes to
1742 * continue to exist and be freed up for other outputs.
1743 */
1744 if (output->cursor_plane)
1745 drm_plane_reset_state(output->cursor_plane);
1746 if (output->scanout_plane)
1747 drm_plane_reset_state(output->scanout_plane);
1748 }
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001749 }
1750
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001751 output->cursor_plane = NULL;
1752 output->scanout_plane = NULL;
1753}
1754
1755/** Pick a CRTC and reserve it for the output.
1756 *
1757 * On failure, the output remains without a CRTC.
1758 *
1759 * @param output The output with no CRTC associated.
1760 * @return 0 on success, -1 on failure.
1761 */
1762static int
1763drm_output_attach_crtc(struct drm_output *output)
1764{
1765 output->crtc = drm_output_pick_crtc(output);
1766 if (!output->crtc) {
1767 weston_log("Output '%s': No available CRTCs.\n",
1768 output->base.name);
1769 return -1;
1770 }
1771
1772 /* Reserve the CRTC for the output */
1773 output->crtc->output = output;
1774
1775 return 0;
1776}
1777
1778/** Release reservation of the CRTC.
1779 *
1780 * Make the CRTC free to be reserved and used by another output.
1781 *
1782 * @param output The output that will release its CRTC.
1783 */
1784static void
1785drm_output_detach_crtc(struct drm_output *output)
1786{
1787 struct drm_backend *b = output->backend;
1788 struct drm_crtc *crtc = output->crtc;
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001789
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001790 crtc->output = NULL;
1791 output->crtc = NULL;
1792
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001793 /* Force resetting unused CRTCs */
1794 b->state_invalid = true;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001795}
1796
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001797static int
Armin Krezović08368132016-09-30 14:11:05 +02001798drm_output_enable(struct weston_output *base)
1799{
1800 struct drm_output *output = to_drm_output(base);
1801 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001802 int ret;
1803
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001804 assert(!output->virtual);
1805
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001806 ret = drm_output_attach_crtc(output);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001807 if (ret < 0)
1808 return -1;
1809
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001810 ret = drm_output_init_planes(output);
1811 if (ret < 0)
1812 goto err_crtc;
1813
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001814 if (drm_output_init_gamma_size(output) < 0)
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001815 goto err_planes;
Armin Krezović08368132016-09-30 14:11:05 +02001816
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001817 if (b->pageflip_timeout)
1818 drm_output_pageflip_timer_create(output);
1819
Giulio Camuffo954f1832014-10-11 18:27:30 +03001820 if (b->use_pixman) {
1821 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001822 weston_log("Failed to init output pixman state\n");
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001823 goto err_planes;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001824 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03001825 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001826 weston_log("Failed to init output gl state\n");
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001827 goto err_planes;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001828 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001829
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001830 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001831
Jonas Ådahle5a12252013-04-05 23:07:11 +02001832 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001833 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001834 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001835 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001836 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01001837 output->base.set_gamma = drm_output_set_gamma;
1838
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001839 weston_log("Output %s (crtc %d) video modes:\n",
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001840 output->base.name, output->crtc->crtc_id);
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001841 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001842
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001843 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001844
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001845err_planes:
1846 drm_output_deinit_planes(output);
1847err_crtc:
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001848 drm_output_detach_crtc(output);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001849 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001850}
1851
Jesse Barnes58ef3792012-02-23 09:45:49 -05001852static void
Armin Krezović08368132016-09-30 14:11:05 +02001853drm_output_deinit(struct weston_output *base)
1854{
1855 struct drm_output *output = to_drm_output(base);
1856 struct drm_backend *b = to_drm_backend(base->compositor);
1857
Daniel Stone3e661f72016-11-04 17:24:06 +00001858 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02001859 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00001860 else
1861 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02001862
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001863 drm_output_deinit_planes(output);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001864 drm_output_detach_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02001865}
1866
1867static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03001868drm_head_destroy(struct drm_head *head);
1869
1870static void
Armin Krezović08368132016-09-30 14:11:05 +02001871drm_output_destroy(struct weston_output *base)
1872{
1873 struct drm_output *output = to_drm_output(base);
1874 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02001875
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001876 assert(!output->virtual);
1877
Daniel Stone31838bf2019-06-17 11:23:25 +01001878 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001879 output->destroy_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001880 weston_log("destroy output while page flip pending\n");
1881 return;
1882 }
1883
1884 if (output->base.enabled)
1885 drm_output_deinit(&output->base);
1886
Pekka Paalanen383b3af2017-09-11 14:40:48 +03001887 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02001888
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001889 if (output->pageflip_timer)
1890 wl_event_source_remove(output->pageflip_timer);
1891
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03001892 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02001893
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001894 assert(!output->state_last);
1895 drm_output_state_free(output->state_cur);
1896
Armin Krezović08368132016-09-30 14:11:05 +02001897 free(output);
1898}
1899
1900static int
1901drm_output_disable(struct weston_output *base)
1902{
1903 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02001904
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001905 assert(!output->virtual);
1906
Daniel Stone31838bf2019-06-17 11:23:25 +01001907 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001908 output->disable_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001909 return -1;
1910 }
1911
Daniel Stonea08512f2016-11-08 17:46:10 +00001912 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00001913
Armin Krezović08368132016-09-30 14:11:05 +02001914 if (output->base.enabled)
1915 drm_output_deinit(&output->base);
1916
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001917 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02001918
Armin Krezović08368132016-09-30 14:11:05 +02001919 return 0;
1920}
1921
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301922/*
1923 * This function converts the protection status from drm values to
1924 * weston_hdcp_protection status. The drm values as read from the connector
1925 * properties "Content Protection" and "HDCP Content Type" need to be converted
1926 * to appropriate weston values, that can be sent to a client application.
1927 */
1928static int
1929get_weston_protection_from_drm(enum wdrm_content_protection_state protection,
1930 enum wdrm_hdcp_content_type type,
1931 enum weston_hdcp_protection *weston_protection)
1932
1933{
1934 if (protection >= WDRM_CONTENT_PROTECTION__COUNT)
1935 return -1;
1936 if (protection == WDRM_CONTENT_PROTECTION_DESIRED ||
1937 protection == WDRM_CONTENT_PROTECTION_UNDESIRED) {
1938 *weston_protection = WESTON_HDCP_DISABLE;
1939 return 0;
1940 }
1941 if (type >= WDRM_HDCP_CONTENT_TYPE__COUNT)
1942 return -1;
1943 if (type == WDRM_HDCP_CONTENT_TYPE0) {
1944 *weston_protection = WESTON_HDCP_ENABLE_TYPE_0;
1945 return 0;
1946 }
1947 if (type == WDRM_HDCP_CONTENT_TYPE1) {
1948 *weston_protection = WESTON_HDCP_ENABLE_TYPE_1;
1949 return 0;
1950 }
1951 return -1;
1952}
1953
1954/**
1955 * Get current content-protection status for a given head.
1956 *
1957 * @param head drm_head, whose protection is to be retrieved
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301958 * @return protection status in case of success, -1 otherwise
1959 */
1960static enum weston_hdcp_protection
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03001961drm_head_get_current_protection(struct drm_head *head)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301962{
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03001963 drmModeObjectProperties *props = head->connector.props_drm;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301964 struct drm_property_info *info;
1965 enum wdrm_content_protection_state protection;
1966 enum wdrm_hdcp_content_type type;
1967 enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
1968
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001969 info = &head->connector.props[WDRM_CONNECTOR_CONTENT_PROTECTION];
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301970 protection = drm_property_get_value(info, props,
1971 WDRM_CONTENT_PROTECTION__COUNT);
1972
1973 if (protection == WDRM_CONTENT_PROTECTION__COUNT)
1974 return WESTON_HDCP_DISABLE;
1975
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001976 info = &head->connector.props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301977 type = drm_property_get_value(info, props,
1978 WDRM_HDCP_CONTENT_TYPE__COUNT);
1979
1980 /*
1981 * In case of platforms supporting HDCP1.4, only property
1982 * 'Content Protection' is exposed and not the 'HDCP Content Type'
1983 * for such cases HDCP Type 0 should be considered as the content-type.
1984 */
1985
1986 if (type == WDRM_HDCP_CONTENT_TYPE__COUNT)
1987 type = WDRM_HDCP_CONTENT_TYPE0;
1988
1989 if (get_weston_protection_from_drm(protection, type,
1990 &weston_hdcp) == -1) {
1991 weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
1992 protection, type, head->base.name,
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001993 head->connector.connector_id);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301994 return WESTON_HDCP_DISABLE;
1995 }
1996
1997 return weston_hdcp;
1998}
1999
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002000static int
2001drm_connector_update_properties(struct drm_connector *connector)
2002{
2003 drmModeObjectProperties *props;
2004
2005 props = drmModeObjectGetProperties(connector->backend->drm.fd,
2006 connector->connector_id,
2007 DRM_MODE_OBJECT_CONNECTOR);
2008 if (!props) {
2009 weston_log("Error: failed to get connector properties\n");
2010 return -1;
2011 }
2012
2013 if (connector->props_drm)
2014 drmModeFreeObjectProperties(connector->props_drm);
2015 connector->props_drm = props;
2016
2017 return 0;
2018}
2019
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002020/** Replace connector data and monitor information
2021 *
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002022 * @param connector The drm_connector object to be updated.
2023 * @param conn The connector data to be owned by the drm_connector, must match
2024 * the current drm_connector ID.
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002025 * @return 0 on success, -1 on failure.
2026 *
2027 * Takes ownership of @c connector on success, not on failure.
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002028 */
2029static int
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002030drm_connector_assign_connector_info(struct drm_connector *connector,
2031 drmModeConnector *conn)
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002032{
Leandro Ribeiro70863962020-09-09 13:12:35 -03002033 assert(connector->conn != conn);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002034 assert(connector->connector_id == conn->connector_id);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002035
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002036 if (drm_connector_update_properties(connector) < 0)
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002037 return -1;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002038
Leandro Ribeiro70863962020-09-09 13:12:35 -03002039 if (connector->conn)
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002040 drmModeFreeConnector(connector->conn);
2041 connector->conn = conn;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002042
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002043 drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
2044 drm_property_info_populate(connector->backend, connector_props,
2045 connector->props,
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002046 WDRM_CONNECTOR__COUNT, connector->props_drm);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002047 return 0;
2048}
2049
Leandro Ribeiro70863962020-09-09 13:12:35 -03002050static void
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002051drm_connector_init(struct drm_backend *b, struct drm_connector *connector,
2052 uint32_t connector_id)
2053{
2054 connector->backend = b;
2055 connector->connector_id = connector_id;
Leandro Ribeiro70863962020-09-09 13:12:35 -03002056 connector->conn = NULL;
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002057 connector->props_drm = NULL;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002058}
2059
2060static void
2061drm_connector_fini(struct drm_connector *connector)
2062{
2063 drmModeFreeConnector(connector->conn);
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002064 drmModeFreeObjectProperties(connector->props_drm);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002065 drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
2066}
2067
Pekka Paalanen456dc732017-11-09 15:10:11 +02002068static void
2069drm_head_log_info(struct drm_head *head, const char *msg)
2070{
2071 if (head->base.connected) {
2072 weston_log("DRM: head '%s' %s, connector %d is connected, "
2073 "EDID make '%s', model '%s', serial '%s'\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002074 head->base.name, msg, head->connector.connector_id,
Pekka Paalanen456dc732017-11-09 15:10:11 +02002075 head->base.make, head->base.model,
2076 head->base.serial_number ?: "");
2077 } else {
2078 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002079 head->base.name, msg, head->connector.connector_id);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002080 }
2081}
2082
Pekka Paalanend2e62422017-09-08 15:48:07 +03002083/** Update connector and monitor information
2084 *
2085 * @param head The head to update.
Leandro Ribeiro70863962020-09-09 13:12:35 -03002086 * @param conn The DRM connector object.
2087 * @returns 0 on success, -1 on failure.
Pekka Paalanend2e62422017-09-08 15:48:07 +03002088 *
Leandro Ribeiro70863962020-09-09 13:12:35 -03002089 * Updates monitor information and connection status. This may schedule a
2090 * heads changed call to the user.
Leandro Ribeiro4a5b67a2020-09-15 15:30:35 -03002091 *
2092 * Takes ownership of @c connector on success, not on failure.
Pekka Paalanend2e62422017-09-08 15:48:07 +03002093 */
Leandro Ribeiro70863962020-09-09 13:12:35 -03002094static int
2095drm_head_update_info(struct drm_head *head, drmModeConnector *conn)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002096{
Leandro Ribeiro70863962020-09-09 13:12:35 -03002097 int ret;
Pekka Paalanend2e62422017-09-08 15:48:07 +03002098
Leandro Ribeiro70863962020-09-09 13:12:35 -03002099 ret = drm_connector_assign_connector_info(&head->connector, conn);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002100
Leandro Ribeiro67941642020-09-15 00:11:02 -03002101 update_head_from_connector(head);
2102 weston_head_set_content_protection_status(&head->base,
2103 drm_head_get_current_protection(head));
2104
Pekka Paalanen456dc732017-11-09 15:10:11 +02002105 if (head->base.device_changed)
2106 drm_head_log_info(head, "updated");
Leandro Ribeiro70863962020-09-09 13:12:35 -03002107
2108 return ret;
Pekka Paalanend2e62422017-09-08 15:48:07 +03002109}
2110
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002111/** Update writeback connector
2112 *
2113 * @param writeback The writeback to update.
2114 * @param conn DRM connector object.
2115 * @returns 0 on success, -1 on failure.
2116 *
2117 * Takes ownership of @c connector on success, not on failure.
2118 */
2119static int
2120drm_writeback_update_info(struct drm_writeback *writeback, drmModeConnector *conn)
2121{
2122 int ret;
2123
2124 ret = drm_connector_assign_connector_info(&writeback->connector, conn);
2125
2126 return ret;
2127}
2128
Daniel Stone087ddf02017-02-14 17:51:30 +00002129/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03002130 * Create a Weston head for a connector
2131 *
2132 * Given a DRM connector, create a matching drm_head structure and add it
2133 * to Weston's head list.
2134 *
Marius Vlada2dace22019-06-12 16:05:44 +03002135 * @param backend Weston backend structure
Leandro Ribeiro70863962020-09-09 13:12:35 -03002136 * @param conn DRM connector object
Pekka Paalanenc112f002017-08-28 16:27:20 +03002137 * @param drm_device udev device pointer
Leandro Ribeiro70863962020-09-09 13:12:35 -03002138 * @returns 0 on success, -1 on failure
Leandro Ribeiro4a5b67a2020-09-15 15:30:35 -03002139 *
2140 * Takes ownership of @c connector on success, not on failure.
Pekka Paalanenc112f002017-08-28 16:27:20 +03002141 */
Leandro Ribeiro70863962020-09-09 13:12:35 -03002142static int
2143drm_head_create(struct drm_backend *backend, drmModeConnector *conn,
Pekka Paalanenc112f002017-08-28 16:27:20 +03002144 struct udev_device *drm_device)
2145{
2146 struct drm_head *head;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002147 char *name;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002148 int ret;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002149
2150 head = zalloc(sizeof *head);
2151 if (!head)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002152 return -1;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002153
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002154 head->backend = backend;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002155
Leandro Ribeiro70863962020-09-09 13:12:35 -03002156 drm_connector_init(backend, &head->connector, conn->connector_id);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002157
2158 name = make_connector_name(conn);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002159 if (!name)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002160 goto err;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002161
2162 weston_head_init(&head->base, name);
2163 free(name);
2164
Leandro Ribeiro67941642020-09-15 00:11:02 -03002165 ret = drm_head_update_info(head, conn);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002166 if (ret < 0)
Leandro Ribeiro67941642020-09-15 00:11:02 -03002167 goto err_update;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002168
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002169 head->backlight = backlight_init(drm_device, conn->connector_type);
Pekka Paalanence724242017-09-04 12:21:24 +03002170
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002171 if (conn->connector_type == DRM_MODE_CONNECTOR_LVDS ||
2172 conn->connector_type == DRM_MODE_CONNECTOR_eDP)
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002173 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002174
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02002175 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002176 weston_log("Failed to retrieve current mode from connector %d.\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002177 head->connector.connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02002178 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002179 }
2180
Pekka Paalanenc112f002017-08-28 16:27:20 +03002181 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002182 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03002183
Leandro Ribeiro70863962020-09-09 13:12:35 -03002184 return 0;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002185
Leandro Ribeiro67941642020-09-15 00:11:02 -03002186err_update:
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002187 weston_head_release(&head->base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002188err:
Leandro Ribeiro70863962020-09-09 13:12:35 -03002189 drm_connector_fini(&head->connector);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002190 free(head);
Leandro Ribeiro70863962020-09-09 13:12:35 -03002191 return -1;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002192}
2193
2194static void
2195drm_head_destroy(struct drm_head *head)
2196{
2197 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03002198
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002199 drm_connector_fini(&head->connector);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002200
Pekka Paalanence724242017-09-04 12:21:24 +03002201 if (head->backlight)
2202 backlight_destroy(head->backlight);
2203
Pekka Paalanenc112f002017-08-28 16:27:20 +03002204 free(head);
2205}
2206
2207/**
Armin Krezović08368132016-09-30 14:11:05 +02002208 * Create a Weston output structure
2209 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002210 * Create an "empty" drm_output. This is the implementation of
2211 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02002212 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002213 * Creating an output is usually followed by drm_output_attach_head()
2214 * and drm_output_enable() to make use of it.
2215 *
2216 * @param compositor The compositor instance.
2217 * @param name Name for the new output.
2218 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02002219 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03002220static struct weston_output *
2221drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02002222{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002223 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02002224 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02002225
Armin Krezović08368132016-09-30 14:11:05 +02002226 output = zalloc(sizeof *output);
2227 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002228 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02002229
Daniel Stone64dbbee2018-07-20 19:00:06 +01002230 output->backend = b;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002231 output->crtc = NULL;
2232
Stefan Agnerccf24072019-07-09 22:02:00 +02002233#ifdef BUILD_DRM_GBM
Tomohito Esaki718a40b2018-01-31 17:50:15 +09002234 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
Stefan Agnerccf24072019-07-09 22:02:00 +02002235#endif
Daniel Stone64dbbee2018-07-20 19:00:06 +01002236
Pekka Paalanend2e62422017-09-08 15:48:07 +03002237 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002238
Armin Krezović08368132016-09-30 14:11:05 +02002239 output->base.enable = drm_output_enable;
2240 output->base.destroy = drm_output_destroy;
2241 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002242 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02002243 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02002244
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002245 output->destroy_pending = false;
2246 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02002247
Pekka Paalanen01f60212017-03-24 15:39:24 +02002248 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03002249
Armin Krezović08368132016-09-30 14:11:05 +02002250 weston_compositor_add_pending_output(&output->base, b->compositor);
2251
Pekka Paalanend2e62422017-09-08 15:48:07 +03002252 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02002253}
2254
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002255/**
2256 * Create a Weston writeback for a writeback connector
Leandro Ribeiro72430222020-09-14 17:41:41 -03002257 *
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002258 * Given a DRM connector of type writeback, create a matching drm_writeback
2259 * structure and add it to Weston's writeback list.
2260 *
2261 * @param b Weston backend structure
2262 * @param conn DRM connector object of type writeback
2263 * @returns 0 on success, -1 on failure
2264 *
2265 * Takes ownership of @c connector on success, not on failure.
2266 */
2267static int
2268drm_writeback_create(struct drm_backend *b, drmModeConnector *conn)
2269{
2270 struct drm_writeback *writeback;
2271 int ret;
2272
2273 writeback = zalloc(sizeof *writeback);
2274 assert(writeback);
2275
2276 writeback->backend = b;
2277
2278 drm_connector_init(b, &writeback->connector, conn->connector_id);
2279
2280 ret = drm_writeback_update_info(writeback, conn);
2281 if (ret < 0)
2282 goto err;
2283
2284 wl_list_insert(&b->writeback_connector_list, &writeback->link);
2285 return 0;
2286
2287err:
2288 drm_connector_fini(&writeback->connector);
2289 free(writeback);
2290 return -1;
2291}
2292
2293static void
2294drm_writeback_destroy(struct drm_writeback *writeback)
2295{
2296 drm_connector_fini(&writeback->connector);
2297 wl_list_remove(&writeback->link);
2298
2299 free(writeback);
2300}
2301
2302/** Given the DRM connector object of a connector, create drm_head or
2303 * drm_writeback object (depending on the type of connector) for it.
2304 *
2305 * The object is then added to the DRM-backend list of heads or writebacks.
Leandro Ribeiro72430222020-09-14 17:41:41 -03002306 *
2307 * @param b The DRM-backend structure
2308 * @param conn The DRM connector object
2309 * @param drm_device udev device pointer
2310 * @return 0 on success, -1 on failure
2311 */
2312static int
2313drm_backend_add_connector(struct drm_backend *b, drmModeConnector *conn,
2314 struct udev_device *drm_device)
2315{
2316 int ret;
2317
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002318 if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) {
2319 ret = drm_writeback_create(b, conn);
2320 if (ret < 0)
2321 weston_log("DRM: failed to create writeback for connector %d.\n",
2322 conn->connector_id);
2323 } else {
2324 ret = drm_head_create(b, conn, drm_device);
2325 if (ret < 0)
2326 weston_log("DRM: failed to create head for connector %d.\n",
2327 conn->connector_id);
2328 }
Leandro Ribeiro72430222020-09-14 17:41:41 -03002329
2330 return ret;
2331}
2332
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002333/** Find all connectors of the fd and create drm_head or drm_writeback objects
2334 * (depending on the type of connector they are) for each of them
2335 *
2336 * These objects are added to the DRM-backend lists of heads and writebacks.
2337 *
2338 * @param b The DRM-backend structure
2339 * @param drm_device udev device pointer
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03002340 * @param resources The DRM resources, it is taken with drmModeGetResources
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002341 * @return 0 on success, -1 on failure
2342 */
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002343static int
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03002344drm_backend_discover_connectors(struct drm_backend *b, struct udev_device *drm_device,
2345 drmModeRes *resources)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002346{
Leandro Ribeiro70863962020-09-09 13:12:35 -03002347 drmModeConnector *conn;
2348 int i, ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002349
Giulio Camuffo954f1832014-10-11 18:27:30 +03002350 b->min_width = resources->min_width;
2351 b->max_width = resources->max_width;
2352 b->min_height = resources->min_height;
2353 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002354
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002355 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002356 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00002357
Leandro Ribeiro70863962020-09-09 13:12:35 -03002358 conn = drmModeGetConnector(b->drm.fd, connector_id);
2359 if (!conn)
2360 continue;
2361
Leandro Ribeiro72430222020-09-14 17:41:41 -03002362 ret = drm_backend_add_connector(b, conn, drm_device);
2363 if (ret < 0)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002364 drmModeFreeConnector(conn);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002365 }
2366
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002367 return 0;
2368}
2369
Leandro Ribeiro99611c82020-09-14 17:19:12 -03002370static bool
2371resources_has_connector(drmModeRes *resources, uint32_t connector_id)
2372{
2373 for (int i = 0; i < resources->count_connectors; i++) {
2374 if (resources->connectors[i] == connector_id)
2375 return true;
2376 }
2377
2378 return false;
2379}
2380
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002381static void
Leandro Ribeiro993920d2020-09-14 17:01:01 -03002382drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002383{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002384 drmModeRes *resources;
Leandro Ribeiro70863962020-09-09 13:12:35 -03002385 drmModeConnector *conn;
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002386 struct weston_head *base, *base_next;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002387 struct drm_head *head;
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002388 struct drm_writeback *writeback, *writeback_next;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002389 uint32_t connector_id;
Leandro Ribeiro70863962020-09-09 13:12:35 -03002390 int i, ret;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002391
Giulio Camuffo954f1832014-10-11 18:27:30 +03002392 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002393 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002394 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002395 return;
2396 }
2397
Pekka Paalanend2e62422017-09-08 15:48:07 +03002398 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002399 for (i = 0; i < resources->count_connectors; i++) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002400 connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02002401
Leandro Ribeiro70863962020-09-09 13:12:35 -03002402 conn = drmModeGetConnector(b->drm.fd, connector_id);
2403 if (!conn)
2404 continue;
2405
Pekka Paalanend2e62422017-09-08 15:48:07 +03002406 head = drm_head_find_by_connector(b, connector_id);
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002407 writeback = drm_writeback_find_by_connector(b, connector_id);
2408
2409 /* Connector can't be owned by both a head and a writeback, so
2410 * one of the searches must fail. */
2411 assert(head == NULL || writeback == NULL);
2412
Leandro Ribeiro72430222020-09-14 17:41:41 -03002413 if (head)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002414 ret = drm_head_update_info(head, conn);
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002415 else if (writeback)
2416 ret = drm_writeback_update_info(writeback, conn);
Leandro Ribeiro72430222020-09-14 17:41:41 -03002417 else
2418 ret = drm_backend_add_connector(b, conn, drm_device);
2419
2420 if (ret < 0)
2421 drmModeFreeConnector(conn);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002422 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002423
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002424 /* Destroy head objects of connectors (except writeback connectors) that
2425 * have disappeared. */
2426 wl_list_for_each_safe(base, base_next,
Pekka Paalanena0a37462017-08-31 15:41:57 +03002427 &b->compositor->head_list, compositor_link) {
Pekka Paalanena0a37462017-08-31 15:41:57 +03002428 head = to_drm_head(base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002429 connector_id = head->connector.connector_id;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002430
Leandro Ribeiro99611c82020-09-14 17:19:12 -03002431 if (resources_has_connector(resources, connector_id))
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002432 continue;
2433
Pekka Paalanend2e62422017-09-08 15:48:07 +03002434 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002435 head->base.name, connector_id);
Pekka Paalanend2e62422017-09-08 15:48:07 +03002436 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002437 }
2438
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002439 /* Destroy writeback objects of writeback connectors that have
2440 * disappeared. */
2441 wl_list_for_each_safe(writeback, writeback_next,
2442 &b->writeback_connector_list, link) {
2443 connector_id = writeback->connector.connector_id;
2444
2445 if (resources_has_connector(resources, connector_id))
2446 continue;
2447
2448 weston_log("DRM: writeback connector (connector %d) disappeared.\n",
2449 connector_id);
2450 drm_writeback_destroy(writeback);
2451 }
2452
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002453 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002454}
2455
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302456static enum wdrm_connector_property
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002457drm_connector_find_property_by_id(struct drm_connector *connector,
2458 uint32_t property_id)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302459{
2460 int i;
2461 enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
2462
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002463 if (!connector || !property_id)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302464 return WDRM_CONNECTOR__COUNT;
2465
2466 for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002467 if (connector->props[i].prop_id == property_id) {
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302468 prop = (enum wdrm_connector_property) i;
2469 break;
2470 }
2471 return prop;
2472}
2473
2474static void
2475drm_backend_update_conn_props(struct drm_backend *b,
2476 uint32_t connector_id,
2477 uint32_t property_id)
2478{
2479 struct drm_head *head;
2480 enum wdrm_connector_property conn_prop;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302481
2482 head = drm_head_find_by_connector(b, connector_id);
2483 if (!head) {
2484 weston_log("DRM: failed to find head for connector id: %d.\n",
2485 connector_id);
2486 return;
2487 }
2488
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002489 conn_prop = drm_connector_find_property_by_id(&head->connector, property_id);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302490 if (conn_prop >= WDRM_CONNECTOR__COUNT)
2491 return;
2492
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002493 if (drm_connector_update_properties(&head->connector) < 0)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302494 return;
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002495
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302496 if (conn_prop == WDRM_CONNECTOR_CONTENT_PROTECTION) {
2497 weston_head_set_content_protection_status(&head->base,
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002498 drm_head_get_current_protection(head));
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302499 }
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302500}
2501
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002502static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002503udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002504{
David Herrmannd7488c22012-03-11 20:05:21 +01002505 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002506 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002507
2508 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002509 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002510 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002511
David Herrmann6ac52db2012-03-11 20:05:22 +01002512 val = udev_device_get_property_value(device, "HOTPLUG");
2513 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002514 return 0;
2515
David Herrmann6ac52db2012-03-11 20:05:22 +01002516 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002517}
2518
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002519static int
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302520udev_event_is_conn_prop_change(struct drm_backend *b,
2521 struct udev_device *device,
2522 uint32_t *connector_id,
2523 uint32_t *property_id)
2524
2525{
2526 const char *val;
2527 int id;
2528
2529 val = udev_device_get_property_value(device, "CONNECTOR");
2530 if (!val || !safe_strtoint(val, &id))
2531 return 0;
2532 else
2533 *connector_id = id;
2534
2535 val = udev_device_get_property_value(device, "PROPERTY");
2536 if (!val || !safe_strtoint(val, &id))
2537 return 0;
2538 else
2539 *property_id = id;
2540
2541 return 1;
2542}
2543
2544static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002545udev_drm_event(int fd, uint32_t mask, void *data)
2546{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002547 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002548 struct udev_device *event;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302549 uint32_t conn_id, prop_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002550
Giulio Camuffo954f1832014-10-11 18:27:30 +03002551 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002552
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302553 if (udev_event_is_hotplug(b, event)) {
2554 if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
2555 drm_backend_update_conn_props(b, conn_id, prop_id);
2556 else
Leandro Ribeiro993920d2020-09-14 17:01:01 -03002557 drm_backend_update_connectors(b, event);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302558 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002559
2560 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002561
2562 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002563}
2564
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002565static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002566drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002567{
Armin Krezović545dba62016-08-05 15:54:18 +02002568 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002569 struct weston_head *base, *next;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002570 struct drm_crtc *crtc, *crtc_tmp;
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002571 struct drm_writeback *writeback, *writeback_tmp;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002572
Giulio Camuffo954f1832014-10-11 18:27:30 +03002573 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002574
Giulio Camuffo954f1832014-10-11 18:27:30 +03002575 wl_event_source_remove(b->udev_drm_source);
2576 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002577
Daniel Stoneb57c6a02017-10-05 16:27:21 +01002578 b->shutting_down = true;
2579
Giulio Camuffo954f1832014-10-11 18:27:30 +03002580 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002581
Leandro Ribeirof0149642019-12-18 15:52:18 -03002582 weston_log_scope_destroy(b->debug);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002583 b->debug = NULL;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002584 weston_compositor_shutdown(ec);
2585
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002586 wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
2587 drm_crtc_destroy(crtc);
2588
Pekka Paalanenc112f002017-08-28 16:27:20 +03002589 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
2590 drm_head_destroy(to_drm_head(base));
2591
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002592 wl_list_for_each_safe(writeback, writeback_tmp,
2593 &b->writeback_connector_list, link)
2594 drm_writeback_destroy(writeback);
2595
Stefan Agnerccf24072019-07-09 22:02:00 +02002596#ifdef BUILD_DRM_GBM
Giulio Camuffo954f1832014-10-11 18:27:30 +03002597 if (b->gbm)
2598 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02002599#endif
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002600
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02002601 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03002602 udev_unref(b->udev);
2603
Giulio Camuffo954f1832014-10-11 18:27:30 +03002604 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002605
Giulio Camuffo954f1832014-10-11 18:27:30 +03002606 close(b->drm.fd);
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02002607 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002608 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002609}
2610
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002611static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002612session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002613{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002614 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02002615 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01002616 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002617 struct drm_output *output;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002618 struct drm_crtc *crtc;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002619
Giulio Camuffo954f1832014-10-11 18:27:30 +03002620 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002621 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00002622 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002623 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00002624 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002625 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002626 } else {
2627 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002628 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002629
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002630 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002631
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002632 /* If we have a repaint scheduled (either from a
2633 * pending pageflip or the idle handler), make sure we
2634 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002635 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05002636 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002637 * back, we schedule a repaint, which will process
2638 * pending frame callbacks. */
2639
Giulio Camuffo954f1832014-10-11 18:27:30 +03002640 wl_list_for_each(output, &compositor->output_list, base.link) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002641 crtc = output->crtc;
Daniel Stone09a97e22017-03-01 11:34:06 +00002642 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002643 if (output->cursor_plane)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002644 drmModeSetCursor(b->drm.fd, crtc->crtc_id,
Daniel Stone2ba17f42015-05-19 20:02:41 +01002645 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002646 }
2647
Giulio Camuffo954f1832014-10-11 18:27:30 +03002648 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002649 struct drm_output, base.link);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002650 crtc = output->crtc;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002651
Daniel Stone085d2b92015-05-21 00:00:57 +01002652 wl_list_for_each(plane, &b->plane_list, link) {
2653 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
2654 continue;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002655 drmModeSetPlane(b->drm.fd, plane->plane_id, crtc->crtc_id,
2656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01002657 }
2658 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002659}
2660
Robert Beckett8d23ab72019-06-13 16:55:44 +01002661
2662/**
2663 * Handle KMS GPU being added/removed
2664 *
2665 * If the device being added/removed is the KMS device, we activate/deactivate
2666 * the compositor session.
2667 *
2668 * @param compositor The compositor instance.
2669 * @param device The device being added/removed.
2670 * @param added Whether the device is being added (or removed)
2671 */
2672static void
2673drm_device_changed(struct weston_compositor *compositor,
2674 dev_t device, bool added)
2675{
2676 struct drm_backend *b = to_drm_backend(compositor);
2677
Robert Beckett49dc3202019-07-02 16:31:22 +01002678 if (b->drm.fd < 0 || b->drm.devnum != device ||
2679 compositor->session_active == added)
Robert Beckett8d23ab72019-06-13 16:55:44 +01002680 return;
2681
2682 compositor->session_active = added;
2683 wl_signal_emit(&compositor->session_signal, compositor);
2684}
2685
Daniel Stoneefa504f2016-12-19 16:48:20 +00002686/**
2687 * Determines whether or not a device is capable of modesetting. If successful,
2688 * sets b->drm.fd and b->drm.filename to the opened device.
2689 */
2690static bool
2691drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
2692{
2693 const char *filename = udev_device_get_devnode(device);
2694 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002695 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002696 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02002697 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002698
2699 if (!filename)
2700 return false;
2701
2702 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
2703 if (fd < 0)
2704 return false;
2705
2706 res = drmModeGetResources(fd);
2707 if (!res)
2708 goto out_fd;
2709
2710 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
2711 res->count_encoders <= 0)
2712 goto out_res;
2713
2714 if (sysnum)
2715 id = atoi(sysnum);
2716 if (!sysnum || id < 0) {
2717 weston_log("couldn't get sysnum for device %s\n", filename);
2718 goto out_res;
2719 }
2720
2721 /* We can be called successfully on multiple devices; if we have,
2722 * clean up old entries. */
2723 if (b->drm.fd >= 0)
2724 weston_launcher_close(b->compositor->launcher, b->drm.fd);
2725 free(b->drm.filename);
2726
2727 b->drm.fd = fd;
2728 b->drm.id = id;
2729 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002730 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002731
Sergi Granellceb59812017-03-28 12:44:04 +02002732 drmModeFreeResources(res);
2733
Daniel Stoneefa504f2016-12-19 16:48:20 +00002734 return true;
2735
2736out_res:
2737 drmModeFreeResources(res);
2738out_fd:
2739 weston_launcher_close(b->compositor->launcher, fd);
2740 return false;
2741}
2742
David Herrmann0af066f2012-10-29 19:21:16 +01002743/*
2744 * Find primary GPU
2745 * Some systems may have multiple DRM devices attached to a single seat. This
2746 * function loops over all devices and tries to find a PCI device with the
2747 * boot_vga sysfs attribute set to 1.
2748 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00002749 * Devices are also vetted to make sure they are are capable of modesetting,
2750 * rather than pure render nodes (GPU with no display), or pure
2751 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01002752 */
2753static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002754find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002755{
2756 struct udev_enumerate *e;
2757 struct udev_list_entry *entry;
2758 const char *path, *device_seat, *id;
2759 struct udev_device *device, *drm_device, *pci;
2760
Giulio Camuffo954f1832014-10-11 18:27:30 +03002761 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002762 udev_enumerate_add_match_subsystem(e, "drm");
2763 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2764
2765 udev_enumerate_scan_devices(e);
2766 drm_device = NULL;
2767 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00002768 bool is_boot_vga = false;
2769
David Herrmann0af066f2012-10-29 19:21:16 +01002770 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002771 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002772 if (!device)
2773 continue;
2774 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2775 if (!device_seat)
2776 device_seat = default_seat;
2777 if (strcmp(device_seat, seat)) {
2778 udev_device_unref(device);
2779 continue;
2780 }
2781
2782 pci = udev_device_get_parent_with_subsystem_devtype(device,
2783 "pci", NULL);
2784 if (pci) {
2785 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00002786 if (id && !strcmp(id, "1"))
2787 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01002788 }
2789
Daniel Stoneefa504f2016-12-19 16:48:20 +00002790 /* If we already have a modesetting-capable device, and this
2791 * device isn't our boot-VGA device, we aren't going to use
2792 * it. */
2793 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01002794 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002795 continue;
2796 }
2797
2798 /* Make sure this device is actually capable of modesetting;
2799 * if this call succeeds, b->drm.{fd,filename} will be set,
2800 * and any old values freed. */
2801 if (!drm_device_is_kms(b, device)) {
2802 udev_device_unref(device);
2803 continue;
2804 }
2805
2806 /* There can only be one boot_vga device, and we try to use it
2807 * at all costs. */
2808 if (is_boot_vga) {
2809 if (drm_device)
2810 udev_device_unref(drm_device);
2811 drm_device = device;
2812 break;
2813 }
2814
2815 /* Per the (!is_boot_vga && drm_device) test above, we only
2816 * trump existing saved devices with boot-VGA devices, so if
2817 * we end up here, this must be the first device we've seen. */
2818 assert(!drm_device);
2819 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01002820 }
2821
Daniel Stoneefa504f2016-12-19 16:48:20 +00002822 /* If we're returning a device to use, we must have an open FD for
2823 * it. */
2824 assert(!!drm_device == (b->drm.fd >= 0));
2825
David Herrmann0af066f2012-10-29 19:21:16 +01002826 udev_enumerate_unref(e);
2827 return drm_device;
2828}
2829
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002830static struct udev_device *
2831open_specific_drm_device(struct drm_backend *b, const char *name)
2832{
2833 struct udev_device *device;
2834
2835 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
2836 if (!device) {
2837 weston_log("ERROR: could not open DRM device '%s'\n", name);
2838 return NULL;
2839 }
2840
2841 if (!drm_device_is_kms(b, device)) {
2842 udev_device_unref(device);
2843 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
2844 return NULL;
2845 }
2846
2847 /* If we're returning a device to use, we must have an open FD for
2848 * it. */
2849 assert(b->drm.fd >= 0);
2850
2851 return device;
2852}
2853
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002854static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002855planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2856 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002857{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002858 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002859
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002860 switch (key) {
2861 case KEY_C:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002862 b->cursors_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002863 break;
2864 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01002865 /* We don't support overlay-plane usage with legacy KMS. */
2866 if (b->atomic_modeset)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002867 b->sprites_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002868 break;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002869 default:
2870 break;
2871 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002872}
2873
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002874#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002875static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002876recorder_destroy(struct drm_output *output)
2877{
2878 vaapi_recorder_destroy(output->recorder);
2879 output->recorder = NULL;
2880
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302881 weston_output_disable_planes_decr(&output->base);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002882
2883 wl_list_remove(&output->recorder_frame_listener.link);
2884 weston_log("[libva recorder] done\n");
2885}
2886
2887static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002888recorder_frame_notify(struct wl_listener *listener, void *data)
2889{
2890 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002891 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002892 int fd, ret;
2893
2894 output = container_of(listener, struct drm_output,
2895 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02002896 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002897
2898 if (!output->recorder)
2899 return;
2900
Daniel Stonee2e80132018-01-16 15:37:33 +00002901 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002902 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002903 DRM_CLOEXEC, &fd);
2904 if (ret) {
2905 weston_log("[libva recorder] "
2906 "failed to create prime fd for front buffer\n");
2907 return;
2908 }
2909
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002910 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002911 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002912 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002913 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002914 recorder_destroy(output);
2915 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002916}
2917
2918static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002919create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002920 const char *filename)
2921{
2922 int fd;
2923 drm_magic_t magic;
2924
Giulio Camuffo954f1832014-10-11 18:27:30 +03002925 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002926 if (fd < 0)
2927 return NULL;
2928
2929 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002930 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002931
2932 return vaapi_recorder_create(fd, width, height, filename);
2933}
2934
2935static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002936recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2937 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002938{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002939 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002940 struct drm_output *output;
2941 int width, height;
2942
Giulio Camuffo954f1832014-10-11 18:27:30 +03002943 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002944 struct drm_output, base.link);
2945
2946 if (!output->recorder) {
Stefan Agner4a18f302019-10-20 18:25:42 +02002947 if (output->gbm_format != DRM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002948 weston_log("failed to start vaapi recorder: "
2949 "output format not supported\n");
2950 return;
2951 }
2952
Hardeningff39efa2013-09-18 23:56:35 +02002953 width = output->base.current_mode->width;
2954 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002955
2956 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002957 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002958 if (!output->recorder) {
2959 weston_log("failed to create vaapi recorder\n");
2960 return;
2961 }
2962
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302963 weston_output_disable_planes_incr(&output->base);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002964
2965 output->recorder_frame_listener.notify = recorder_frame_notify;
2966 wl_signal_add(&output->base.frame_signal,
2967 &output->recorder_frame_listener);
2968
2969 weston_output_schedule_repaint(&output->base);
2970
2971 weston_log("[libva recorder] initialized\n");
2972 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002973 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002974 }
2975}
2976#else
2977static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002978recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2979 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002980{
2981 weston_log("Compiled without libva support\n");
2982}
2983#endif
2984
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002985
Armin Krezović08368132016-09-30 14:11:05 +02002986static const struct weston_drm_output_api api = {
2987 drm_output_set_mode,
2988 drm_output_set_gbm_format,
2989 drm_output_set_seat,
2990};
2991
Giulio Camuffo954f1832014-10-11 18:27:30 +03002992static struct drm_backend *
2993drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002994 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002995{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002996 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01002997 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002998 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002999 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04003000 const char *session_seat;
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003001 drmModeRes *res;
Armin Krezović08368132016-09-30 14:11:05 +02003002 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003003
nerdopolisb16c4ac2018-06-29 08:17:46 -04003004 session_seat = getenv("XDG_SEAT");
3005 if (session_seat)
3006 seat_id = session_seat;
3007
3008 if (config->seat_id)
3009 seat_id = config->seat_id;
3010
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04003011 weston_log("initializing drm backend\n");
3012
Giulio Camuffo954f1832014-10-11 18:27:30 +03003013 b = zalloc(sizeof *b);
3014 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003015 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01003016
Daniel Stone6020f472018-02-05 15:46:20 +00003017 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003018 b->drm.fd = -1;
3019
Giulio Camuffo954f1832014-10-11 18:27:30 +03003020 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003021 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00003022 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02003023 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003024
Leandro Ribeiro172afc22019-12-26 16:23:43 -03003025 b->debug = weston_compositor_add_log_scope(compositor, "drm-backend",
3026 "Debug messages from DRM/KMS backend\n",
3027 NULL, NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003028
Pekka Paalanen7da9a382017-08-30 11:29:49 +03003029 compositor->backend = &b->base;
3030
Stefan Agner0bfebeb2019-07-08 00:30:44 +02003031 if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003032 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003033
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003034 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003035 compositor->launcher = weston_launcher_connect(compositor, config->tty,
3036 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003037 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02003038 weston_log("fatal: drm backend should be run using "
3039 "weston-launch binary, or your system should "
3040 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003041 goto err_compositor;
3042 }
3043
Giulio Camuffo954f1832014-10-11 18:27:30 +03003044 b->udev = udev_new();
3045 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003046 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003047 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003048 }
3049
Giulio Camuffo954f1832014-10-11 18:27:30 +03003050 b->session_listener.notify = session_notify;
3051 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003052
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03003053 if (config->specific_device)
3054 drm_device = open_specific_drm_device(b, config->specific_device);
3055 else
3056 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003057 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003058 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003059 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003060 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003061
Daniel Stoneefa504f2016-12-19 16:48:20 +00003062 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003063 weston_log("failed to initialize kms\n");
3064 goto err_udev_dev;
3065 }
3066
Giulio Camuffo954f1832014-10-11 18:27:30 +03003067 if (b->use_pixman) {
3068 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003069 weston_log("failed to initialize pixman renderer\n");
3070 goto err_udev_dev;
3071 }
3072 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003073 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003074 weston_log("failed to initialize egl\n");
3075 goto err_udev_dev;
3076 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003077 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003078
Giulio Camuffo954f1832014-10-11 18:27:30 +03003079 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003080 b->base.repaint_begin = drm_repaint_begin;
3081 b->base.repaint_flush = drm_repaint_flush;
3082 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03003083 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01003084 b->base.device_changed = drm_device_changed;
Marius Vlad81bada52019-11-11 00:27:17 +02003085 b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003086
Bob Ham91880f12016-01-12 10:21:47 +00003087 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003088
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003089 res = drmModeGetResources(b->drm.fd);
3090 if (!res) {
3091 weston_log("Failed to get drmModeRes\n");
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03003092 goto err_udev_dev;
3093 }
3094
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003095 wl_list_init(&b->crtc_list);
3096 if (drm_backend_create_crtc_list(b, res) == -1) {
3097 weston_log("Failed to create CRTC list for DRM-backend\n");
3098 goto err_create_crtc_list;
3099 }
3100
Daniel Stone085d2b92015-05-21 00:00:57 +01003101 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003102 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003103
Giulio Camuffo954f1832014-10-11 18:27:30 +03003104 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03003105 compositor, b->udev, seat_id,
3106 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003107 weston_log("failed to create input devices\n");
3108 goto err_sprite;
3109 }
3110
Leandro Ribeiro96bef052020-09-09 15:23:49 -03003111 wl_list_init(&b->writeback_connector_list);
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003112 if (drm_backend_discover_connectors(b, drm_device, res) < 0) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03003113 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003114 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003115 }
3116
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003117 drmModeFreeResources(res);
3118
Marius Vlade83e7502019-10-29 17:29:37 +02003119 /* 'compute' faked zpos values in case HW doesn't expose any */
3120 drm_backend_create_faked_zpos(b);
3121
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003122 /* A this point we have some idea of whether or not we have a working
3123 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003124 if (!b->cursors_are_broken)
3125 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003126
Giulio Camuffo954f1832014-10-11 18:27:30 +03003127 loop = wl_display_get_event_loop(compositor->wl_display);
3128 b->drm_source =
3129 wl_event_loop_add_fd(loop, b->drm.fd,
3130 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003131
Giulio Camuffo954f1832014-10-11 18:27:30 +03003132 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3133 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05003134 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003135 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003136 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003137 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003138 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003139 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003140 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003141 udev_monitor_get_fd(b->udev_monitor),
3142 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003143
Giulio Camuffo954f1832014-10-11 18:27:30 +03003144 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003145 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003146 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003147 }
3148
Daniel Stonea96b93c2012-06-22 14:04:37 +01003149 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003150
Giulio Camuffo954f1832014-10-11 18:27:30 +03003151 weston_compositor_add_debug_binding(compositor, KEY_O,
3152 planes_binding, b);
3153 weston_compositor_add_debug_binding(compositor, KEY_C,
3154 planes_binding, b);
3155 weston_compositor_add_debug_binding(compositor, KEY_V,
3156 planes_binding, b);
3157 weston_compositor_add_debug_binding(compositor, KEY_Q,
3158 recorder_binding, b);
3159 weston_compositor_add_debug_binding(compositor, KEY_W,
3160 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003161
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003162 if (compositor->renderer->import_dmabuf) {
3163 if (linux_dmabuf_setup(compositor) < 0)
3164 weston_log("Error: initializing dmabuf "
3165 "support failed.\n");
Marius Vladebd10e52019-11-16 19:22:48 +02003166 if (weston_direct_display_setup(compositor) < 0)
3167 weston_log("Error: initializing direct-display "
3168 "support failed.\n");
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003169 }
3170
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003171 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
3172 if (linux_explicit_synchronization_setup(compositor) < 0)
3173 weston_log("Error: initializing explicit "
3174 " synchronization support failed.\n");
3175 }
3176
Ankit Nautiyala344fe32019-05-14 18:36:08 +05303177 if (b->atomic_modeset)
3178 if (weston_compositor_enable_content_protection(compositor) < 0)
3179 weston_log("Error: initializing content-protection "
3180 "support failed.\n");
3181
Armin Krezović08368132016-09-30 14:11:05 +02003182 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
3183 &api, sizeof(api));
3184
3185 if (ret < 0) {
3186 weston_log("Failed to register output API.\n");
3187 goto err_udev_monitor;
3188 }
3189
Stefan Agner3654c672019-07-09 00:50:30 +02003190 ret = drm_backend_init_virtual_output_api(compositor);
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003191 if (ret < 0) {
3192 weston_log("Failed to register virtual output API.\n");
3193 goto err_udev_monitor;
3194 }
3195
Giulio Camuffo954f1832014-10-11 18:27:30 +03003196 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003197
3198err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003199 wl_event_source_remove(b->udev_drm_source);
3200 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003201err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003202 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003203err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003204 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003205err_sprite:
Stefan Agnerccf24072019-07-09 22:02:00 +02003206#ifdef BUILD_DRM_GBM
Emmanuel Gil Peyrotb8347e32016-05-02 22:40:13 +01003207 if (b->gbm)
3208 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02003209#endif
Giulio Camuffo954f1832014-10-11 18:27:30 +03003210 destroy_sprites(b);
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003211err_create_crtc_list:
3212 drmModeFreeResources(res);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003213err_udev_dev:
3214 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003215err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003216 udev_unref(b->udev);
Marius Vlad5130a8c2020-07-30 14:47:32 +03003217err_launcher:
3218 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003219err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003220 weston_compositor_shutdown(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003221 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003222 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003223}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003224
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003225static void
3226config_init_to_defaults(struct weston_drm_backend_config *config)
3227{
Pekka Paalanendee412d2018-04-23 11:44:58 +02003228 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003229}
3230
Giulio Camuffo954f1832014-10-11 18:27:30 +03003231WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01003232weston_backend_init(struct weston_compositor *compositor,
3233 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003234{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003235 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003236 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003237
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003238 if (config_base == NULL ||
3239 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
3240 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
3241 weston_log("drm backend config structure is invalid\n");
3242 return -1;
3243 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02003244
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003245 config_init_to_defaults(&config);
3246 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003247
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003248 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003249 if (b == NULL)
3250 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003251
Giulio Camuffo954f1832014-10-11 18:27:30 +03003252 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003253}