blob: 4e408cb98b77fb4d47868e175023a84e14ca9135 [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>
47
Pekka Paalanen33156972012-08-03 13:30:30 -040048#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020049
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020050#include <libweston/libweston.h>
Pekka Paalanen75710272019-03-29 16:39:12 +020051#include <libweston/backend-drm.h>
Marius Vladc901e892019-06-21 22:49:18 +030052#include <libweston/weston-log.h>
Daniel Stonedd1bc502019-06-17 12:13:46 +010053#include "drm-internal.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070054#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020055#include "shared/timespec-util.h"
Ankit Nautiyala344fe32019-05-14 18:36:08 +053056#include "shared/string-helpers.h"
Pekka Paalanen4b301fe2021-02-04 17:39:45 +020057#include "shared/weston-drm-fourcc.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;
Derek Foreman74bdb352021-07-29 09:02:04 -0500315
316 if (output->state_cur->dpms != WESTON_DPMS_OFF)
317 weston_output_finish_frame(&output->base, &ts, flags);
318 else
319 weston_output_finish_frame(&output->base, NULL,
320 WP_PRESENTATION_FEEDBACK_INVALID);
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000321
322 /* We can't call this from frame_notify, because the output's
323 * repaint needed flag is cleared just after that */
324 if (output->recorder)
325 weston_output_schedule_repaint(&output->base);
326}
327
Daniel Stone95d48a22017-04-04 17:54:30 +0100328static struct drm_fb *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000329drm_output_render_pixman(struct drm_output_state *state,
330 pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200331{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000332 struct drm_output *output = state->output;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200333 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200334
335 output->current_image ^= 1;
336
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200337 pixman_renderer_output_set_buffer(&output->base,
338 output->image[output->current_image]);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200339 pixman_renderer_output_set_hw_extra_damage(&output->base,
340 &output->previous_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200341
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200342 ec->renderer->repaint_output(&output->base, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200343
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200344 pixman_region32_copy(&output->previous_damage, damage);
Daniel Stone95d48a22017-04-04 17:54:30 +0100345
346 return drm_fb_ref(output->dumb[output->current_image]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200347}
348
Stefan Agner3654c672019-07-09 00:50:30 +0200349void
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000350drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200351{
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000352 struct drm_output *output = state->output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300353 struct weston_compositor *c = output->base.compositor;
Daniel Stonee2e80132018-01-16 15:37:33 +0000354 struct drm_plane_state *scanout_state;
Daniel Stonee95169b2016-11-14 17:46:59 +0000355 struct drm_plane *scanout_plane = output->scanout_plane;
Scott Anderson15c603c2020-06-02 17:39:43 +1200356 struct drm_property_info *damage_info =
357 &scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
Armin Krezović545dba62016-08-05 15:54:18 +0200358 struct drm_backend *b = to_drm_backend(c);
Daniel Stone95d48a22017-04-04 17:54:30 +0100359 struct drm_fb *fb;
Scott Anderson15c603c2020-06-02 17:39:43 +1200360 pixman_region32_t scanout_damage;
361 pixman_box32_t *rects;
362 int n_rects;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200363
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100364 /* If we already have a client buffer promoted to scanout, then we don't
365 * want to render. */
Leandro Ribeiro05cecc82020-08-13 17:34:58 -0300366 scanout_state = drm_output_state_get_plane(state, scanout_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +0000367 if (scanout_state->fb)
Daniel Stone4e84f7d2017-04-04 17:54:29 +0100368 return;
369
Daniel Stone98d75e12020-03-06 11:03:14 +0000370 /*
371 * If we don't have any damage on the primary plane, and we already
372 * have a renderer buffer active, we can reuse it; else we pass
373 * the damaged region into the renderer to re-render the affected
Pekka Paalanen7f1a1132020-12-07 14:59:44 +0200374 * area. But, we still have to call the renderer anyway if any screen
375 * capture is pending, otherwise the capture will not complete.
Daniel Stone98d75e12020-03-06 11:03:14 +0000376 */
Daniel Stonee95169b2016-11-14 17:46:59 +0000377 if (!pixman_region32_not_empty(damage) &&
Pekka Paalanen7f1a1132020-12-07 14:59:44 +0200378 wl_list_empty(&output->base.frame_signal.listener_list) &&
Daniel Stonee95169b2016-11-14 17:46:59 +0000379 scanout_plane->state_cur->fb &&
380 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
Daniel Stone98d75e12020-03-06 11:03:14 +0000381 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
Daniel Stonee95169b2016-11-14 17:46:59 +0000382 fb = drm_fb_ref(scanout_plane->state_cur->fb);
383 } else if (b->use_pixman) {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000384 fb = drm_output_render_pixman(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000385 } else {
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000386 fb = drm_output_render_gl(state, damage);
Daniel Stonee95169b2016-11-14 17:46:59 +0000387 }
Daniel Stone95d48a22017-04-04 17:54:30 +0100388
Daniel Stonee2e80132018-01-16 15:37:33 +0000389 if (!fb) {
390 drm_plane_state_put_back(scanout_state);
Daniel Stone95d48a22017-04-04 17:54:30 +0100391 return;
Daniel Stonee2e80132018-01-16 15:37:33 +0000392 }
393
394 scanout_state->fb = fb;
395 scanout_state->output = output;
396
397 scanout_state->src_x = 0;
398 scanout_state->src_y = 0;
Daniel Stonef9a61622020-03-06 11:07:15 +0000399 scanout_state->src_w = fb->width << 16;
400 scanout_state->src_h = fb->height << 16;
Daniel Stonee2e80132018-01-16 15:37:33 +0000401
402 scanout_state->dest_x = 0;
403 scanout_state->dest_y = 0;
Daniel Stonef9a61622020-03-06 11:07:15 +0000404 scanout_state->dest_w = output->base.current_mode->width;
405 scanout_state->dest_h = output->base.current_mode->height;
Daniel Stonee2e80132018-01-16 15:37:33 +0000406
Scott Anderson15c603c2020-06-02 17:39:43 +1200407 pixman_region32_subtract(&c->primary_plane.damage,
408 &c->primary_plane.damage, damage);
409
410 /* Don't bother calculating plane damage if the plane doesn't support it */
411 if (damage_info->prop_id == 0)
412 return;
413
414 pixman_region32_init(&scanout_damage);
415 pixman_region32_copy(&scanout_damage, damage);
416
Deepak Rawat46a1c722018-07-24 14:13:34 -0700417 if (output->base.zoom.active) {
Derek Foremandb7e85d2022-01-20 10:27:17 -0600418 pixman_region32_t clip;
419
Scott Anderson15c603c2020-06-02 17:39:43 +1200420 weston_matrix_transform_region(&scanout_damage,
Deepak Rawat46a1c722018-07-24 14:13:34 -0700421 &output->base.matrix,
Scott Anderson15c603c2020-06-02 17:39:43 +1200422 &scanout_damage);
Derek Foremandb7e85d2022-01-20 10:27:17 -0600423 pixman_region32_init_rect(&clip, 0, 0,
424 output->base.width,
425 output->base.height);
426 pixman_region32_intersect(&scanout_damage, &scanout_damage, &clip);
427 pixman_region32_fini(&clip);
Deepak Rawat46a1c722018-07-24 14:13:34 -0700428 } else {
Scott Anderson15c603c2020-06-02 17:39:43 +1200429 pixman_region32_translate(&scanout_damage,
Deepak Rawat46a1c722018-07-24 14:13:34 -0700430 -output->base.x, -output->base.y);
431 weston_transformed_region(output->base.width,
432 output->base.height,
433 output->base.transform,
434 output->base.current_scale,
Scott Anderson15c603c2020-06-02 17:39:43 +1200435 &scanout_damage,
436 &scanout_damage);
Deepak Rawat46a1c722018-07-24 14:13:34 -0700437 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200438
Scott Anderson15c603c2020-06-02 17:39:43 +1200439 assert(scanout_state->damage_blob_id == 0);
440
441 rects = pixman_region32_rectangles(&scanout_damage, &n_rects);
442
443 /*
444 * If this function fails, the blob id should still be 0.
445 * This tells the kernel there is no damage information, which means
446 * that it will consider the whole plane damaged. While this may
447 * affect efficiency, it should still produce correct results.
448 */
449 drmModeCreatePropertyBlob(b->drm.fd, rects,
450 sizeof(*rects) * n_rects,
451 &scanout_state->damage_blob_id);
452
453 pixman_region32_fini(&scanout_damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200454}
455
Daniel Stonea08512f2016-11-08 17:46:10 +0000456static int
457drm_output_repaint(struct weston_output *output_base,
458 pixman_region32_t *damage,
459 void *repaint_data)
460{
461 struct drm_pending_state *pending_state = repaint_data;
462 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +0000463 struct drm_output_state *state = NULL;
464 struct drm_plane_state *scanout_state;
465
Tomohito Esakib1fb00d2018-01-31 17:50:48 +0900466 assert(!output->virtual);
467
Daniel Stonea08512f2016-11-08 17:46:10 +0000468 if (output->disable_pending || output->destroy_pending)
469 goto err;
470
471 assert(!output->state_last);
472
473 /* If planes have been disabled in the core, we might not have
474 * hit assign_planes at all, so might not have valid output state
475 * here. */
476 state = drm_pending_state_get_output(pending_state, output);
477 if (!state)
478 state = drm_output_state_duplicate(output->state_cur,
479 pending_state,
480 DRM_OUTPUT_STATE_CLEAR_PLANES);
481 state->dpms = WESTON_DPMS_ON;
482
Ankit Nautiyala344fe32019-05-14 18:36:08 +0530483 if (output_base->allow_protection)
484 state->protection = output_base->desired_protection;
485 else
486 state->protection = WESTON_HDCP_DISABLE;
487
Daniel Stonea08512f2016-11-08 17:46:10 +0000488 drm_output_render(state, damage);
489 scanout_state = drm_output_state_get_plane(state,
490 output->scanout_plane);
491 if (!scanout_state || !scanout_state->fb)
492 goto err;
493
Daniel Stonea08512f2016-11-08 17:46:10 +0000494 return 0;
495
496err:
497 drm_output_state_free(state);
David Herrmann1edf44c2013-10-22 17:11:26 +0200498 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400499}
500
Daniel Stone4c2fc702019-06-18 11:12:07 +0100501/* Determine the type of vblank synchronization to use for the output.
502 *
503 * The pipe parameter indicates which CRTC is in use. Knowing this, we
504 * can determine which vblank sequence type to use for it. Traditional
505 * cards had only two CRTCs, with CRTC 0 using no special flags, and
506 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
507 * parameter indicates this.
508 *
509 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
510 * 0-31. If this is non-zero it indicates we're dealing with a
511 * multi-gpu situation and we need to calculate the vblank sync
512 * using DRM_BLANK_HIGH_CRTC_MASK.
513 */
514static unsigned int
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300515drm_waitvblank_pipe(struct drm_crtc *crtc)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100516{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300517 if (crtc->pipe > 1)
518 return (crtc->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
Daniel Stone4c2fc702019-06-18 11:12:07 +0100519 DRM_VBLANK_HIGH_CRTC_MASK;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300520 else if (crtc->pipe > 0)
Daniel Stone4c2fc702019-06-18 11:12:07 +0100521 return DRM_VBLANK_SECONDARY;
522 else
523 return 0;
524}
525
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200526static int
Jonas Ådahle5a12252013-04-05 23:07:11 +0200527drm_output_start_repaint_loop(struct weston_output *output_base)
528{
Armin Krezović545dba62016-08-05 15:54:18 +0200529 struct drm_output *output = to_drm_output(output_base);
Daniel Stone8747f952016-11-29 20:17:32 +0000530 struct drm_pending_state *pending_state;
Daniel Stonee2e80132018-01-16 15:37:33 +0000531 struct drm_plane *scanout_plane = output->scanout_plane;
Armin Krezović545dba62016-08-05 15:54:18 +0200532 struct drm_backend *backend =
533 to_drm_backend(output_base->compositor);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200534 struct timespec ts, tnow;
535 struct timespec vbl2now;
536 int64_t refresh_nsec;
537 int ret;
538 drmVBlank vbl = {
539 .request.type = DRM_VBLANK_RELATIVE,
540 .request.sequence = 0,
541 .request.signal = 0,
542 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300543
Armin Krezović08368132016-09-30 14:11:05 +0200544 if (output->disable_pending || output->destroy_pending)
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200545 return 0;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800546
Leandro Ribeiro05cecc82020-08-13 17:34:58 -0300547 if (!scanout_plane->state_cur->fb) {
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300548 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200549 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300550 }
551
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300552 /* Need to smash all state in from scratch; current timings might not
553 * be what we want, page flip might not work, etc.
554 */
Daniel Stone6020f472018-02-05 15:46:20 +0000555 if (backend->state_invalid)
Pekka Paalanen6b65d8f2017-07-27 13:44:32 +0300556 goto finish_frame;
557
Daniel Stonee2e80132018-01-16 15:37:33 +0000558 assert(scanout_plane->state_cur->output == output);
559
Mario Kleinerf507ec32015-06-21 21:25:14 +0200560 /* Try to get current msc and timestamp via instant query */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300561 vbl.request.type |= drm_waitvblank_pipe(output->crtc);
Mario Kleinerf507ec32015-06-21 21:25:14 +0200562 ret = drmWaitVBlank(backend->drm.fd, &vbl);
563
564 /* Error ret or zero timestamp means failure to get valid timestamp */
565 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
566 ts.tv_sec = vbl.reply.tval_sec;
567 ts.tv_nsec = vbl.reply.tval_usec * 1000;
568
569 /* Valid timestamp for most recent vblank - not stale?
570 * Stale ts could happen on Linux 3.17+, so make sure it
571 * is not older than 1 refresh duration since now.
572 */
573 weston_compositor_read_presentation_clock(backend->compositor,
574 &tnow);
575 timespec_sub(&vbl2now, &tnow, &ts);
576 refresh_nsec =
577 millihz_to_nsec(output->base.current_mode->refresh);
578 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
579 drm_output_update_msc(output, vbl.reply.sequence);
580 weston_output_finish_frame(output_base, &ts,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200581 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200582 return 0;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200583 }
584 }
585
586 /* Immediate query didn't provide valid timestamp.
587 * Use pageflip fallback.
588 */
Jonas Ådahle5a12252013-04-05 23:07:11 +0200589
Daniel Stone205c0a02017-04-04 17:54:33 +0100590 assert(!output->page_flip_pending);
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000591 assert(!output->state_last);
592
593 pending_state = drm_pending_state_alloc(backend);
Daniel Stone8747f952016-11-29 20:17:32 +0000594 drm_output_state_duplicate(output->state_cur, pending_state,
595 DRM_OUTPUT_STATE_PRESERVE_PLANES);
Daniel Stone205c0a02017-04-04 17:54:33 +0100596
Daniel Stone8747f952016-11-29 20:17:32 +0000597 ret = drm_pending_state_apply(pending_state);
598 if (ret != 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200599 weston_log("applying repaint-start state failed: %s\n",
600 strerror(errno));
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200601 if (ret == -EACCES)
602 return -1;
David Herrmann3c688c52013-10-22 17:11:25 +0200603 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200604 }
David Herrmann3c688c52013-10-22 17:11:25 +0200605
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200606 return 0;
David Herrmann3c688c52013-10-22 17:11:25 +0200607
608finish_frame:
609 /* if we cannot page-flip, immediately finish frame */
Daniel Stone3615ce12017-03-01 11:34:05 +0000610 weston_output_finish_frame(output_base, NULL,
Pekka Paalanenb00c79b2016-02-18 16:53:27 +0200611 WP_PRESENTATION_FEEDBACK_INVALID);
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200612 return 0;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200613}
614
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000615/**
616 * Begin a new repaint cycle
617 *
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000618 * Called by the core compositor at the beginning of a repaint cycle. Creates
619 * a new pending_state structure to own any output state created by individual
620 * output repaint functions until the repaint is flushed or cancelled.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000621 */
622static void *
623drm_repaint_begin(struct weston_compositor *compositor)
624{
625 struct drm_backend *b = to_drm_backend(compositor);
626 struct drm_pending_state *ret;
627
628 ret = drm_pending_state_alloc(b);
629 b->repaint_data = ret;
630
Marius Vlad7e4db952019-04-17 13:47:06 +0300631 if (weston_log_scope_is_enabled(b->debug)) {
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100632 char *dbg = weston_compositor_print_scene_graph(compositor);
633 drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
634 ret);
635 drm_debug(b, "%s", dbg);
636 free(dbg);
637 }
638
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000639 return ret;
640}
641
642/**
643 * Flush a repaint set
644 *
645 * Called by the core compositor when a repaint cycle has been completed
Daniel Stone7b2ddac2016-11-11 19:11:49 +0000646 * and should be flushed. Frees the pending state, transitioning ownership
647 * of the output state from the pending state, to the update itself. When
648 * the update completes (see drm_output_update_complete), the output
649 * state will be freed.
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000650 */
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200651static int
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000652drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
653{
654 struct drm_backend *b = to_drm_backend(compositor);
655 struct drm_pending_state *pending_state = repaint_data;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200656 int ret;
Daniel Stone6020f472018-02-05 15:46:20 +0000657
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200658 ret = drm_pending_state_apply(pending_state);
659 if (ret != 0)
660 weston_log("repaint-flush failed: %s\n", strerror(errno));
661
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100662 drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000663 b->repaint_data = NULL;
Antonio Borneoc90fccc2019-06-30 15:51:10 +0200664
665 return (ret == -EACCES) ? -1 : 0;
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000666}
667
668/**
669 * Cancel a repaint set
670 *
671 * Called by the core compositor when a repaint has finished, so the data
672 * held across the repaint cycle should be discarded.
673 */
674static void
675drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
676{
677 struct drm_backend *b = to_drm_backend(compositor);
678 struct drm_pending_state *pending_state = repaint_data;
679
680 drm_pending_state_free(pending_state);
Daniel Stone1cbe1f92018-07-20 10:21:28 +0100681 drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
Daniel Stoneeedf84c2017-02-10 18:06:04 +0000682 b->repaint_data = NULL;
683}
684
Alex Wub7b8bda2012-04-17 17:20:48 +0800685static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300686drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Daniel Stone3e661f72016-11-04 17:24:06 +0000687static void
688drm_output_fini_pixman(struct drm_output *output);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200689
690static int
Alex Wub7b8bda2012-04-17 17:20:48 +0800691drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
692{
Daniel Stone02d487a2017-10-07 14:01:45 +0100693 struct drm_output *output = to_drm_output(output_base);
694 struct drm_backend *b = to_drm_backend(output_base->compositor);
Daniel Stonefbe6c1d2019-06-17 16:04:26 +0100695 struct drm_mode *drm_mode = drm_output_choose_mode(output, mode);
Alex Wub7b8bda2012-04-17 17:20:48 +0800696
697 if (!drm_mode) {
Daniel Stone02d487a2017-10-07 14:01:45 +0100698 weston_log("%s: invalid resolution %dx%d\n",
699 output_base->name, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800700 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200701 }
702
Hardeningff39efa2013-09-18 23:56:35 +0200703 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +0800704 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800705
Hardeningff39efa2013-09-18 23:56:35 +0200706 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800707
Hardeningff39efa2013-09-18 23:56:35 +0200708 output->base.current_mode = &drm_mode->base;
709 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +0800710 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
711
Daniel Stonef30a18c2017-04-04 17:54:31 +0100712 /* XXX: This drops our current buffer too early, before we've started
713 * displaying it. Ideally this should be much more atomic and
714 * integrated with a full repaint cycle, rather than doing a
715 * sledgehammer modeswitch first, and only later showing new
716 * content.
717 */
Daniel Stone6020f472018-02-05 15:46:20 +0000718 b->state_invalid = true;
Alex Wub7b8bda2012-04-17 17:20:48 +0800719
Giulio Camuffo954f1832014-10-11 18:27:30 +0300720 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200721 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300722 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200723 weston_log("failed to init output pixman state with "
724 "new mode\n");
725 return -1;
726 }
727 } else {
Daniel Stone3e661f72016-11-04 17:24:06 +0000728 drm_output_fini_egl(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +0300729 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200730 weston_log("failed to init output egl state with "
731 "new mode");
732 return -1;
733 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -0200734 }
735
Alex Wub7b8bda2012-04-17 17:20:48 +0800736 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +0800737}
738
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200739static int
Giulio Camuffo954f1832014-10-11 18:27:30 +0300740init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200741{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300742 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200743}
744
Pekka Paalanen7b36b422014-06-04 14:00:53 +0300745/**
Pekka Paalanenec272712014-06-05 11:22:25 +0300746 * Create a drm_plane for a hardware plane
747 *
748 * Creates one drm_plane structure for a hardware plane, and initialises its
749 * properties and formats.
750 *
751 * This function does not add the plane to the list of usable planes in Weston
752 * itself; the caller is responsible for this.
753 *
754 * Call drm_plane_destroy to clean up the plane.
755 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100756 * @sa drm_output_find_special_plane
Pekka Paalanenec272712014-06-05 11:22:25 +0300757 * @param b DRM compositor backend
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300758 * @param kplane DRM plane to create
Pekka Paalanenec272712014-06-05 11:22:25 +0300759 */
760static struct drm_plane *
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300761drm_plane_create(struct drm_backend *b, const drmModePlane *kplane)
Pekka Paalanenec272712014-06-05 11:22:25 +0300762{
763 struct drm_plane *plane;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100764 drmModeObjectProperties *props;
Marius Vladcdd6fa22019-08-29 20:42:00 +0300765 uint64_t *zpos_range_values;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100766
Scott Anderson74663092021-02-01 15:46:33 -0300767 plane = zalloc(sizeof(*plane));
Pekka Paalanenec272712014-06-05 11:22:25 +0300768 if (!plane) {
769 weston_log("%s: out of memory\n", __func__);
770 return NULL;
771 }
772
773 plane->backend = b;
Daniel Stone57d609a2021-11-16 18:56:09 +0000774 plane->plane_idx = b->next_plane_idx++;
Daniel Stonebc15f682016-11-14 16:57:01 +0000775 plane->state_cur = drm_plane_state_alloc(NULL, plane);
776 plane->state_cur->complete = true;
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300777 plane->possible_crtcs = kplane->possible_crtcs;
778 plane->plane_id = kplane->plane_id;
Pekka Paalanenec272712014-06-05 11:22:25 +0300779
Scott Anderson74663092021-02-01 15:46:33 -0300780 weston_drm_format_array_init(&plane->formats);
781
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300782 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
783 DRM_MODE_OBJECT_PLANE);
784 if (!props) {
785 weston_log("couldn't get plane properties\n");
786 goto err;
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100787 }
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300788
789 drm_property_info_populate(b, plane_props, plane->props,
790 WDRM_PLANE__COUNT, props);
791 plane->type =
792 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
793 props,
794 WDRM_PLANE_TYPE__COUNT);
795
796 zpos_range_values =
797 drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
798 props);
799
800 if (zpos_range_values) {
801 plane->zpos_min = zpos_range_values[0];
802 plane->zpos_max = zpos_range_values[1];
803 } else {
Marius Vladcdd6fa22019-08-29 20:42:00 +0300804 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300805 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100806 }
807
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300808 if (drm_plane_populate_formats(plane, kplane, props,
809 b->fb_modifiers) < 0) {
810 drmModeFreeObjectProperties(props);
811 goto err;
812 }
813
814 drmModeFreeObjectProperties(props);
815
Daniel Stone2ba17f42015-05-19 20:02:41 +0100816 if (plane->type == WDRM_PLANE_TYPE__COUNT)
817 goto err_props;
818
Pekka Paalanenec272712014-06-05 11:22:25 +0300819 weston_plane_init(&plane->base, b->compositor, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +0100820 wl_list_insert(&b->plane_list, &plane->link);
Pekka Paalanenec272712014-06-05 11:22:25 +0300821
822 return plane;
Daniel Stone2ba17f42015-05-19 20:02:41 +0100823
824err_props:
825 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
826err:
Scott Anderson74663092021-02-01 15:46:33 -0300827 weston_drm_format_array_fini(&plane->formats);
Daniel Stone2ba17f42015-05-19 20:02:41 +0100828 drm_plane_state_free(plane->state_cur, true);
829 free(plane);
830 return NULL;
831}
832
833/**
834 * Find, or create, a special-purpose plane
835 *
Daniel Stone2ba17f42015-05-19 20:02:41 +0100836 * @param b DRM backend
837 * @param output Output to use for plane
838 * @param type Type of plane
839 */
840static struct drm_plane *
841drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
842 enum wdrm_plane_type type)
843{
844 struct drm_plane *plane;
845
Daniel Stone2ba17f42015-05-19 20:02:41 +0100846 wl_list_for_each(plane, &b->plane_list, link) {
847 struct drm_output *tmp;
848 bool found_elsewhere = false;
849
850 if (plane->type != type)
851 continue;
852 if (!drm_plane_is_available(plane, output))
853 continue;
854
855 /* On some platforms, primary/cursor planes can roam
856 * between different CRTCs, so make sure we don't claim the
857 * same plane for two outputs. */
Leandro Ribeiro05cecc82020-08-13 17:34:58 -0300858 wl_list_for_each(tmp, &b->compositor->output_list, base.link) {
Daniel Stonee2e80132018-01-16 15:37:33 +0000859 if (tmp->cursor_plane == plane ||
860 tmp->scanout_plane == plane) {
Daniel Stone2ba17f42015-05-19 20:02:41 +0100861 found_elsewhere = true;
862 break;
863 }
864 }
865
866 if (found_elsewhere)
867 continue;
868
Leandro Ribeirob00d1a22020-08-13 14:12:28 -0300869 plane->possible_crtcs = (1 << output->crtc->pipe);
Daniel Stone2ba17f42015-05-19 20:02:41 +0100870 return plane;
871 }
872
873 return NULL;
Pekka Paalanenec272712014-06-05 11:22:25 +0300874}
875
876/**
877 * Destroy one DRM plane
878 *
879 * Destroy a DRM plane, removing it from screen and releasing its retained
880 * buffers in the process. The counterpart to drm_plane_create.
881 *
882 * @param plane Plane to deallocate (will be freed)
883 */
884static void
885drm_plane_destroy(struct drm_plane *plane)
886{
Daniel Stone2ba17f42015-05-19 20:02:41 +0100887 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
888 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
889 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stonebc15f682016-11-14 16:57:01 +0000890 drm_plane_state_free(plane->state_cur, true);
Pekka Paalanenc5de57f2015-05-20 23:01:44 +0100891 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
Pekka Paalanenec272712014-06-05 11:22:25 +0300892 weston_plane_release(&plane->base);
Scott Anderson74663092021-02-01 15:46:33 -0300893 weston_drm_format_array_fini(&plane->formats);
Pekka Paalanenec272712014-06-05 11:22:25 +0300894 wl_list_remove(&plane->link);
895 free(plane);
896}
897
898/**
899 * Initialise sprites (overlay planes)
900 *
901 * Walk the list of provided DRM planes, and add overlay planes.
902 *
903 * Call destroy_sprites to free these planes.
904 *
905 * @param b DRM compositor backend
906 */
907static void
908create_sprites(struct drm_backend *b)
909{
910 drmModePlaneRes *kplane_res;
911 drmModePlane *kplane;
912 struct drm_plane *drm_plane;
913 uint32_t i;
Pekka Paalanenec272712014-06-05 11:22:25 +0300914 kplane_res = drmModeGetPlaneResources(b->drm.fd);
915 if (!kplane_res) {
916 weston_log("failed to get plane resources: %s\n",
917 strerror(errno));
918 return;
919 }
920
921 for (i = 0; i < kplane_res->count_planes; i++) {
922 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
923 if (!kplane)
924 continue;
925
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -0300926 drm_plane = drm_plane_create(b, kplane);
Pekka Paalanenec272712014-06-05 11:22:25 +0300927 drmModeFreePlane(kplane);
928 if (!drm_plane)
929 continue;
930
Daniel Stone085d2b92015-05-21 00:00:57 +0100931 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
932 weston_compositor_stack_plane(b->compositor,
933 &drm_plane->base,
934 &b->compositor->primary_plane);
Pekka Paalanenec272712014-06-05 11:22:25 +0300935 }
936
937 drmModeFreePlaneResources(kplane_res);
938}
939
940/**
941 * Clean up sprites (overlay planes)
942 *
943 * The counterpart to create_sprites.
944 *
945 * @param b DRM compositor backend
946 */
947static void
948destroy_sprites(struct drm_backend *b)
949{
950 struct drm_plane *plane, *next;
951
Daniel Stone085d2b92015-05-21 00:00:57 +0100952 wl_list_for_each_safe(plane, next, &b->plane_list, link)
Pekka Paalanenec272712014-06-05 11:22:25 +0300953 drm_plane_destroy(plane);
954}
955
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -0300956/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200957static uint32_t
Pekka Paalanence724242017-09-04 12:21:24 +0300958drm_get_backlight(struct drm_head *head)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200959{
960 long brightness, max_brightness, norm;
961
Pekka Paalanence724242017-09-04 12:21:24 +0300962 brightness = backlight_get_brightness(head->backlight);
963 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200964
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -0300965 /* convert it on a scale of 0 to 255 */
966 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200967
968 return (uint32_t) norm;
969}
970
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -0300971/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200972static void
973drm_set_backlight(struct weston_output *output_base, uint32_t value)
974{
Pekka Paalanenecc8cce2017-09-12 16:14:31 +0300975 struct drm_output *output = to_drm_output(output_base);
976 struct drm_head *head;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200977 long max_brightness, new_brightness;
978
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400979 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200980 return;
981
Pekka Paalanenecc8cce2017-09-12 16:14:31 +0300982 wl_list_for_each(head, &output->base.head_list, base.output_link) {
983 if (!head->backlight)
984 return;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200985
Pekka Paalanenecc8cce2017-09-12 16:14:31 +0300986 max_brightness = backlight_get_max_brightness(head->backlight);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200987
Pekka Paalanenecc8cce2017-09-12 16:14:31 +0300988 /* get denormalized value */
989 new_brightness = (value * max_brightness) / 255;
990
991 backlight_set_brightness(head->backlight, new_brightness);
992 }
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200993}
994
Pekka Paalanenf8b850d2017-11-15 12:51:01 +0200995static void
996drm_output_init_backlight(struct drm_output *output)
997{
998 struct weston_head *base;
999 struct drm_head *head;
1000
1001 output->base.set_backlight = NULL;
1002
1003 wl_list_for_each(base, &output->base.head_list, output_link) {
1004 head = to_drm_head(base);
1005
1006 if (head->backlight) {
1007 weston_log("Initialized backlight for head '%s', device %s\n",
1008 head->base.name, head->backlight->path);
1009
1010 if (!output->base.set_backlight) {
1011 output->base.set_backlight = drm_set_backlight;
1012 output->base.backlight_current =
1013 drm_get_backlight(head);
1014 }
1015 }
1016 }
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001017}
1018
Daniel Stonea08512f2016-11-08 17:46:10 +00001019/**
1020 * Power output on or off
1021 *
1022 * The DPMS/power level of an output is used to switch it on or off. This
1023 * is DRM's hook for doing so, which can called either as part of repaint,
1024 * or independently of the repaint loop.
1025 *
1026 * If we are called as part of repaint, we simply set the relevant bit in
1027 * state and return.
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001028 *
1029 * This function is never called on a virtual output.
Daniel Stonea08512f2016-11-08 17:46:10 +00001030 */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001031static void
1032drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1033{
Armin Krezović545dba62016-08-05 15:54:18 +02001034 struct drm_output *output = to_drm_output(output_base);
Daniel Stonea08512f2016-11-08 17:46:10 +00001035 struct drm_backend *b = to_drm_backend(output_base->compositor);
1036 struct drm_pending_state *pending_state = b->repaint_data;
1037 struct drm_output_state *state;
Daniel Stone36609c72015-06-18 07:49:02 +01001038 int ret;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001039
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001040 assert(!output->virtual);
1041
Daniel Stonea08512f2016-11-08 17:46:10 +00001042 if (output->state_cur->dpms == level)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001043 return;
1044
Daniel Stonea08512f2016-11-08 17:46:10 +00001045 /* If we're being called during the repaint loop, then this is
1046 * simple: discard any previously-generated state, and create a new
1047 * state where we disable everything. When we come to flush, this
1048 * will be applied.
1049 *
1050 * However, we need to be careful: we can be called whilst another
1051 * output is in its repaint cycle (pending_state exists), but our
1052 * output still has an incomplete state application outstanding.
1053 * In that case, we need to wait until that completes. */
1054 if (pending_state && !output->state_last) {
1055 /* The repaint loop already sets DPMS on; we don't need to
1056 * explicitly set it on here, as it will already happen
1057 * whilst applying the repaint state. */
1058 if (level == WESTON_DPMS_ON)
1059 return;
1060
1061 state = drm_pending_state_get_output(pending_state, output);
1062 if (state)
1063 drm_output_state_free(state);
1064 state = drm_output_get_disable_state(pending_state, output);
Daniel Stone36609c72015-06-18 07:49:02 +01001065 return;
1066 }
1067
Daniel Stonea08512f2016-11-08 17:46:10 +00001068 /* As we throw everything away when disabling, just send us back through
1069 * a repaint cycle. */
1070 if (level == WESTON_DPMS_ON) {
1071 if (output->dpms_off_pending)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001072 output->dpms_off_pending = false;
Daniel Stonea08512f2016-11-08 17:46:10 +00001073 weston_output_schedule_repaint(output_base);
1074 return;
1075 }
1076
1077 /* If we've already got a request in the pipeline, then we need to
1078 * park our DPMS request until that request has quiesced. */
1079 if (output->state_last) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001080 output->dpms_off_pending = true;
Daniel Stonea08512f2016-11-08 17:46:10 +00001081 return;
1082 }
1083
1084 pending_state = drm_pending_state_alloc(b);
1085 drm_output_get_disable_state(pending_state, output);
1086 ret = drm_pending_state_apply_sync(pending_state);
1087 if (ret != 0)
1088 weston_log("drm_set_dpms: couldn't disable output?\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001089}
1090
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001091static const char * const connector_type_names[] = {
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001092 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
1093 [DRM_MODE_CONNECTOR_VGA] = "VGA",
1094 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
1095 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
1096 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
1097 [DRM_MODE_CONNECTOR_Composite] = "Composite",
1098 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
1099 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
1100 [DRM_MODE_CONNECTOR_Component] = "Component",
1101 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
1102 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
1103 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
1104 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
1105 [DRM_MODE_CONNECTOR_TV] = "TV",
1106 [DRM_MODE_CONNECTOR_eDP] = "eDP",
1107 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
1108 [DRM_MODE_CONNECTOR_DSI] = "DSI",
Stefan Agner30e283d2018-08-20 17:11:38 +02001109 [DRM_MODE_CONNECTOR_DPI] = "DPI",
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001110};
1111
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001112/** Create a name given a DRM connector
1113 *
1114 * \param con The DRM connector whose type and id form the name.
1115 * \return A newly allocate string, or NULL on error. Must be free()'d
1116 * after use.
1117 *
1118 * The name does not identify the DRM display device.
1119 */
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001120static char *
1121make_connector_name(const drmModeConnector *con)
1122{
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001123 char *name;
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001124 const char *type_name = NULL;
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001125 int ret;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001126
1127 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1128 type_name = connector_type_names[con->connector_type];
Pekka Paalanen89c49b32015-08-19 15:25:57 +03001129
1130 if (!type_name)
1131 type_name = "UNNAMED";
1132
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001133 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
1134 if (ret < 0)
1135 return NULL;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001136
Pekka Paalanen1f21ef12017-04-03 13:33:26 +03001137 return name;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001138}
1139
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001140static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001141drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001142{
Hardeningff39efa2013-09-18 23:56:35 +02001143 int w = output->base.current_mode->width;
1144 int h = output->base.current_mode->height;
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001145 uint32_t format = output->gbm_format;
1146 uint32_t pixman_format;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001147 unsigned int i;
Daniel Stone61abf352020-03-06 12:46:30 +00001148 const struct pixman_renderer_output_options options = {
1149 .use_shadow = b->use_pixman_shadow,
1150 };
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001151
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001152 switch (format) {
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001153 case DRM_FORMAT_XRGB8888:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001154 pixman_format = PIXMAN_x8r8g8b8;
1155 break;
Stefan Agner0bfebeb2019-07-08 00:30:44 +02001156 case DRM_FORMAT_RGB565:
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001157 pixman_format = PIXMAN_r5g6b5;
1158 break;
1159 default:
1160 weston_log("Unsupported pixman format 0x%x\n", format);
1161 return -1;
1162 }
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001163
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001164 /* FIXME error checking */
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001165 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001166 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001167 if (!output->dumb[i])
1168 goto err;
1169
1170 output->image[i] =
Tomi Valkeinenf8da0c22016-06-20 14:18:45 +03001171 pixman_image_create_bits(pixman_format, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001172 output->dumb[i]->map,
Daniel Stone8eece0c2016-11-17 17:54:00 +00001173 output->dumb[i]->strides[0]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001174 if (!output->image[i])
1175 goto err;
1176 }
1177
Daniel Stone61abf352020-03-06 12:46:30 +00001178 if (pixman_renderer_output_create(&output->base, &options) < 0)
Dongjin Kimba89f002024-09-30 17:49:36 +09001179 goto err;
Ankit Nautiyala21c3932097-03-19 00:24:57 +05301180
Pekka Paalanendee412d2018-04-23 11:44:58 +02001181 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
1182 b->use_pixman_shadow ? "uses" : "does not use");
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001183
1184 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001185 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001186
1187 return 0;
1188
1189err:
1190 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1191 if (output->dumb[i])
Daniel Stone6e7a9612017-04-04 17:54:26 +01001192 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001193 if (output->image[i])
1194 pixman_image_unref(output->image[i]);
1195
1196 output->dumb[i] = NULL;
1197 output->image[i] = NULL;
1198 }
1199
1200 return -1;
1201}
1202
1203static void
1204drm_output_fini_pixman(struct drm_output *output)
1205{
Daniel Stonee2e80132018-01-16 15:37:33 +00001206 struct drm_backend *b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001207 unsigned int i;
1208
Daniel Stonee2e80132018-01-16 15:37:33 +00001209 /* Destroying the Pixman surface will destroy all our buffers,
1210 * regardless of refcount. Ensure we destroy them here. */
1211 if (!b->shutting_down &&
1212 output->scanout_plane->state_cur->fb &&
1213 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
Alexandros Frantzis99751342020-05-18 15:22:49 +03001214 drm_plane_reset_state(output->scanout_plane);
Daniel Stonee2e80132018-01-16 15:37:33 +00001215 }
1216
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001217 pixman_renderer_output_destroy(&output->base);
1218 pixman_region32_fini(&output->previous_damage);
1219
1220 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001221 pixman_image_unref(output->image[i]);
Daniel Stone6e7a9612017-04-04 17:54:26 +01001222 drm_fb_unref(output->dumb[i]);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001223 output->dumb[i] = NULL;
1224 output->image[i] = NULL;
1225 }
1226}
1227
Richard Hughes2b2092a2013-04-24 14:58:02 +01001228static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001229setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01001230 struct weston_output *output,
1231 const char *s)
1232{
1233 if (strcmp(s, "") != 0) {
Derek Foreman1281a362015-07-31 16:55:32 -05001234 struct weston_pointer *pointer;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001235 struct udev_seat *seat;
1236
Giulio Camuffo954f1832014-10-11 18:27:30 +03001237 seat = udev_seat_get_named(&b->input, s);
Derek Foreman0720ea32015-07-15 13:00:35 -05001238 if (!seat)
1239 return;
Rob Bradford66bd9f52013-06-25 18:56:42 +01001240
Derek Foreman0720ea32015-07-15 13:00:35 -05001241 seat->base.output = output;
1242
Derek Foreman1281a362015-07-31 16:55:32 -05001243 pointer = weston_seat_get_pointer(&seat->base);
1244 if (pointer)
1245 weston_pointer_clamp(pointer,
1246 &pointer->x,
1247 &pointer->y);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001248 }
1249}
1250
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001251static int
Pekka Paalanenc112f002017-08-28 16:27:20 +03001252drm_output_attach_head(struct weston_output *output_base,
1253 struct weston_head *head_base)
1254{
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001255 struct drm_backend *b = to_drm_backend(output_base->compositor);
1256
Pekka Paalanenc112f002017-08-28 16:27:20 +03001257 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
1258 return -1;
1259
Pekka Paalanend5f98d82017-12-08 14:45:00 +02001260 if (!output_base->enabled)
1261 return 0;
1262
1263 /* XXX: ensure the configuration will work.
1264 * This is actually impossible without major infrastructure
1265 * work. */
1266
1267 /* Need to go through modeset to add connectors. */
1268 /* XXX: Ideally we'd do this per-output, not globally. */
1269 /* XXX: Doing it globally, what guarantees another output's update
1270 * will not clear the flag before this output is updated?
1271 */
1272 b->state_invalid = true;
1273
1274 weston_output_schedule_repaint(output_base);
1275
Pekka Paalanenc112f002017-08-28 16:27:20 +03001276 return 0;
1277}
1278
Pekka Paalanen7f853792017-11-29 14:33:33 +02001279static void
1280drm_output_detach_head(struct weston_output *output_base,
1281 struct weston_head *head_base)
1282{
1283 struct drm_backend *b = to_drm_backend(output_base->compositor);
1284
1285 if (!output_base->enabled)
1286 return;
1287
1288 /* Need to go through modeset to drop connectors that should no longer
1289 * be driven. */
1290 /* XXX: Ideally we'd do this per-output, not globally. */
1291 b->state_invalid = true;
1292
1293 weston_output_schedule_repaint(output_base);
1294}
1295
Stefan Agner3654c672019-07-09 00:50:30 +02001296int
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001297parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001298{
Pekka Paalanen62a94362018-09-26 14:33:36 +03001299 const struct pixel_format_info *pinfo;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001300
Pekka Paalanen62a94362018-09-26 14:33:36 +03001301 if (s == NULL) {
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001302 *gbm_format = default_value;
Pekka Paalanen62a94362018-09-26 14:33:36 +03001303
1304 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001305 }
1306
Pekka Paalanen62a94362018-09-26 14:33:36 +03001307 pinfo = pixel_format_get_info_by_drm_name(s);
1308 if (!pinfo) {
1309 weston_log("fatal: unrecognized pixel format: %s\n", s);
1310
1311 return -1;
1312 }
1313
1314 /* GBM formats and DRM formats are identical. */
1315 *gbm_format = pinfo->format;
1316
1317 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001318}
1319
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001320static int
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001321drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001322{
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02001323 int drm_fd = backend->drm.fd;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001324 drmModeConnector *conn = head->connector.conn;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001325 drmModeEncoder *encoder;
1326 drmModeCrtc *crtc;
1327
1328 /* Get the current mode on the crtc that's currently driving
1329 * this connector. */
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001330 encoder = drmModeGetEncoder(drm_fd, conn->encoder_id);
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001331 if (encoder != NULL) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001332 head->inherited_crtc_id = encoder->crtc_id;
1333
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001334 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
1335 drmModeFreeEncoder(encoder);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001336
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001337 if (crtc == NULL)
1338 return -1;
1339 if (crtc->mode_valid)
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02001340 head->inherited_mode = crtc->mode;
Pekka Paalaneneee580b2014-06-04 16:43:06 +03001341 drmModeFreeCrtc(crtc);
1342 }
1343
1344 return 0;
1345}
1346
Armin Krezović08368132016-09-30 14:11:05 +02001347static void
1348drm_output_set_gbm_format(struct weston_output *base,
1349 const char *gbm_format)
1350{
1351 struct drm_output *output = to_drm_output(base);
1352 struct drm_backend *b = to_drm_backend(base->compositor);
1353
1354 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
1355 output->gbm_format = b->gbm_format;
1356}
1357
1358static void
1359drm_output_set_seat(struct weston_output *base,
1360 const char *seat)
1361{
1362 struct drm_output *output = to_drm_output(base);
1363 struct drm_backend *b = to_drm_backend(base->compositor);
1364
1365 setup_output_seat_constraint(b, &output->base,
1366 seat ? seat : "");
1367}
1368
1369static int
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001370drm_output_init_gamma_size(struct drm_output *output)
1371{
1372 struct drm_backend *backend = to_drm_backend(output->base.compositor);
1373 drmModeCrtc *crtc;
1374
1375 assert(output->base.compositor);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001376 assert(output->crtc);
1377 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc->crtc_id);
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001378 if (!crtc)
1379 return -1;
1380
1381 output->base.gamma_size = crtc->gamma_size;
1382
1383 drmModeFreeCrtc(crtc);
1384
1385 return 0;
1386}
1387
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001388static uint32_t
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001389drm_connector_get_possible_crtcs_mask(struct drm_connector *connector)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001390{
1391 uint32_t possible_crtcs = 0;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001392 drmModeConnector *conn = connector->conn;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001393 drmModeEncoder *encoder;
1394 int i;
1395
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001396 for (i = 0; i < conn->count_encoders; i++) {
1397 encoder = drmModeGetEncoder(connector->backend->drm.fd,
1398 conn->encoders[i]);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001399 if (!encoder)
1400 continue;
1401
1402 possible_crtcs |= encoder->possible_crtcs;
1403 drmModeFreeEncoder(encoder);
1404 }
1405
1406 return possible_crtcs;
1407}
1408
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001409/** Pick a CRTC that might be able to drive all attached connectors
1410 *
1411 * @param output The output whose attached heads to include.
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001412 * @return CRTC object to pick, or NULL on failure or not found.
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001413 */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001414static struct drm_crtc *
1415drm_output_pick_crtc(struct drm_output *output)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001416{
1417 struct drm_backend *backend;
1418 struct weston_head *base;
1419 struct drm_head *head;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001420 struct drm_crtc *crtc;
1421 struct drm_crtc *best_crtc = NULL;
1422 struct drm_crtc *fallback_crtc = NULL;
1423 struct drm_crtc *existing_crtc[32];
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001424 uint32_t possible_crtcs = 0xffffffff;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001425 unsigned n = 0;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001426 uint32_t crtc_id;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001427 unsigned int i;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001428 bool match;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001429
1430 backend = to_drm_backend(output->base.compositor);
1431
1432 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
1433 * because it is more often set wrong than not in the kernel. */
1434
1435 /* Accumulate a mask of possible crtcs and find existing routings. */
1436 wl_list_for_each(base, &output->base.head_list, output_link) {
1437 head = to_drm_head(base);
1438
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001439 possible_crtcs &=
1440 drm_connector_get_possible_crtcs_mask(&head->connector);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001441
1442 crtc_id = head->inherited_crtc_id;
1443 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001444 existing_crtc[n++] = drm_crtc_find(backend, crtc_id);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001445 }
1446
1447 /* Find a crtc that could drive each connector individually at least,
1448 * and prefer existing routings. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001449 wl_list_for_each(crtc, &backend->crtc_list, link) {
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001450
1451 /* Could the crtc not drive each connector? */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001452 if (!(possible_crtcs & (1 << crtc->pipe)))
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001453 continue;
1454
1455 /* Is the crtc already in use? */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001456 if (crtc->output)
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001457 continue;
1458
1459 /* Try to preserve the existing CRTC -> connector routing;
1460 * it makes initialisation faster, and also since we have a
1461 * very dumb picking algorithm, may preserve a better
1462 * choice. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001463 for (i = 0; i < n; i++) {
1464 if (existing_crtc[i] == crtc)
1465 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001466 }
1467
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001468 /* Check if any other head had existing routing to this CRTC.
1469 * If they did, this is not the best CRTC as it might be needed
1470 * for another output we haven't enabled yet. */
1471 match = false;
1472 wl_list_for_each(base, &backend->compositor->head_list,
1473 compositor_link) {
1474 head = to_drm_head(base);
1475
1476 if (head->base.output == &output->base)
1477 continue;
1478
1479 if (weston_head_is_enabled(&head->base))
1480 continue;
1481
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001482 if (head->inherited_crtc_id == crtc->crtc_id) {
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001483 match = true;
1484 break;
1485 }
1486 }
1487 if (!match)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001488 best_crtc = crtc;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001489
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001490 fallback_crtc = crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001491 }
1492
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001493 if (best_crtc)
1494 return best_crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001495
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001496 if (fallback_crtc)
1497 return fallback_crtc;
Pekka Paalanendb4c7d72017-11-28 16:11:00 +02001498
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001499 /* Likely possible_crtcs was empty due to asking for clones,
1500 * but since the DRM documentation says the kernel lies, let's
1501 * pick one crtc anyway. Trial and error is the only way to
1502 * be sure if something doesn't work. */
1503
1504 /* First pick any existing assignment. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001505 for (i = 0; i < n; i++) {
1506 crtc = existing_crtc[i];
1507 if (!crtc->output)
1508 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001509 }
1510
1511 /* Otherwise pick any available crtc. */
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001512 wl_list_for_each(crtc, &backend->crtc_list, link) {
1513 if (!crtc->output)
1514 return crtc;
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001515 }
1516
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001517 return NULL;
1518}
1519
1520/** Create an "empty" drm_crtc. It will only set its ID, pipe and props. After
1521 * all, it adds the object to the DRM-backend CRTC list.
1522 */
1523static struct drm_crtc *
1524drm_crtc_create(struct drm_backend *b, uint32_t crtc_id, uint32_t pipe)
1525{
1526 struct drm_crtc *crtc;
1527 drmModeObjectPropertiesPtr props;
1528
1529 props = drmModeObjectGetProperties(b->drm.fd, crtc_id,
1530 DRM_MODE_OBJECT_CRTC);
1531 if (!props) {
1532 weston_log("failed to get CRTC properties\n");
1533 return NULL;
1534 }
1535
1536 crtc = zalloc(sizeof(*crtc));
1537 if (!crtc)
1538 goto ret;
1539
1540 drm_property_info_populate(b, crtc_props, crtc->props_crtc,
1541 WDRM_CRTC__COUNT, props);
1542 crtc->backend = b;
1543 crtc->crtc_id = crtc_id;
1544 crtc->pipe = pipe;
1545 crtc->output = NULL;
1546
1547 /* Add it to the last position of the DRM-backend CRTC list */
1548 wl_list_insert(b->crtc_list.prev, &crtc->link);
1549
1550ret:
1551 drmModeFreeObjectProperties(props);
1552 return crtc;
1553}
1554
1555/** Destroy a drm_crtc object that was created with drm_crtc_create(). It will
1556 * also remove it from the DRM-backend CRTC list.
1557 */
1558static void
1559drm_crtc_destroy(struct drm_crtc *crtc)
1560{
1561 /* TODO: address the issue below to be able to remove the comment
1562 * from the assert.
1563 *
1564 * https://gitlab.freedesktop.org/wayland/weston/-/issues/421
1565 */
1566
1567 //assert(!crtc->output);
1568
1569 wl_list_remove(&crtc->link);
1570 drm_property_info_free(crtc->props_crtc, WDRM_CRTC__COUNT);
1571 free(crtc);
1572}
1573
1574/** Find all CRTCs of the fd and create drm_crtc objects for them.
1575 *
1576 * The CRTCs are saved in a list of the drm_backend and will keep there until
1577 * the fd gets closed.
1578 *
1579 * @param b The DRM-backend structure.
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03001580 * @param resources The DRM resources, it is taken with drmModeGetResources
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001581 * @return 0 on success (at least one CRTC in the list), -1 on failure.
1582 */
1583static int
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03001584drm_backend_create_crtc_list(struct drm_backend *b, drmModeRes *resources)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001585{
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001586 struct drm_crtc *crtc, *crtc_tmp;
1587 int i;
1588
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001589 /* Iterate through all CRTCs */
1590 for (i = 0; i < resources->count_crtcs; i++) {
1591
1592 /* Let's create an object for the CRTC and add it to the list */
1593 crtc = drm_crtc_create(b, resources->crtcs[i], i);
1594 if (!crtc)
1595 goto err;
1596 }
1597
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001598 return 0;
1599
1600err:
1601 wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
1602 drm_crtc_destroy(crtc);
Pekka Paalanen27cc4812017-11-20 13:31:06 +02001603 return -1;
1604}
1605
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001606
1607/** Populates scanout and cursor planes for the output. Also sets the topology
1608 * of the planes by adding them to the plane stacking list.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001609 */
1610static int
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001611drm_output_init_planes(struct drm_output *output)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001612{
1613 struct drm_backend *b = to_drm_backend(output->base.compositor);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001614
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001615 output->scanout_plane =
1616 drm_output_find_special_plane(b, output,
1617 WDRM_PLANE_TYPE_PRIMARY);
1618 if (!output->scanout_plane) {
1619 weston_log("Failed to find primary plane for output %s\n",
1620 output->base.name);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001621 return -1;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001622 }
1623
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001624 weston_compositor_stack_plane(b->compositor,
1625 &output->scanout_plane->base,
1626 &b->compositor->primary_plane);
1627
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001628 /* Failing to find a cursor plane is not fatal, as we'll fall back
1629 * to software cursor. */
1630 output->cursor_plane =
1631 drm_output_find_special_plane(b, output,
1632 WDRM_PLANE_TYPE_CURSOR);
1633
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001634 if (output->cursor_plane)
1635 weston_compositor_stack_plane(b->compositor,
1636 &output->cursor_plane->base,
1637 NULL);
1638 else
1639 b->cursors_are_broken = true;
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001640
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001641 return 0;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001642}
1643
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001644/** The opposite of drm_output_init_planes(). First of all it removes the planes
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001645 * from the plane stacking list. After all it sets the planes of the output as NULL.
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001646 */
1647static void
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001648drm_output_deinit_planes(struct drm_output *output)
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001649{
1650 struct drm_backend *b = to_drm_backend(output->base.compositor);
1651
Alexandros Frantzis53a71cb2020-05-18 15:26:01 +03001652 /* If the compositor is already shutting down, the planes have already
1653 * been destroyed. */
1654 if (!b->shutting_down) {
Pekka Paalanen3d6721e2020-09-16 15:04:04 +03001655 wl_list_remove(&output->scanout_plane->base.link);
1656 wl_list_init(&output->scanout_plane->base.link);
1657
1658 if (output->cursor_plane) {
1659 wl_list_remove(&output->cursor_plane->base.link);
1660 wl_list_init(&output->cursor_plane->base.link);
1661 /* Turn off hardware cursor */
1662 drmModeSetCursor(b->drm.fd, output->crtc->crtc_id, 0, 0, 0);
1663 }
1664
Igor Matheus Andrade Torrentebfcb1ad2020-10-12 13:37:07 -03001665 /* With universal planes, the planes are allocated at startup,
1666 * freed at shutdown, and live on the plane list in between.
1667 * We want the planes to continue to exist and be freed up
1668 * for other outputs.
1669 */
1670 if (output->cursor_plane)
1671 drm_plane_reset_state(output->cursor_plane);
1672 if (output->scanout_plane)
1673 drm_plane_reset_state(output->scanout_plane);
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001674 }
1675
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001676 output->cursor_plane = NULL;
1677 output->scanout_plane = NULL;
1678}
1679
Leandro Ribeiro54293022021-10-12 14:48:36 -03001680static struct weston_drm_format_array *
1681get_scanout_formats(struct drm_backend *b)
1682{
1683 struct weston_compositor *ec = b->compositor;
1684 const struct weston_drm_format_array *renderer_formats;
1685 struct weston_drm_format_array *scanout_formats, union_planes_formats;
1686 struct drm_plane *plane;
1687 int ret;
1688
1689 /* If we got here it means that dma-buf feedback is supported and that
1690 * the renderer has formats/modifiers to expose. */
1691 assert(ec->renderer->get_supported_formats != NULL);
1692 renderer_formats = ec->renderer->get_supported_formats(ec);
1693
1694 scanout_formats = zalloc(sizeof(*scanout_formats));
1695 if (!scanout_formats) {
1696 weston_log("%s: out of memory\n", __func__);
1697 return NULL;
1698 }
1699
1700 weston_drm_format_array_init(&union_planes_formats);
1701 weston_drm_format_array_init(scanout_formats);
1702
1703 /* Compute the union of the format/modifiers of the KMS planes */
1704 wl_list_for_each(plane, &b->plane_list, link) {
1705 /* The scanout formats are used by the dma-buf feedback. But for
1706 * now cursor planes do not support dma-buf buffers, only wl_shm
1707 * buffers. So we skip cursor planes here. */
1708 if (plane->type == WDRM_PLANE_TYPE_CURSOR)
1709 continue;
1710
1711 ret = weston_drm_format_array_join(&union_planes_formats,
1712 &plane->formats);
1713 if (ret < 0)
1714 goto err;
1715 }
1716
1717 /* Compute the intersection between the union of format/modifiers of KMS
1718 * planes and the formats supported by the renderer */
1719 ret = weston_drm_format_array_replace(scanout_formats,
1720 renderer_formats);
1721 if (ret < 0)
1722 goto err;
1723
1724 ret = weston_drm_format_array_intersect(scanout_formats,
1725 &union_planes_formats);
1726 if (ret < 0)
1727 goto err;
1728
1729 weston_drm_format_array_fini(&union_planes_formats);
1730
1731 return scanout_formats;
1732
1733err:
1734 weston_drm_format_array_fini(&union_planes_formats);
1735 weston_drm_format_array_fini(scanout_formats);
Daniel Stonef5086032021-12-06 16:52:19 +00001736 free(scanout_formats);
Leandro Ribeiro54293022021-10-12 14:48:36 -03001737 return NULL;
1738}
1739
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001740/** Pick a CRTC and reserve it for the output.
1741 *
1742 * On failure, the output remains without a CRTC.
1743 *
1744 * @param output The output with no CRTC associated.
1745 * @return 0 on success, -1 on failure.
1746 */
1747static int
1748drm_output_attach_crtc(struct drm_output *output)
1749{
1750 output->crtc = drm_output_pick_crtc(output);
1751 if (!output->crtc) {
1752 weston_log("Output '%s': No available CRTCs.\n",
1753 output->base.name);
1754 return -1;
1755 }
1756
1757 /* Reserve the CRTC for the output */
1758 output->crtc->output = output;
1759
1760 return 0;
1761}
1762
1763/** Release reservation of the CRTC.
1764 *
1765 * Make the CRTC free to be reserved and used by another output.
1766 *
1767 * @param output The output that will release its CRTC.
1768 */
1769static void
1770drm_output_detach_crtc(struct drm_output *output)
1771{
1772 struct drm_backend *b = output->backend;
1773 struct drm_crtc *crtc = output->crtc;
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001774
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001775 crtc->output = NULL;
1776 output->crtc = NULL;
1777
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001778 /* Force resetting unused CRTCs */
1779 b->state_invalid = true;
Pekka Paalanenfc5f5d72017-09-05 16:11:15 +03001780}
1781
Pekka Paalanenc4db6f72017-09-05 16:37:03 +03001782static int
Armin Krezović08368132016-09-30 14:11:05 +02001783drm_output_enable(struct weston_output *base)
1784{
1785 struct drm_output *output = to_drm_output(base);
1786 struct drm_backend *b = to_drm_backend(base->compositor);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001787 int ret;
1788
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001789 assert(!output->virtual);
1790
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001791 ret = drm_output_attach_crtc(output);
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001792 if (ret < 0)
1793 return -1;
1794
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001795 ret = drm_output_init_planes(output);
1796 if (ret < 0)
1797 goto err_crtc;
1798
Pekka Paalanen663d5e92017-09-08 13:32:40 +03001799 if (drm_output_init_gamma_size(output) < 0)
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001800 goto err_planes;
Armin Krezović08368132016-09-30 14:11:05 +02001801
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001802 if (b->pageflip_timeout)
1803 drm_output_pageflip_timer_create(output);
1804
Giulio Camuffo954f1832014-10-11 18:27:30 +03001805 if (b->use_pixman) {
1806 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001807 weston_log("Failed to init output pixman state\n");
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001808 goto err_planes;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001809 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03001810 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001811 weston_log("Failed to init output gl state\n");
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001812 goto err_planes;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001813 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001814
Pekka Paalanenf8b850d2017-11-15 12:51:01 +02001815 drm_output_init_backlight(output);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001816
Jonas Ådahle5a12252013-04-05 23:07:11 +02001817 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001818 output->base.repaint = drm_output_repaint;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001819 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001820 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001821 output->base.switch_mode = drm_output_switch_mode;
Richard Hughese7299962013-05-01 21:52:12 +01001822 output->base.set_gamma = drm_output_set_gamma;
1823
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001824 weston_log("Output %s (crtc %d) video modes:\n",
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001825 output->base.name, output->crtc->crtc_id);
Pekka Paalanenc0eb2542017-11-15 13:37:18 +02001826 drm_output_print_modes(output);
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001827
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001828 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001829
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001830err_planes:
1831 drm_output_deinit_planes(output);
1832err_crtc:
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001833 drm_output_detach_crtc(output);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001834 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001835}
1836
Jesse Barnes58ef3792012-02-23 09:45:49 -05001837static void
Armin Krezović08368132016-09-30 14:11:05 +02001838drm_output_deinit(struct weston_output *base)
1839{
1840 struct drm_output *output = to_drm_output(base);
1841 struct drm_backend *b = to_drm_backend(base->compositor);
1842
Daniel Stone3e661f72016-11-04 17:24:06 +00001843 if (b->use_pixman)
Armin Krezović08368132016-09-30 14:11:05 +02001844 drm_output_fini_pixman(output);
Daniel Stone3e661f72016-11-04 17:24:06 +00001845 else
1846 drm_output_fini_egl(output);
Armin Krezović08368132016-09-30 14:11:05 +02001847
Leandro Ribeiro3be23ef2020-08-13 16:44:02 -03001848 drm_output_deinit_planes(output);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03001849 drm_output_detach_crtc(output);
Armin Krezović08368132016-09-30 14:11:05 +02001850}
1851
1852static void
Pekka Paalanenc112f002017-08-28 16:27:20 +03001853drm_head_destroy(struct drm_head *head);
1854
1855static void
Armin Krezović08368132016-09-30 14:11:05 +02001856drm_output_destroy(struct weston_output *base)
1857{
1858 struct drm_output *output = to_drm_output(base);
1859 struct drm_backend *b = to_drm_backend(base->compositor);
Armin Krezović08368132016-09-30 14:11:05 +02001860
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001861 assert(!output->virtual);
1862
Daniel Stone31838bf2019-06-17 11:23:25 +01001863 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001864 output->destroy_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001865 weston_log("destroy output while page flip pending\n");
1866 return;
1867 }
1868
Alexandros Frantzis10937fe2021-06-14 13:09:44 +03001869 drm_output_set_cursor_view(output, NULL);
1870
Armin Krezović08368132016-09-30 14:11:05 +02001871 if (output->base.enabled)
1872 drm_output_deinit(&output->base);
1873
Pekka Paalanen383b3af2017-09-11 14:40:48 +03001874 drm_mode_list_destroy(b, &output->base.mode_list);
Armin Krezović445b41b2016-10-09 23:48:16 +02001875
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00001876 if (output->pageflip_timer)
1877 wl_event_source_remove(output->pageflip_timer);
1878
Pekka Paalanenae6d35d2017-08-16 12:07:14 +03001879 weston_output_release(&output->base);
Armin Krezović08368132016-09-30 14:11:05 +02001880
Daniel Stone7b2ddac2016-11-11 19:11:49 +00001881 assert(!output->state_last);
1882 drm_output_state_free(output->state_cur);
1883
Armin Krezović08368132016-09-30 14:11:05 +02001884 free(output);
1885}
1886
1887static int
1888drm_output_disable(struct weston_output *base)
1889{
1890 struct drm_output *output = to_drm_output(base);
Armin Krezović08368132016-09-30 14:11:05 +02001891
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09001892 assert(!output->virtual);
1893
Daniel Stone31838bf2019-06-17 11:23:25 +01001894 if (output->page_flip_pending || output->atomic_complete_pending) {
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001895 output->disable_pending = true;
Armin Krezović08368132016-09-30 14:11:05 +02001896 return -1;
1897 }
1898
Daniel Stonea08512f2016-11-08 17:46:10 +00001899 weston_log("Disabling output %s\n", output->base.name);
Daniel Stonea08512f2016-11-08 17:46:10 +00001900
Armin Krezović08368132016-09-30 14:11:05 +02001901 if (output->base.enabled)
1902 drm_output_deinit(&output->base);
1903
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01001904 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02001905
Armin Krezović08368132016-09-30 14:11:05 +02001906 return 0;
1907}
1908
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301909/*
1910 * This function converts the protection status from drm values to
1911 * weston_hdcp_protection status. The drm values as read from the connector
1912 * properties "Content Protection" and "HDCP Content Type" need to be converted
1913 * to appropriate weston values, that can be sent to a client application.
1914 */
1915static int
1916get_weston_protection_from_drm(enum wdrm_content_protection_state protection,
1917 enum wdrm_hdcp_content_type type,
1918 enum weston_hdcp_protection *weston_protection)
1919
1920{
1921 if (protection >= WDRM_CONTENT_PROTECTION__COUNT)
1922 return -1;
1923 if (protection == WDRM_CONTENT_PROTECTION_DESIRED ||
1924 protection == WDRM_CONTENT_PROTECTION_UNDESIRED) {
1925 *weston_protection = WESTON_HDCP_DISABLE;
1926 return 0;
1927 }
1928 if (type >= WDRM_HDCP_CONTENT_TYPE__COUNT)
1929 return -1;
1930 if (type == WDRM_HDCP_CONTENT_TYPE0) {
1931 *weston_protection = WESTON_HDCP_ENABLE_TYPE_0;
1932 return 0;
1933 }
1934 if (type == WDRM_HDCP_CONTENT_TYPE1) {
1935 *weston_protection = WESTON_HDCP_ENABLE_TYPE_1;
1936 return 0;
1937 }
1938 return -1;
1939}
1940
1941/**
1942 * Get current content-protection status for a given head.
1943 *
1944 * @param head drm_head, whose protection is to be retrieved
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301945 * @return protection status in case of success, -1 otherwise
1946 */
1947static enum weston_hdcp_protection
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03001948drm_head_get_current_protection(struct drm_head *head)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301949{
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03001950 drmModeObjectProperties *props = head->connector.props_drm;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301951 struct drm_property_info *info;
1952 enum wdrm_content_protection_state protection;
1953 enum wdrm_hdcp_content_type type;
1954 enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
1955
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001956 info = &head->connector.props[WDRM_CONNECTOR_CONTENT_PROTECTION];
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301957 protection = drm_property_get_value(info, props,
1958 WDRM_CONTENT_PROTECTION__COUNT);
1959
1960 if (protection == WDRM_CONTENT_PROTECTION__COUNT)
1961 return WESTON_HDCP_DISABLE;
1962
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001963 info = &head->connector.props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301964 type = drm_property_get_value(info, props,
1965 WDRM_HDCP_CONTENT_TYPE__COUNT);
1966
1967 /*
1968 * In case of platforms supporting HDCP1.4, only property
1969 * 'Content Protection' is exposed and not the 'HDCP Content Type'
1970 * for such cases HDCP Type 0 should be considered as the content-type.
1971 */
1972
1973 if (type == WDRM_HDCP_CONTENT_TYPE__COUNT)
1974 type = WDRM_HDCP_CONTENT_TYPE0;
1975
1976 if (get_weston_protection_from_drm(protection, type,
1977 &weston_hdcp) == -1) {
1978 weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
1979 protection, type, head->base.name,
Leandro Ribeiroe6369902020-06-17 11:09:47 -03001980 head->connector.connector_id);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05301981 return WESTON_HDCP_DISABLE;
1982 }
1983
1984 return weston_hdcp;
1985}
1986
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03001987static int
1988drm_connector_update_properties(struct drm_connector *connector)
1989{
1990 drmModeObjectProperties *props;
1991
1992 props = drmModeObjectGetProperties(connector->backend->drm.fd,
1993 connector->connector_id,
1994 DRM_MODE_OBJECT_CONNECTOR);
1995 if (!props) {
1996 weston_log("Error: failed to get connector properties\n");
1997 return -1;
1998 }
1999
2000 if (connector->props_drm)
2001 drmModeFreeObjectProperties(connector->props_drm);
2002 connector->props_drm = props;
2003
2004 return 0;
2005}
2006
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002007/** Replace connector data and monitor information
2008 *
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002009 * @param connector The drm_connector object to be updated.
2010 * @param conn The connector data to be owned by the drm_connector, must match
2011 * the current drm_connector ID.
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002012 * @return 0 on success, -1 on failure.
2013 *
2014 * Takes ownership of @c connector on success, not on failure.
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002015 */
2016static int
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002017drm_connector_assign_connector_info(struct drm_connector *connector,
2018 drmModeConnector *conn)
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002019{
Leandro Ribeiro70863962020-09-09 13:12:35 -03002020 assert(connector->conn != conn);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002021 assert(connector->connector_id == conn->connector_id);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002022
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002023 if (drm_connector_update_properties(connector) < 0)
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002024 return -1;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002025
Leandro Ribeiro70863962020-09-09 13:12:35 -03002026 if (connector->conn)
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002027 drmModeFreeConnector(connector->conn);
2028 connector->conn = conn;
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002029
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002030 drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
2031 drm_property_info_populate(connector->backend, connector_props,
2032 connector->props,
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002033 WDRM_CONNECTOR__COUNT, connector->props_drm);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002034 return 0;
2035}
2036
Leandro Ribeiro70863962020-09-09 13:12:35 -03002037static void
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002038drm_connector_init(struct drm_backend *b, struct drm_connector *connector,
2039 uint32_t connector_id)
2040{
2041 connector->backend = b;
2042 connector->connector_id = connector_id;
Leandro Ribeiro70863962020-09-09 13:12:35 -03002043 connector->conn = NULL;
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002044 connector->props_drm = NULL;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002045}
2046
2047static void
2048drm_connector_fini(struct drm_connector *connector)
2049{
2050 drmModeFreeConnector(connector->conn);
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002051 drmModeFreeObjectProperties(connector->props_drm);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002052 drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
2053}
2054
Pekka Paalanen456dc732017-11-09 15:10:11 +02002055static void
2056drm_head_log_info(struct drm_head *head, const char *msg)
2057{
2058 if (head->base.connected) {
2059 weston_log("DRM: head '%s' %s, connector %d is connected, "
2060 "EDID make '%s', model '%s', serial '%s'\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002061 head->base.name, msg, head->connector.connector_id,
Pekka Paalanen456dc732017-11-09 15:10:11 +02002062 head->base.make, head->base.model,
2063 head->base.serial_number ?: "");
2064 } else {
2065 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002066 head->base.name, msg, head->connector.connector_id);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002067 }
2068}
2069
Pekka Paalanend2e62422017-09-08 15:48:07 +03002070/** Update connector and monitor information
2071 *
2072 * @param head The head to update.
Leandro Ribeiro70863962020-09-09 13:12:35 -03002073 * @param conn The DRM connector object.
2074 * @returns 0 on success, -1 on failure.
Pekka Paalanend2e62422017-09-08 15:48:07 +03002075 *
Leandro Ribeiro70863962020-09-09 13:12:35 -03002076 * Updates monitor information and connection status. This may schedule a
2077 * heads changed call to the user.
Leandro Ribeiro4a5b67a2020-09-15 15:30:35 -03002078 *
2079 * Takes ownership of @c connector on success, not on failure.
Pekka Paalanend2e62422017-09-08 15:48:07 +03002080 */
Leandro Ribeiro70863962020-09-09 13:12:35 -03002081static int
2082drm_head_update_info(struct drm_head *head, drmModeConnector *conn)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002083{
Leandro Ribeiro70863962020-09-09 13:12:35 -03002084 int ret;
Pekka Paalanend2e62422017-09-08 15:48:07 +03002085
Leandro Ribeiro70863962020-09-09 13:12:35 -03002086 ret = drm_connector_assign_connector_info(&head->connector, conn);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002087
Leandro Ribeiro67941642020-09-15 00:11:02 -03002088 update_head_from_connector(head);
2089 weston_head_set_content_protection_status(&head->base,
2090 drm_head_get_current_protection(head));
2091
Pekka Paalanen456dc732017-11-09 15:10:11 +02002092 if (head->base.device_changed)
2093 drm_head_log_info(head, "updated");
Leandro Ribeiro70863962020-09-09 13:12:35 -03002094
2095 return ret;
Pekka Paalanend2e62422017-09-08 15:48:07 +03002096}
2097
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002098/** Update writeback connector
2099 *
2100 * @param writeback The writeback to update.
2101 * @param conn DRM connector object.
2102 * @returns 0 on success, -1 on failure.
2103 *
2104 * Takes ownership of @c connector on success, not on failure.
2105 */
2106static int
2107drm_writeback_update_info(struct drm_writeback *writeback, drmModeConnector *conn)
2108{
2109 int ret;
2110
2111 ret = drm_connector_assign_connector_info(&writeback->connector, conn);
2112
2113 return ret;
2114}
2115
Daniel Stone087ddf02017-02-14 17:51:30 +00002116/**
Pekka Paalanenc112f002017-08-28 16:27:20 +03002117 * Create a Weston head for a connector
2118 *
2119 * Given a DRM connector, create a matching drm_head structure and add it
2120 * to Weston's head list.
2121 *
Marius Vlada2dace22019-06-12 16:05:44 +03002122 * @param backend Weston backend structure
Leandro Ribeiro70863962020-09-09 13:12:35 -03002123 * @param conn DRM connector object
Pekka Paalanenc112f002017-08-28 16:27:20 +03002124 * @param drm_device udev device pointer
Leandro Ribeiro70863962020-09-09 13:12:35 -03002125 * @returns 0 on success, -1 on failure
Leandro Ribeiro4a5b67a2020-09-15 15:30:35 -03002126 *
2127 * Takes ownership of @c connector on success, not on failure.
Pekka Paalanenc112f002017-08-28 16:27:20 +03002128 */
Leandro Ribeiro70863962020-09-09 13:12:35 -03002129static int
2130drm_head_create(struct drm_backend *backend, drmModeConnector *conn,
Pekka Paalanenc112f002017-08-28 16:27:20 +03002131 struct udev_device *drm_device)
2132{
2133 struct drm_head *head;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002134 char *name;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002135 int ret;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002136
2137 head = zalloc(sizeof *head);
2138 if (!head)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002139 return -1;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002140
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002141 head->backend = backend;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002142
Leandro Ribeiro70863962020-09-09 13:12:35 -03002143 drm_connector_init(backend, &head->connector, conn->connector_id);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002144
2145 name = make_connector_name(conn);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002146 if (!name)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002147 goto err;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002148
2149 weston_head_init(&head->base, name);
2150 free(name);
2151
Leandro Ribeiro67941642020-09-15 00:11:02 -03002152 ret = drm_head_update_info(head, conn);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002153 if (ret < 0)
Leandro Ribeiro67941642020-09-15 00:11:02 -03002154 goto err_update;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002155
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002156 head->backlight = backlight_init(drm_device, conn->connector_type);
Pekka Paalanence724242017-09-04 12:21:24 +03002157
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002158 if (conn->connector_type == DRM_MODE_CONNECTOR_LVDS ||
2159 conn->connector_type == DRM_MODE_CONNECTOR_eDP)
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002160 weston_head_set_internal(&head->base);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002161
Pekka Paalanen9c03a7c2017-11-28 14:30:10 +02002162 if (drm_head_read_current_setup(head, backend) < 0) {
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002163 weston_log("Failed to retrieve current mode from connector %d.\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002164 head->connector.connector_id);
Pekka Paalanen6fae2be2017-11-28 14:33:52 +02002165 /* Not fatal. */
Pekka Paalanen13d233e2017-09-11 14:06:11 +03002166 }
2167
Pekka Paalanenc112f002017-08-28 16:27:20 +03002168 weston_compositor_add_head(backend->compositor, &head->base);
Pekka Paalanen456dc732017-11-09 15:10:11 +02002169 drm_head_log_info(head, "found");
Pekka Paalanenc112f002017-08-28 16:27:20 +03002170
Leandro Ribeiro70863962020-09-09 13:12:35 -03002171 return 0;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002172
Leandro Ribeiro67941642020-09-15 00:11:02 -03002173err_update:
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002174 weston_head_release(&head->base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002175err:
Leandro Ribeiro70863962020-09-09 13:12:35 -03002176 drm_connector_fini(&head->connector);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002177 free(head);
Leandro Ribeiro70863962020-09-09 13:12:35 -03002178 return -1;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002179}
2180
2181static void
2182drm_head_destroy(struct drm_head *head)
2183{
2184 weston_head_release(&head->base);
Pekka Paalanence724242017-09-04 12:21:24 +03002185
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002186 drm_connector_fini(&head->connector);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002187
Pekka Paalanence724242017-09-04 12:21:24 +03002188 if (head->backlight)
2189 backlight_destroy(head->backlight);
2190
Pekka Paalanenc112f002017-08-28 16:27:20 +03002191 free(head);
2192}
2193
2194/**
Armin Krezović08368132016-09-30 14:11:05 +02002195 * Create a Weston output structure
2196 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002197 * Create an "empty" drm_output. This is the implementation of
2198 * weston_backend::create_output.
Armin Krezović08368132016-09-30 14:11:05 +02002199 *
Pekka Paalanend2e62422017-09-08 15:48:07 +03002200 * Creating an output is usually followed by drm_output_attach_head()
2201 * and drm_output_enable() to make use of it.
2202 *
2203 * @param compositor The compositor instance.
2204 * @param name Name for the new output.
2205 * @returns The output, or NULL on failure.
Armin Krezović08368132016-09-30 14:11:05 +02002206 */
Pekka Paalanend2e62422017-09-08 15:48:07 +03002207static struct weston_output *
2208drm_output_create(struct weston_compositor *compositor, const char *name)
Armin Krezović08368132016-09-30 14:11:05 +02002209{
Pekka Paalanend2e62422017-09-08 15:48:07 +03002210 struct drm_backend *b = to_drm_backend(compositor);
Armin Krezović08368132016-09-30 14:11:05 +02002211 struct drm_output *output;
Armin Krezović08368132016-09-30 14:11:05 +02002212
Armin Krezović08368132016-09-30 14:11:05 +02002213 output = zalloc(sizeof *output);
2214 if (output == NULL)
Pekka Paalanend2e62422017-09-08 15:48:07 +03002215 return NULL;
Armin Krezović08368132016-09-30 14:11:05 +02002216
Daniel Stone64dbbee2018-07-20 19:00:06 +01002217 output->backend = b;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002218 output->crtc = NULL;
2219
Stefan Agnerccf24072019-07-09 22:02:00 +02002220#ifdef BUILD_DRM_GBM
Tomohito Esaki718a40b2018-01-31 17:50:15 +09002221 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
Stefan Agnerccf24072019-07-09 22:02:00 +02002222#endif
Daniel Stone64dbbee2018-07-20 19:00:06 +01002223
Pekka Paalanend2e62422017-09-08 15:48:07 +03002224 weston_output_init(&output->base, compositor, name);
Pekka Paalanenc1e89ba2017-08-31 16:18:48 +03002225
Armin Krezović08368132016-09-30 14:11:05 +02002226 output->base.enable = drm_output_enable;
2227 output->base.destroy = drm_output_destroy;
2228 output->base.disable = drm_output_disable;
Pekka Paalanenc112f002017-08-28 16:27:20 +03002229 output->base.attach_head = drm_output_attach_head;
Pekka Paalanen7f853792017-11-29 14:33:33 +02002230 output->base.detach_head = drm_output_detach_head;
Armin Krezović08368132016-09-30 14:11:05 +02002231
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002232 output->destroy_pending = false;
2233 output->disable_pending = false;
Armin Krezović08368132016-09-30 14:11:05 +02002234
Pekka Paalanen01f60212017-03-24 15:39:24 +02002235 output->state_cur = drm_output_state_alloc(output, NULL);
Pekka Paalanena0bfedc2017-04-03 14:42:51 +03002236
Armin Krezović08368132016-09-30 14:11:05 +02002237 weston_compositor_add_pending_output(&output->base, b->compositor);
2238
Pekka Paalanend2e62422017-09-08 15:48:07 +03002239 return &output->base;
Armin Krezović08368132016-09-30 14:11:05 +02002240}
2241
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002242/**
2243 * Create a Weston writeback for a writeback connector
Leandro Ribeiro72430222020-09-14 17:41:41 -03002244 *
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002245 * Given a DRM connector of type writeback, create a matching drm_writeback
2246 * structure and add it to Weston's writeback list.
2247 *
2248 * @param b Weston backend structure
2249 * @param conn DRM connector object of type writeback
2250 * @returns 0 on success, -1 on failure
2251 *
2252 * Takes ownership of @c connector on success, not on failure.
2253 */
2254static int
2255drm_writeback_create(struct drm_backend *b, drmModeConnector *conn)
2256{
2257 struct drm_writeback *writeback;
2258 int ret;
2259
2260 writeback = zalloc(sizeof *writeback);
2261 assert(writeback);
2262
2263 writeback->backend = b;
2264
2265 drm_connector_init(b, &writeback->connector, conn->connector_id);
2266
2267 ret = drm_writeback_update_info(writeback, conn);
2268 if (ret < 0)
2269 goto err;
2270
2271 wl_list_insert(&b->writeback_connector_list, &writeback->link);
2272 return 0;
2273
2274err:
2275 drm_connector_fini(&writeback->connector);
2276 free(writeback);
2277 return -1;
2278}
2279
2280static void
2281drm_writeback_destroy(struct drm_writeback *writeback)
2282{
2283 drm_connector_fini(&writeback->connector);
2284 wl_list_remove(&writeback->link);
2285
2286 free(writeback);
2287}
2288
2289/** Given the DRM connector object of a connector, create drm_head or
2290 * drm_writeback object (depending on the type of connector) for it.
2291 *
2292 * The object is then added to the DRM-backend list of heads or writebacks.
Leandro Ribeiro72430222020-09-14 17:41:41 -03002293 *
2294 * @param b The DRM-backend structure
2295 * @param conn The DRM connector object
2296 * @param drm_device udev device pointer
2297 * @return 0 on success, -1 on failure
2298 */
2299static int
2300drm_backend_add_connector(struct drm_backend *b, drmModeConnector *conn,
2301 struct udev_device *drm_device)
2302{
2303 int ret;
2304
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002305 if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) {
2306 ret = drm_writeback_create(b, conn);
2307 if (ret < 0)
2308 weston_log("DRM: failed to create writeback for connector %d.\n",
2309 conn->connector_id);
2310 } else {
2311 ret = drm_head_create(b, conn, drm_device);
2312 if (ret < 0)
2313 weston_log("DRM: failed to create head for connector %d.\n",
2314 conn->connector_id);
2315 }
Leandro Ribeiro72430222020-09-14 17:41:41 -03002316
2317 return ret;
2318}
2319
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002320/** Find all connectors of the fd and create drm_head or drm_writeback objects
2321 * (depending on the type of connector they are) for each of them
2322 *
2323 * These objects are added to the DRM-backend lists of heads and writebacks.
2324 *
2325 * @param b The DRM-backend structure
2326 * @param drm_device udev device pointer
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03002327 * @param resources The DRM resources, it is taken with drmModeGetResources
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002328 * @return 0 on success, -1 on failure
2329 */
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002330static int
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03002331drm_backend_discover_connectors(struct drm_backend *b, struct udev_device *drm_device,
2332 drmModeRes *resources)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002333{
Leandro Ribeiro70863962020-09-09 13:12:35 -03002334 drmModeConnector *conn;
2335 int i, ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002336
Giulio Camuffo954f1832014-10-11 18:27:30 +03002337 b->min_width = resources->min_width;
2338 b->max_width = resources->max_width;
2339 b->min_height = resources->min_height;
2340 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002341
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002342 for (i = 0; i < resources->count_connectors; i++) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03002343 uint32_t connector_id = resources->connectors[i];
Daniel Stone02cf4662017-03-03 16:19:39 +00002344
Leandro Ribeiro70863962020-09-09 13:12:35 -03002345 conn = drmModeGetConnector(b->drm.fd, connector_id);
2346 if (!conn)
2347 continue;
2348
Leandro Ribeiro72430222020-09-14 17:41:41 -03002349 ret = drm_backend_add_connector(b, conn, drm_device);
2350 if (ret < 0)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002351 drmModeFreeConnector(conn);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002352 }
2353
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002354 return 0;
2355}
2356
Leandro Ribeiro99611c82020-09-14 17:19:12 -03002357static bool
2358resources_has_connector(drmModeRes *resources, uint32_t connector_id)
2359{
2360 for (int i = 0; i < resources->count_connectors; i++) {
2361 if (resources->connectors[i] == connector_id)
2362 return true;
2363 }
2364
2365 return false;
2366}
2367
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002368static void
Leandro Ribeiro993920d2020-09-14 17:01:01 -03002369drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002370{
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002371 drmModeRes *resources;
Leandro Ribeiro70863962020-09-09 13:12:35 -03002372 drmModeConnector *conn;
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002373 struct weston_head *base, *base_next;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002374 struct drm_head *head;
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002375 struct drm_writeback *writeback, *writeback_next;
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002376 uint32_t connector_id;
Leandro Ribeiro70863962020-09-09 13:12:35 -03002377 int i, ret;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002378
Giulio Camuffo954f1832014-10-11 18:27:30 +03002379 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002380 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002381 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002382 return;
2383 }
2384
Pekka Paalanend2e62422017-09-08 15:48:07 +03002385 /* collect new connectors that have appeared, e.g. MST */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002386 for (i = 0; i < resources->count_connectors; i++) {
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002387 connector_id = resources->connectors[i];
Benjamin Franzke117483d2011-08-30 11:38:26 +02002388
Leandro Ribeiro70863962020-09-09 13:12:35 -03002389 conn = drmModeGetConnector(b->drm.fd, connector_id);
2390 if (!conn)
2391 continue;
2392
Pekka Paalanend2e62422017-09-08 15:48:07 +03002393 head = drm_head_find_by_connector(b, connector_id);
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002394 writeback = drm_writeback_find_by_connector(b, connector_id);
2395
2396 /* Connector can't be owned by both a head and a writeback, so
2397 * one of the searches must fail. */
2398 assert(head == NULL || writeback == NULL);
2399
Leandro Ribeiro72430222020-09-14 17:41:41 -03002400 if (head)
Leandro Ribeiro70863962020-09-09 13:12:35 -03002401 ret = drm_head_update_info(head, conn);
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002402 else if (writeback)
2403 ret = drm_writeback_update_info(writeback, conn);
Leandro Ribeiro72430222020-09-14 17:41:41 -03002404 else
2405 ret = drm_backend_add_connector(b, conn, drm_device);
2406
2407 if (ret < 0)
2408 drmModeFreeConnector(conn);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002409 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002410
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002411 /* Destroy head objects of connectors (except writeback connectors) that
2412 * have disappeared. */
2413 wl_list_for_each_safe(base, base_next,
Pekka Paalanena0a37462017-08-31 15:41:57 +03002414 &b->compositor->head_list, compositor_link) {
Pekka Paalanena0a37462017-08-31 15:41:57 +03002415 head = to_drm_head(base);
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002416 connector_id = head->connector.connector_id;
Pekka Paalanena0a37462017-08-31 15:41:57 +03002417
Leandro Ribeiro99611c82020-09-14 17:19:12 -03002418 if (resources_has_connector(resources, connector_id))
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002419 continue;
2420
Pekka Paalanend2e62422017-09-08 15:48:07 +03002421 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002422 head->base.name, connector_id);
Pekka Paalanend2e62422017-09-08 15:48:07 +03002423 drm_head_destroy(head);
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002424 }
2425
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002426 /* Destroy writeback objects of writeback connectors that have
2427 * disappeared. */
2428 wl_list_for_each_safe(writeback, writeback_next,
2429 &b->writeback_connector_list, link) {
2430 connector_id = writeback->connector.connector_id;
2431
2432 if (resources_has_connector(resources, connector_id))
2433 continue;
2434
2435 weston_log("DRM: writeback connector (connector %d) disappeared.\n",
2436 connector_id);
2437 drm_writeback_destroy(writeback);
2438 }
2439
Daniel Stoneefc2b1d2017-02-09 14:06:31 +00002440 drmModeFreeResources(resources);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002441}
2442
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302443static enum wdrm_connector_property
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002444drm_connector_find_property_by_id(struct drm_connector *connector,
2445 uint32_t property_id)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302446{
2447 int i;
2448 enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
2449
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002450 if (!connector || !property_id)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302451 return WDRM_CONNECTOR__COUNT;
2452
2453 for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002454 if (connector->props[i].prop_id == property_id) {
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302455 prop = (enum wdrm_connector_property) i;
2456 break;
2457 }
2458 return prop;
2459}
2460
2461static void
2462drm_backend_update_conn_props(struct drm_backend *b,
2463 uint32_t connector_id,
2464 uint32_t property_id)
2465{
2466 struct drm_head *head;
2467 enum wdrm_connector_property conn_prop;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302468
2469 head = drm_head_find_by_connector(b, connector_id);
2470 if (!head) {
2471 weston_log("DRM: failed to find head for connector id: %d.\n",
2472 connector_id);
2473 return;
2474 }
2475
Leandro Ribeiroe6369902020-06-17 11:09:47 -03002476 conn_prop = drm_connector_find_property_by_id(&head->connector, property_id);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302477 if (conn_prop >= WDRM_CONNECTOR__COUNT)
2478 return;
2479
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002480 if (drm_connector_update_properties(&head->connector) < 0)
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302481 return;
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002482
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302483 if (conn_prop == WDRM_CONNECTOR_CONTENT_PROTECTION) {
2484 weston_head_set_content_protection_status(&head->base,
Leandro Ribeiro702fbf72020-08-18 17:35:05 -03002485 drm_head_get_current_protection(head));
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302486 }
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302487}
2488
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002489static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002490udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002491{
David Herrmannd7488c22012-03-11 20:05:21 +01002492 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002493 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002494
2495 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002496 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002497 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002498
David Herrmann6ac52db2012-03-11 20:05:22 +01002499 val = udev_device_get_property_value(device, "HOTPLUG");
2500 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002501 return 0;
2502
David Herrmann6ac52db2012-03-11 20:05:22 +01002503 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002504}
2505
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002506static int
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302507udev_event_is_conn_prop_change(struct drm_backend *b,
2508 struct udev_device *device,
2509 uint32_t *connector_id,
2510 uint32_t *property_id)
2511
2512{
2513 const char *val;
2514 int id;
2515
2516 val = udev_device_get_property_value(device, "CONNECTOR");
2517 if (!val || !safe_strtoint(val, &id))
2518 return 0;
2519 else
2520 *connector_id = id;
2521
2522 val = udev_device_get_property_value(device, "PROPERTY");
2523 if (!val || !safe_strtoint(val, &id))
2524 return 0;
2525 else
2526 *property_id = id;
2527
2528 return 1;
2529}
2530
2531static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002532udev_drm_event(int fd, uint32_t mask, void *data)
2533{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002534 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002535 struct udev_device *event;
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302536 uint32_t conn_id, prop_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002537
Giulio Camuffo954f1832014-10-11 18:27:30 +03002538 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002539
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302540 if (udev_event_is_hotplug(b, event)) {
2541 if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
2542 drm_backend_update_conn_props(b, conn_id, prop_id);
2543 else
Leandro Ribeiro993920d2020-09-14 17:01:01 -03002544 drm_backend_update_connectors(b, event);
Ankit Nautiyala344fe32019-05-14 18:36:08 +05302545 }
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002546
2547 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002548
2549 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002550}
2551
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002552static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002553drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002554{
Armin Krezović545dba62016-08-05 15:54:18 +02002555 struct drm_backend *b = to_drm_backend(ec);
Pekka Paalanenc112f002017-08-28 16:27:20 +03002556 struct weston_head *base, *next;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002557 struct drm_crtc *crtc, *crtc_tmp;
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002558 struct drm_writeback *writeback, *writeback_tmp;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002559
Giulio Camuffo954f1832014-10-11 18:27:30 +03002560 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002561
Giulio Camuffo954f1832014-10-11 18:27:30 +03002562 wl_event_source_remove(b->udev_drm_source);
2563 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002564
Daniel Stoneb57c6a02017-10-05 16:27:21 +01002565 b->shutting_down = true;
2566
Giulio Camuffo954f1832014-10-11 18:27:30 +03002567 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002568
Leandro Ribeirof0149642019-12-18 15:52:18 -03002569 weston_log_scope_destroy(b->debug);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01002570 b->debug = NULL;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002571 weston_compositor_shutdown(ec);
2572
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002573 wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link)
2574 drm_crtc_destroy(crtc);
2575
Pekka Paalanenc112f002017-08-28 16:27:20 +03002576 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
2577 drm_head_destroy(to_drm_head(base));
2578
Leandro Ribeiro96bef052020-09-09 15:23:49 -03002579 wl_list_for_each_safe(writeback, writeback_tmp,
2580 &b->writeback_connector_list, link)
2581 drm_writeback_destroy(writeback);
2582
Stefan Agnerccf24072019-07-09 22:02:00 +02002583#ifdef BUILD_DRM_GBM
Giulio Camuffo954f1832014-10-11 18:27:30 +03002584 if (b->gbm)
2585 gbm_device_destroy(b->gbm);
Stefan Agnerccf24072019-07-09 22:02:00 +02002586#endif
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002587
Pekka Paalanen5b0aa552017-12-07 16:06:05 +02002588 udev_monitor_unref(b->udev_monitor);
Pekka Paalanen2a0c6c32017-09-13 16:48:01 +03002589 udev_unref(b->udev);
2590
Marius Vlad7a44ee72021-06-23 16:02:35 +03002591 weston_launcher_close(ec->launcher, b->drm.fd);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002592 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002593
Pekka Paalanen9bf4f372017-12-07 16:05:29 +02002594 free(b->drm.filename);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002595 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002596}
2597
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002598static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002599session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002600{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002601 struct weston_compositor *compositor = data;
Armin Krezović545dba62016-08-05 15:54:18 +02002602 struct drm_backend *b = to_drm_backend(compositor);
Daniel Stone085d2b92015-05-21 00:00:57 +01002603 struct drm_plane *plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002604 struct drm_output *output;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002605 struct drm_crtc *crtc;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002606
Giulio Camuffo954f1832014-10-11 18:27:30 +03002607 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002608 weston_log("activating session\n");
Daniel Stonef33e1042016-11-05 08:10:13 +00002609 weston_compositor_wake(compositor);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002610 weston_compositor_damage_all(compositor);
Daniel Stone6020f472018-02-05 15:46:20 +00002611 b->state_invalid = true;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002612 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002613 } else {
2614 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002615 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002616
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002617 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002618
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002619 /* If we have a repaint scheduled (either from a
2620 * pending pageflip or the idle handler), make sure we
2621 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002622 * vt switched away. The OFFSCREEN state will prevent
Abdur Rehman4dca0e12017-01-01 19:46:35 +05002623 * further attempts at repainting. When we switch
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002624 * back, we schedule a repaint, which will process
2625 * pending frame callbacks. */
2626
Giulio Camuffo954f1832014-10-11 18:27:30 +03002627 wl_list_for_each(output, &compositor->output_list, base.link) {
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002628 crtc = output->crtc;
Daniel Stone09a97e22017-03-01 11:34:06 +00002629 output->base.repaint_needed = false;
Daniel Stone2ba17f42015-05-19 20:02:41 +01002630 if (output->cursor_plane)
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002631 drmModeSetCursor(b->drm.fd, crtc->crtc_id,
Daniel Stone2ba17f42015-05-19 20:02:41 +01002632 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002633 }
2634
Giulio Camuffo954f1832014-10-11 18:27:30 +03002635 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002636 struct drm_output, base.link);
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002637 crtc = output->crtc;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002638
Daniel Stone085d2b92015-05-21 00:00:57 +01002639 wl_list_for_each(plane, &b->plane_list, link) {
2640 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
2641 continue;
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03002642 drmModeSetPlane(b->drm.fd, plane->plane_id, crtc->crtc_id,
2643 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Daniel Stone085d2b92015-05-21 00:00:57 +01002644 }
2645 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002646}
2647
Robert Beckett8d23ab72019-06-13 16:55:44 +01002648
2649/**
2650 * Handle KMS GPU being added/removed
2651 *
2652 * If the device being added/removed is the KMS device, we activate/deactivate
2653 * the compositor session.
2654 *
2655 * @param compositor The compositor instance.
2656 * @param device The device being added/removed.
2657 * @param added Whether the device is being added (or removed)
2658 */
2659static void
2660drm_device_changed(struct weston_compositor *compositor,
2661 dev_t device, bool added)
2662{
2663 struct drm_backend *b = to_drm_backend(compositor);
2664
Robert Beckett49dc3202019-07-02 16:31:22 +01002665 if (b->drm.fd < 0 || b->drm.devnum != device ||
2666 compositor->session_active == added)
Robert Beckett8d23ab72019-06-13 16:55:44 +01002667 return;
2668
2669 compositor->session_active = added;
2670 wl_signal_emit(&compositor->session_signal, compositor);
2671}
2672
Daniel Stoneefa504f2016-12-19 16:48:20 +00002673/**
2674 * Determines whether or not a device is capable of modesetting. If successful,
2675 * sets b->drm.fd and b->drm.filename to the opened device.
2676 */
2677static bool
2678drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
2679{
2680 const char *filename = udev_device_get_devnode(device);
2681 const char *sysnum = udev_device_get_sysnum(device);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002682 dev_t devnum = udev_device_get_devnum(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002683 drmModeRes *res;
Marius Vlad7d070ca2018-11-23 14:02:07 +02002684 int id = -1, fd;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002685
2686 if (!filename)
2687 return false;
2688
2689 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
2690 if (fd < 0)
2691 return false;
2692
2693 res = drmModeGetResources(fd);
2694 if (!res)
2695 goto out_fd;
2696
2697 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
2698 res->count_encoders <= 0)
2699 goto out_res;
2700
2701 if (sysnum)
2702 id = atoi(sysnum);
2703 if (!sysnum || id < 0) {
2704 weston_log("couldn't get sysnum for device %s\n", filename);
2705 goto out_res;
2706 }
2707
2708 /* We can be called successfully on multiple devices; if we have,
2709 * clean up old entries. */
2710 if (b->drm.fd >= 0)
2711 weston_launcher_close(b->compositor->launcher, b->drm.fd);
2712 free(b->drm.filename);
2713
2714 b->drm.fd = fd;
2715 b->drm.id = id;
2716 b->drm.filename = strdup(filename);
Robert Beckett8d23ab72019-06-13 16:55:44 +01002717 b->drm.devnum = devnum;
Daniel Stoneefa504f2016-12-19 16:48:20 +00002718
Sergi Granellceb59812017-03-28 12:44:04 +02002719 drmModeFreeResources(res);
2720
Daniel Stoneefa504f2016-12-19 16:48:20 +00002721 return true;
2722
2723out_res:
2724 drmModeFreeResources(res);
2725out_fd:
2726 weston_launcher_close(b->compositor->launcher, fd);
2727 return false;
2728}
2729
David Herrmann0af066f2012-10-29 19:21:16 +01002730/*
2731 * Find primary GPU
2732 * Some systems may have multiple DRM devices attached to a single seat. This
2733 * function loops over all devices and tries to find a PCI device with the
2734 * boot_vga sysfs attribute set to 1.
2735 * If no such device is found, the first DRM device reported by udev is used.
Daniel Stoneefa504f2016-12-19 16:48:20 +00002736 * Devices are also vetted to make sure they are are capable of modesetting,
2737 * rather than pure render nodes (GPU with no display), or pure
2738 * memory-allocation devices (VGEM).
David Herrmann0af066f2012-10-29 19:21:16 +01002739 */
2740static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002741find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002742{
2743 struct udev_enumerate *e;
2744 struct udev_list_entry *entry;
2745 const char *path, *device_seat, *id;
2746 struct udev_device *device, *drm_device, *pci;
2747
Giulio Camuffo954f1832014-10-11 18:27:30 +03002748 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002749 udev_enumerate_add_match_subsystem(e, "drm");
2750 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2751
2752 udev_enumerate_scan_devices(e);
2753 drm_device = NULL;
2754 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Daniel Stoneefa504f2016-12-19 16:48:20 +00002755 bool is_boot_vga = false;
2756
David Herrmann0af066f2012-10-29 19:21:16 +01002757 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002758 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002759 if (!device)
2760 continue;
2761 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2762 if (!device_seat)
2763 device_seat = default_seat;
2764 if (strcmp(device_seat, seat)) {
2765 udev_device_unref(device);
2766 continue;
2767 }
2768
2769 pci = udev_device_get_parent_with_subsystem_devtype(device,
2770 "pci", NULL);
2771 if (pci) {
2772 id = udev_device_get_sysattr_value(pci, "boot_vga");
Daniel Stoneefa504f2016-12-19 16:48:20 +00002773 if (id && !strcmp(id, "1"))
2774 is_boot_vga = true;
David Herrmann0af066f2012-10-29 19:21:16 +01002775 }
2776
Daniel Stoneefa504f2016-12-19 16:48:20 +00002777 /* If we already have a modesetting-capable device, and this
2778 * device isn't our boot-VGA device, we aren't going to use
2779 * it. */
2780 if (!is_boot_vga && drm_device) {
David Herrmann0af066f2012-10-29 19:21:16 +01002781 udev_device_unref(device);
Daniel Stoneefa504f2016-12-19 16:48:20 +00002782 continue;
2783 }
2784
2785 /* Make sure this device is actually capable of modesetting;
2786 * if this call succeeds, b->drm.{fd,filename} will be set,
2787 * and any old values freed. */
2788 if (!drm_device_is_kms(b, device)) {
2789 udev_device_unref(device);
2790 continue;
2791 }
2792
2793 /* There can only be one boot_vga device, and we try to use it
2794 * at all costs. */
2795 if (is_boot_vga) {
2796 if (drm_device)
2797 udev_device_unref(drm_device);
2798 drm_device = device;
2799 break;
2800 }
2801
2802 /* Per the (!is_boot_vga && drm_device) test above, we only
2803 * trump existing saved devices with boot-VGA devices, so if
2804 * we end up here, this must be the first device we've seen. */
2805 assert(!drm_device);
2806 drm_device = device;
David Herrmann0af066f2012-10-29 19:21:16 +01002807 }
2808
Daniel Stoneefa504f2016-12-19 16:48:20 +00002809 /* If we're returning a device to use, we must have an open FD for
2810 * it. */
2811 assert(!!drm_device == (b->drm.fd >= 0));
2812
David Herrmann0af066f2012-10-29 19:21:16 +01002813 udev_enumerate_unref(e);
2814 return drm_device;
2815}
2816
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03002817static struct udev_device *
2818open_specific_drm_device(struct drm_backend *b, const char *name)
2819{
2820 struct udev_device *device;
2821
2822 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
2823 if (!device) {
2824 weston_log("ERROR: could not open DRM device '%s'\n", name);
2825 return NULL;
2826 }
2827
2828 if (!drm_device_is_kms(b, device)) {
2829 udev_device_unref(device);
2830 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
2831 return NULL;
2832 }
2833
2834 /* If we're returning a device to use, we must have an open FD for
2835 * it. */
2836 assert(b->drm.fd >= 0);
2837
2838 return device;
2839}
2840
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002841static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002842planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2843 uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002844{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002845 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002846
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002847 switch (key) {
2848 case KEY_C:
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002849 b->cursors_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002850 break;
2851 case KEY_V:
Daniel Stone87fab1c2019-06-17 11:13:20 +01002852 /* We don't support overlay-plane usage with legacy KMS. */
2853 if (b->atomic_modeset)
Emmanuel Gil Peyrot1b3ad092019-12-09 02:50:55 +01002854 b->sprites_are_broken ^= true;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002855 break;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002856 default:
2857 break;
2858 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002859}
2860
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002861#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002862static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002863recorder_destroy(struct drm_output *output)
2864{
2865 vaapi_recorder_destroy(output->recorder);
2866 output->recorder = NULL;
2867
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302868 weston_output_disable_planes_decr(&output->base);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002869
2870 wl_list_remove(&output->recorder_frame_listener.link);
2871 weston_log("[libva recorder] done\n");
2872}
2873
2874static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002875recorder_frame_notify(struct wl_listener *listener, void *data)
2876{
2877 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002878 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002879 int fd, ret;
2880
2881 output = container_of(listener, struct drm_output,
2882 recorder_frame_listener);
Armin Krezović545dba62016-08-05 15:54:18 +02002883 b = to_drm_backend(output->base.compositor);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002884
2885 if (!output->recorder)
2886 return;
2887
Daniel Stonee2e80132018-01-16 15:37:33 +00002888 ret = drmPrimeHandleToFD(b->drm.fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002889 output->scanout_plane->state_cur->fb->handles[0],
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002890 DRM_CLOEXEC, &fd);
2891 if (ret) {
2892 weston_log("[libva recorder] "
2893 "failed to create prime fd for front buffer\n");
2894 return;
2895 }
2896
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002897 ret = vaapi_recorder_frame(output->recorder, fd,
Daniel Stone8eece0c2016-11-17 17:54:00 +00002898 output->scanout_plane->state_cur->fb->strides[0]);
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002899 if (ret < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +02002900 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002901 recorder_destroy(output);
2902 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002903}
2904
2905static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002906create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002907 const char *filename)
2908{
2909 int fd;
2910 drm_magic_t magic;
2911
Giulio Camuffo954f1832014-10-11 18:27:30 +03002912 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002913 if (fd < 0)
2914 return NULL;
2915
2916 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002917 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002918
2919 return vaapi_recorder_create(fd, width, height, filename);
2920}
2921
2922static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002923recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2924 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002925{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002926 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002927 struct drm_output *output;
2928 int width, height;
2929
Giulio Camuffo954f1832014-10-11 18:27:30 +03002930 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002931 struct drm_output, base.link);
2932
2933 if (!output->recorder) {
Stefan Agner4a18f302019-10-20 18:25:42 +02002934 if (output->gbm_format != DRM_FORMAT_XRGB8888) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002935 weston_log("failed to start vaapi recorder: "
2936 "output format not supported\n");
2937 return;
2938 }
2939
Hardeningff39efa2013-09-18 23:56:35 +02002940 width = output->base.current_mode->width;
2941 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002942
2943 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002944 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002945 if (!output->recorder) {
2946 weston_log("failed to create vaapi recorder\n");
2947 return;
2948 }
2949
Ankit Nautiyal93dde242019-07-08 11:46:42 +05302950 weston_output_disable_planes_incr(&output->base);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002951
2952 output->recorder_frame_listener.notify = recorder_frame_notify;
2953 wl_signal_add(&output->base.frame_signal,
2954 &output->recorder_frame_listener);
2955
2956 weston_output_schedule_repaint(&output->base);
2957
2958 weston_log("[libva recorder] initialized\n");
2959 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002960 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002961 }
2962}
2963#else
2964static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +02002965recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2966 uint32_t key, void *data)
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002967{
2968 weston_log("Compiled without libva support\n");
2969}
2970#endif
2971
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002972
Armin Krezović08368132016-09-30 14:11:05 +02002973static const struct weston_drm_output_api api = {
2974 drm_output_set_mode,
2975 drm_output_set_gbm_format,
2976 drm_output_set_seat,
2977};
2978
Giulio Camuffo954f1832014-10-11 18:27:30 +03002979static struct drm_backend *
2980drm_backend_create(struct weston_compositor *compositor,
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002981 struct weston_drm_backend_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002982{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002983 struct drm_backend *b;
David Herrmann0af066f2012-10-29 19:21:16 +01002984 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002985 struct wl_event_loop *loop;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07002986 const char *seat_id = default_seat;
nerdopolisb16c4ac2018-06-29 08:17:46 -04002987 const char *session_seat;
Leandro Ribeiro54293022021-10-12 14:48:36 -03002988 struct weston_drm_format_array *scanout_formats;
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03002989 drmModeRes *res;
Armin Krezović08368132016-09-30 14:11:05 +02002990 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002991
nerdopolisb16c4ac2018-06-29 08:17:46 -04002992 session_seat = getenv("XDG_SEAT");
2993 if (session_seat)
2994 seat_id = session_seat;
2995
2996 if (config->seat_id)
2997 seat_id = config->seat_id;
2998
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002999 weston_log("initializing drm backend\n");
3000
Giulio Camuffo954f1832014-10-11 18:27:30 +03003001 b = zalloc(sizeof *b);
3002 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003003 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01003004
Daniel Stone6020f472018-02-05 15:46:20 +00003005 b->state_invalid = true;
Daniel Stoneefa504f2016-12-19 16:48:20 +00003006 b->drm.fd = -1;
3007
Giulio Camuffo954f1832014-10-11 18:27:30 +03003008 b->compositor = compositor;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003009 b->use_pixman = config->use_pixman;
Emmanuel Gil Peyrot11ae2a32017-03-07 13:27:54 +00003010 b->pageflip_timeout = config->pageflip_timeout;
Pekka Paalanendee412d2018-04-23 11:44:58 +02003011 b->use_pixman_shadow = config->use_pixman_shadow;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003012
Leandro Ribeiro172afc22019-12-26 16:23:43 -03003013 b->debug = weston_compositor_add_log_scope(compositor, "drm-backend",
3014 "Debug messages from DRM/KMS backend\n",
3015 NULL, NULL, NULL);
Daniel Stone1cbe1f92018-07-20 10:21:28 +01003016
Pekka Paalanen7da9a382017-08-30 11:29:49 +03003017 compositor->backend = &b->base;
3018
Stefan Agner0bfebeb2019-07-08 00:30:44 +02003019 if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003020 goto err_compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003021
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003022 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003023 compositor->launcher = weston_launcher_connect(compositor, config->tty,
3024 seat_id, true);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003025 if (compositor->launcher == NULL) {
Pekka Paalanena453f4d2017-10-31 10:19:48 +02003026 weston_log("fatal: drm backend should be run using "
3027 "weston-launch binary, or your system should "
3028 "provide the logind D-Bus API.\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003029 goto err_compositor;
3030 }
3031
Giulio Camuffo954f1832014-10-11 18:27:30 +03003032 b->udev = udev_new();
3033 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003034 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003035 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003036 }
3037
Giulio Camuffo954f1832014-10-11 18:27:30 +03003038 b->session_listener.notify = session_notify;
3039 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003040
Pekka Paalanenb45ed8b2017-03-28 18:04:27 +03003041 if (config->specific_device)
3042 drm_device = open_specific_drm_device(b, config->specific_device);
3043 else
3044 drm_device = find_primary_gpu(b, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003045 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003046 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003047 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003048 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003049
Daniel Stoneefa504f2016-12-19 16:48:20 +00003050 if (init_kms_caps(b) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003051 weston_log("failed to initialize kms\n");
3052 goto err_udev_dev;
3053 }
3054
Giulio Camuffo954f1832014-10-11 18:27:30 +03003055 if (b->use_pixman) {
3056 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003057 weston_log("failed to initialize pixman renderer\n");
3058 goto err_udev_dev;
3059 }
3060 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003061 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003062 weston_log("failed to initialize egl\n");
3063 goto err_udev_dev;
3064 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003065 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003066
Giulio Camuffo954f1832014-10-11 18:27:30 +03003067 b->base.destroy = drm_destroy;
Daniel Stoneeedf84c2017-02-10 18:06:04 +00003068 b->base.repaint_begin = drm_repaint_begin;
3069 b->base.repaint_flush = drm_repaint_flush;
3070 b->base.repaint_cancel = drm_repaint_cancel;
Pekka Paalanenc112f002017-08-28 16:27:20 +03003071 b->base.create_output = drm_output_create;
Robert Beckett8d23ab72019-06-13 16:55:44 +01003072 b->base.device_changed = drm_device_changed;
Marius Vlad81bada52019-11-11 00:27:17 +02003073 b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003074
Bob Ham91880f12016-01-12 10:21:47 +00003075 weston_setup_vt_switch_bindings(compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003076
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003077 res = drmModeGetResources(b->drm.fd);
3078 if (!res) {
3079 weston_log("Failed to get drmModeRes\n");
Leandro Ribeirob00d1a22020-08-13 14:12:28 -03003080 goto err_udev_dev;
3081 }
3082
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003083 wl_list_init(&b->crtc_list);
3084 if (drm_backend_create_crtc_list(b, res) == -1) {
3085 weston_log("Failed to create CRTC list for DRM-backend\n");
3086 goto err_create_crtc_list;
3087 }
3088
Daniel Stone085d2b92015-05-21 00:00:57 +01003089 wl_list_init(&b->plane_list);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003090 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003091
Giulio Camuffo954f1832014-10-11 18:27:30 +03003092 if (udev_input_init(&b->input,
Giulio Camuffo8aedf7b2016-06-02 21:48:12 +03003093 compositor, b->udev, seat_id,
3094 config->configure_device) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003095 weston_log("failed to create input devices\n");
3096 goto err_sprite;
3097 }
3098
Leandro Ribeiro96bef052020-09-09 15:23:49 -03003099 wl_list_init(&b->writeback_connector_list);
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003100 if (drm_backend_discover_connectors(b, drm_device, res) < 0) {
Pekka Paalanend2e62422017-09-08 15:48:07 +03003101 weston_log("Failed to create heads for %s\n", b->drm.filename);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003102 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003103 }
3104
Igor Matheus Andrade Torrente63544552020-10-13 11:25:20 -03003105 drmModeFreeResources(res);
3106
Marius Vlade83e7502019-10-29 17:29:37 +02003107 /* 'compute' faked zpos values in case HW doesn't expose any */
3108 drm_backend_create_faked_zpos(b);
3109
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003110 /* A this point we have some idea of whether or not we have a working
3111 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003112 if (!b->cursors_are_broken)
3113 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003114
Giulio Camuffo954f1832014-10-11 18:27:30 +03003115 loop = wl_display_get_event_loop(compositor->wl_display);
3116 b->drm_source =
3117 wl_event_loop_add_fd(loop, b->drm.fd,
3118 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003119
Giulio Camuffo954f1832014-10-11 18:27:30 +03003120 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3121 if (b->udev_monitor == NULL) {
Abdur Rehman4dca0e12017-01-01 19:46:35 +05003122 weston_log("failed to initialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003123 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003124 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003125 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003126 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003127 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003128 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003129 udev_monitor_get_fd(b->udev_monitor),
3130 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003131
Giulio Camuffo954f1832014-10-11 18:27:30 +03003132 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003133 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003134 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003135 }
3136
Daniel Stonea96b93c2012-06-22 14:04:37 +01003137 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003138
Giulio Camuffo954f1832014-10-11 18:27:30 +03003139 weston_compositor_add_debug_binding(compositor, KEY_O,
3140 planes_binding, b);
3141 weston_compositor_add_debug_binding(compositor, KEY_C,
3142 planes_binding, b);
3143 weston_compositor_add_debug_binding(compositor, KEY_V,
3144 planes_binding, b);
3145 weston_compositor_add_debug_binding(compositor, KEY_Q,
3146 recorder_binding, b);
3147 weston_compositor_add_debug_binding(compositor, KEY_W,
3148 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003149
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003150 if (compositor->renderer->import_dmabuf) {
3151 if (linux_dmabuf_setup(compositor) < 0)
3152 weston_log("Error: initializing dmabuf "
3153 "support failed.\n");
Leandro Ribeiro54293022021-10-12 14:48:36 -03003154 if (compositor->default_dmabuf_feedback) {
3155 /* We were able to create the compositor's default
3156 * dma-buf feedback in the renderer, that means that the
3157 * table was already created and populated with
3158 * renderer's format/modifier pairs. So now we must
3159 * compute the scanout formats indices in the table */
3160 scanout_formats = get_scanout_formats(b);
3161 if (!scanout_formats)
3162 goto err_udev_monitor;
3163 ret = weston_dmabuf_feedback_format_table_set_scanout_indices(compositor->dmabuf_feedback_format_table,
3164 scanout_formats);
3165 weston_drm_format_array_fini(scanout_formats);
Daniel Stonef5086032021-12-06 16:52:19 +00003166 free(scanout_formats);
Leandro Ribeiro54293022021-10-12 14:48:36 -03003167 if (ret < 0)
3168 goto err_udev_monitor;
3169 }
Marius Vladebd10e52019-11-16 19:22:48 +02003170 if (weston_direct_display_setup(compositor) < 0)
3171 weston_log("Error: initializing direct-display "
3172 "support failed.\n");
Pekka Paalanene4d231e2014-06-12 15:12:48 +03003173 }
3174
Alexandros Frantzisacff29b2018-10-19 12:14:11 +03003175 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
3176 if (linux_explicit_synchronization_setup(compositor) < 0)
3177 weston_log("Error: initializing explicit "
3178 " synchronization support failed.\n");
3179 }
3180
Ankit Nautiyala344fe32019-05-14 18:36:08 +05303181 if (b->atomic_modeset)
3182 if (weston_compositor_enable_content_protection(compositor) < 0)
3183 weston_log("Error: initializing content-protection "
3184 "support failed.\n");
3185
Armin Krezović08368132016-09-30 14:11:05 +02003186 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
3187 &api, sizeof(api));
3188
3189 if (ret < 0) {
3190 weston_log("Failed to register output API.\n");
3191 goto err_udev_monitor;
3192 }
3193
Stefan Agner3654c672019-07-09 00:50:30 +02003194 ret = drm_backend_init_virtual_output_api(compositor);
Tomohito Esakib1fb00d2018-01-31 17:50:48 +09003195 if (ret < 0) {
3196 weston_log("Failed to register virtual output API.\n");
3197 goto err_udev_monitor;
3198 }
3199
Giulio Camuffo954f1832014-10-11 18:27:30 +03003200 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003201
3202err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003203 wl_event_source_remove(b->udev_drm_source);
3204 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003205err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003206 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003207err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003208 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003209err_sprite:
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);
Marius Vladd171c7b2021-04-01 00:12:00 +03003221#ifdef BUILD_DRM_GBM
3222 if (b->gbm)
3223 gbm_device_destroy(b->gbm);
3224#endif
Giulio Camuffo954f1832014-10-11 18:27:30 +03003225 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003226 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003227}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003228
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003229static void
3230config_init_to_defaults(struct weston_drm_backend_config *config)
3231{
Pekka Paalanendee412d2018-04-23 11:44:58 +02003232 config->use_pixman_shadow = true;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003233}
3234
Giulio Camuffo954f1832014-10-11 18:27:30 +03003235WL_EXPORT int
Quentin Glidic23e1d6f2016-12-02 14:08:44 +01003236weston_backend_init(struct weston_compositor *compositor,
3237 struct weston_backend_config *config_base)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003238{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003239 struct drm_backend *b;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003240 struct weston_drm_backend_config config = {{ 0, }};
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003241
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003242 if (config_base == NULL ||
3243 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
3244 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
3245 weston_log("drm backend config structure is invalid\n");
3246 return -1;
3247 }
Benjamin Franzke117483d2011-08-30 11:38:26 +02003248
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003249 config_init_to_defaults(&config);
3250 memcpy(&config, config_base, config_base->struct_size);
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003251
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003252 b = drm_backend_create(compositor, &config);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003253 if (b == NULL)
3254 return -1;
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07003255
Giulio Camuffo954f1832014-10-11 18:27:30 +03003256 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003257}